Joedb 9.5.0
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Writable_Journal.cpp
Go to the documentation of this file.
5
6/////////////////////////////////////////////////////////////////////////////
8/////////////////////////////////////////////////////////////////////////////
9 Readonly_Journal(lock.set_for_writable_journal())
10{
11 if (file.is_readonly())
12 throw Exception("Cannot create Writable_Journal with read-only file");
13 else if (lock.size == 0)
14 {
15 Header header;
16 header.checkpoint.fill(Header::size);
17 header.version = format_version;
18 header.signature = Header::joedb;
19 file.sequential_write((const char *)(&header), Header::size);
20 }
21 else if (lock.size > 0 && lock.size > checkpoint_position)
22 {
23 throw Exception
24 (
25 "Checkpoint (" + std::to_string(checkpoint_position) +
26 ") is smaller than file size (" + std::to_string(lock.size) +
27 "). This file may contain an aborted transaction. "
28 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
29 );
30 }
31}
32
33/////////////////////////////////////////////////////////////////////////////
35/////////////////////////////////////////////////////////////////////////////
36(
37 const Readonly_Journal &journal,
38 const int64_t until
39)
40{
41 if (checkpoint_position < until)
42 {
43 const int64_t size = until - checkpoint_position;
44 journal.get_file().copy_to(file, checkpoint_position, size);
45 soft_checkpoint_at(until);
46 }
47
48 return checkpoint_position;
49}
50
51/////////////////////////////////////////////////////////////////////////////
53/////////////////////////////////////////////////////////////////////////////
54{
55 return file.get_position() - checkpoint_position;
56}
57
58/////////////////////////////////////////////////////////////////////////////
60/////////////////////////////////////////////////////////////////////////////
61{
62 if (position != checkpoint_position)
63 throw Exception("writing must start at checkpoint position");
64}
65
66/////////////////////////////////////////////////////////////////////////////
68/////////////////////////////////////////////////////////////////////////////
69{
70 if (checkpoint_position >= position)
71 return;
72
73 file.flush();
74
75 soft_index ^= 1;
76 checkpoint_position = position;
77
79
80 const int64_t neg = -checkpoint_position;
81
82 file.pwrite
83 (
84 reinterpret_cast<const char *>(&neg),
85 sizeof(neg),
86 int64_t(sizeof(neg)) * (2 * (hard_index ^ 1) + soft_index)
87 );
88}
89
90/////////////////////////////////////////////////////////////////////////////
92/////////////////////////////////////////////////////////////////////////////
93{
94 file.flush();
95
96 hard_index ^= 1;
97 checkpoint_position = position;
98
100
101 file.pwrite
102 (
103 reinterpret_cast<const char *>(&checkpoint_position),
104 sizeof(checkpoint_position),
105 int64_t(sizeof(checkpoint_position)) * (2 * hard_index)
106 );
107
108 file.sync();
109
110 file.pwrite
111 (
112 reinterpret_cast<const char *>(&checkpoint_position),
113 sizeof(checkpoint_position),
114 int64_t(sizeof(checkpoint_position)) * (2 * hard_index + 1)
115 );
116
117 file.datasync();
118}
119
120/////////////////////////////////////////////////////////////////////////////
121void joedb::Writable_Journal::create_table(const std::string &name)
122/////////////////////////////////////////////////////////////////////////////
123{
124 file.write<operation_t>(operation_t::create_table);
125 file.write_string(name);
126}
127
128/////////////////////////////////////////////////////////////////////////////
130/////////////////////////////////////////////////////////////////////////////
131{
132 file.write<operation_t>(operation_t::drop_table);
133 file.compact_write<>(to_underlying(table_id));
134}
135
136/////////////////////////////////////////////////////////////////////////////
138/////////////////////////////////////////////////////////////////////////////
139(
140 Table_Id table_id,
141 const std::string &name
142)
143{
144 file.write<operation_t>(operation_t::rename_table);
145 file.compact_write<>(to_underlying(table_id));
146 file.write_string(name);
147}
148
149/////////////////////////////////////////////////////////////////////////////
151/////////////////////////////////////////////////////////////////////////////
152(
153 Table_Id table_id,
154 const std::string &name,
155 Type type
156)
157{
158 file.write<operation_t>(operation_t::add_field);
159 file.compact_write<>(to_underlying(table_id));
160 file.write_string(name);
161 file.write<Type_Id_Storage>(Type_Id_Storage(type.get_type_id()));
162 if (type.get_type_id() == Type::Type_Id::reference)
163 file.compact_write<>(to_underlying(type.get_table_id()));
164}
165
166/////////////////////////////////////////////////////////////////////////////
168/////////////////////////////////////////////////////////////////////////////
169(
170 Table_Id table_id,
171 Field_Id field_id
172)
173{
174 file.write<operation_t>(operation_t::drop_field);
175 file.compact_write<>(to_underlying(table_id));
176 file.compact_write<>(to_underlying(field_id));
177}
178
179/////////////////////////////////////////////////////////////////////////////
181/////////////////////////////////////////////////////////////////////////////
182(
183 Table_Id table_id,
184 Field_Id field_id,
185 const std::string &name
186)
187{
188 file.write<operation_t>(operation_t::rename_field);
189 file.compact_write<>(to_underlying(table_id));
190 file.compact_write<>(to_underlying(field_id));
191 file.write_string(name);
192}
193
194/////////////////////////////////////////////////////////////////////////////
195void joedb::Writable_Journal::custom(const std::string &name)
196/////////////////////////////////////////////////////////////////////////////
197{
198 file.write<operation_t>(operation_t::custom);
199 file.write_string(name);
200}
201
202/////////////////////////////////////////////////////////////////////////////
203void joedb::Writable_Journal::comment(const std::string &comment)
204/////////////////////////////////////////////////////////////////////////////
205{
206 file.write<operation_t>(operation_t::comment);
207 file.write_string(comment);
208}
209
210/////////////////////////////////////////////////////////////////////////////
212/////////////////////////////////////////////////////////////////////////////
213{
214 file.write<operation_t>(operation_t::timestamp);
215 file.write<int64_t>(timestamp);
216}
217
218/////////////////////////////////////////////////////////////////////////////
220/////////////////////////////////////////////////////////////////////////////
221{
222 file.write<operation_t>(operation_t::valid_data);
223}
224
225/////////////////////////////////////////////////////////////////////////////
227/////////////////////////////////////////////////////////////////////////////
228(
229 Table_Id table_id,
230 Record_Id record_id
231)
232{
233 if (table_id == table_of_last_operation &&
234 record_id == record_of_last_operation + 1)
235 {
236 file.write<operation_t>(operation_t::append);
237 }
238 else
239 {
240 file.write<operation_t>(operation_t::insert_into);
241 file.compact_write<>(to_underlying(table_id));
242 file.compact_write<>(to_underlying(record_id));
243 }
244
245 table_of_last_operation = table_id;
246 record_of_last_operation = record_id;
247}
248
249/////////////////////////////////////////////////////////////////////////////
251/////////////////////////////////////////////////////////////////////////////
252(
253 Table_Id table_id,
254 Record_Id record_id
255)
256{
257 file.write<operation_t>(operation_t::delete_from);
258 file.compact_write<>(to_underlying(table_id));
259 file.compact_write<>(to_underlying(record_id));
260}
261
262/////////////////////////////////////////////////////////////////////////////
264/////////////////////////////////////////////////////////////////////////////
265(
266 Table_Id table_id,
267 Record_Id record_id,
268 size_t size
269)
270{
271 file.write<operation_t>(operation_t::insert_vector);
272 file.compact_write<>(to_underlying(table_id));
273 file.compact_write<>(to_underlying(record_id));
274 file.compact_write<>(size);
275
276 table_of_last_operation = table_id;
277 record_of_last_operation = record_id;
278}
279
280/////////////////////////////////////////////////////////////////////////////
282/////////////////////////////////////////////////////////////////////////////
283(
284 Table_Id table_id,
285 Record_Id record_id,
286 size_t size
287)
288{
289 file.write<operation_t>(operation_t::delete_vector);
290 file.compact_write<>(to_underlying(table_id));
291 file.compact_write<>(to_underlying(record_id));
292 file.compact_write<>(size);
293}
294
295/////////////////////////////////////////////////////////////////////////////
296void joedb::Writable_Journal::generic_update
297/////////////////////////////////////////////////////////////////////////////
298(
299 Table_Id table_id,
300 Record_Id record_id,
301 Field_Id field_id,
302 operation_t operation
303)
304{
305 if
306 (
307 table_id == table_of_last_operation &&
308 record_id == record_of_last_operation
309 )
310 {
311 constexpr int last =
312 int(operation_t::update_last_int8) -
313 int(operation_t::update_int8);
314
315 file.write<operation_t>(operation_t(int(operation) + last));
316 file.compact_write<>(to_underlying(field_id));
317 field_of_last_update = field_id;
318 }
319 else if
320 (
321 table_id == table_of_last_operation &&
322 record_id == record_of_last_operation + 1 &&
323 field_id == field_of_last_update
324 )
325 {
326 constexpr int next =
327 int(operation_t::update_next_int8) -
328 int(operation_t::update_int8);
329 file.write<operation_t>(operation_t(int(operation) + next));
330 ++record_of_last_operation;
331 }
332 else
333 {
334 file.write<operation_t>(operation);
335 file.compact_write<>(to_underlying(table_id));
336 file.compact_write<>(to_underlying(record_id));
337 file.compact_write<>(to_underlying(field_id));
338 table_of_last_operation = table_id;
339 record_of_last_operation = record_id;
340 field_of_last_update = field_id;
341 }
342}
343
344/////////////////////////////////////////////////////////////////////////////
345#define TYPE_MACRO(type, return_type, type_id, R, write_method)\
346void joedb::Writable_Journal::update_##type_id\
347(\
348 Table_Id table_id,\
349 Record_Id record_id,\
350 Field_Id field_id,\
351 return_type value\
352)\
353{\
354 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
355 file.write_method(value);\
356}\
357void joedb::Writable_Journal::update_vector_##type_id\
358(\
359 Table_Id table_id,\
360 Record_Id record_id,\
361 Field_Id field_id,\
362 size_t size,\
363 const type *value\
364)\
365{\
366 file.write<operation_t>(operation_t::update_vector_##type_id);\
367 file.compact_write<>(to_underlying(table_id));\
368 file.compact_write<>(to_underlying(record_id));\
369 file.compact_write<>(to_underlying(field_id));\
370 file.compact_write<>(size);\
371 table_of_last_operation = table_id;\
372 record_of_last_operation = record_id;\
373 field_of_last_update = field_id;\
374\
375 if constexpr\
376 (\
377 Type::Type_Id::type_id == Type::Type_Id::blob ||\
378 Type::Type_Id::type_id == Type::Type_Id::string ||\
379 Type::Type_Id::type_id == Type::Type_Id::reference\
380 )\
381 {\
382 for (size_t i = 0; i < size; i++)\
383 file.write_method(value[i]);\
384 }\
385 else\
386 file.write_data((const char *)value, size * sizeof(type));\
387}
388#include "joedb/TYPE_MACRO.h"
389
390/////////////////////////////////////////////////////////////////////////////
392/////////////////////////////////////////////////////////////////////////////
393(
394 const std::string &data
395)
396{
397 file.write<operation_t>(operation_t::blob);
398 file.compact_write<size_t>(data.size());
399 const int64_t blob_position = get_position();
400 file.flush();
401 file.sequential_write(data.data(), data.size());
402 return Blob(blob_position, int64_t(data.size()));
403}
404
405/////////////////////////////////////////////////////////////////////////////
407/////////////////////////////////////////////////////////////////////////////
408{
409 if (file.is_shared())
410 {
411 file.exclusive_lock_tail();
412 pull_without_locking();
413 }
414}
415
416/////////////////////////////////////////////////////////////////////////////
418/////////////////////////////////////////////////////////////////////////////
419{
420 if (file.is_shared())
421 file.unlock_tail();
422}
423
424/////////////////////////////////////////////////////////////////////////////
426/////////////////////////////////////////////////////////////////////////////
427{
428 if (ahead_of_checkpoint() > 0)
429 Destructor_Logger::write("Ahead_of_checkpoint in Writable_Journal destructor");
430}
bool is_readonly() const noexcept
static void write(const char *message) noexcept
static constexpr uint32_t format_version
void sequential_write(const char *data, size_t size)
int64_t pull_from(const Readonly_Journal &journal, int64_t until)
void hard_checkpoint_at(int64_t position) override
void soft_checkpoint_at(int64_t position) override
int64_t ahead_of_checkpoint() const noexcept
Blob write_blob(const std::string &data) final
void start_writing(int64_t position) override
constexpr std::underlying_type< Table_Id >::type to_underlying(Table_Id id)
Definition index_types.h:21
uint8_t Type_Id_Storage
Definition Type.h:11
static constexpr size_t size
Definition Header.h:19
std::array< char, 5 > signature
Definition Header.h:15
static constexpr std::array< char, 5 > joedb
Definition Header.h:17
uint32_t version
Definition Header.h:14
std::array< int64_t, 4 > checkpoint
Definition Header.h:13