Joedb 10.0.1
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
22 (
23 lock.size > 0 &&
26 )
27 {
28 throw Exception
29 (
30 "Checkpoint (" + std::to_string(checkpoint_position) +
31 ") is smaller than file size (" + std::to_string(lock.size) +
32 "). This file may contain an aborted transaction. "
33 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
34 );
35 }
36}
37
38/////////////////////////////////////////////////////////////////////////////
40/////////////////////////////////////////////////////////////////////////////
41(
42 const Readonly_Journal &journal,
43 const int64_t until
44)
45{
46 if (checkpoint_position < until)
47 {
48 const int64_t size = until - checkpoint_position;
49 journal.get_file().copy_to(file, checkpoint_position, size);
50 soft_checkpoint_at(until);
51 }
52
53 return checkpoint_position;
54}
55
56/////////////////////////////////////////////////////////////////////////////
58/////////////////////////////////////////////////////////////////////////////
59{
60 return file.get_position() - checkpoint_position;
61}
62
63/////////////////////////////////////////////////////////////////////////////
65/////////////////////////////////////////////////////////////////////////////
66{
67 if (position != checkpoint_position)
68 throw Exception("writing must start at checkpoint position");
69}
70
71/////////////////////////////////////////////////////////////////////////////
73/////////////////////////////////////////////////////////////////////////////
74{
75 if (position != file.get_position())
76 throw Exception("end_writing position is not matching file position");
77}
78
79/////////////////////////////////////////////////////////////////////////////
81/////////////////////////////////////////////////////////////////////////////
82{
83 if (checkpoint_position >= position)
84 return;
85
86 file.flush();
87
88 JOEDB_DEBUG_ASSERT(file.get_size() < 0 || position <= file.get_size());
89
90 soft_index ^= 1;
91 checkpoint_position = position;
92
94
95 const int64_t neg = -checkpoint_position;
96
97 file.pwrite
98 (
99 reinterpret_cast<const char *>(&neg),
100 sizeof(neg),
101 int64_t(sizeof(neg)) * (2 * (hard_index ^ 1) + soft_index)
102 );
103}
104
105/////////////////////////////////////////////////////////////////////////////
107/////////////////////////////////////////////////////////////////////////////
108{
109 if (hard_checkpoint_position >= position)
110 return;
111
112 file.flush();
113
114 hard_index ^= 1;
115 hard_checkpoint_position = checkpoint_position = position;
116
118
119 file.pwrite
120 (
121 reinterpret_cast<const char *>(&checkpoint_position),
122 sizeof(checkpoint_position),
123 int64_t(sizeof(checkpoint_position)) * (2 * hard_index)
124 );
125
126 file.sync();
127
128 file.pwrite
129 (
130 reinterpret_cast<const char *>(&checkpoint_position),
131 sizeof(checkpoint_position),
132 int64_t(sizeof(checkpoint_position)) * (2 * hard_index + 1)
133 );
134
135 file.datasync();
136}
137
138/////////////////////////////////////////////////////////////////////////////
140/////////////////////////////////////////////////////////////////////////////
141{
142 soft_checkpoint_at(file.get_position());
143}
144
145/////////////////////////////////////////////////////////////////////////////
147/////////////////////////////////////////////////////////////////////////////
148{
149 hard_checkpoint_at(file.get_position());
150}
151
152/////////////////////////////////////////////////////////////////////////////
153void joedb::Writable_Journal::create_table(const std::string &name)
154/////////////////////////////////////////////////////////////////////////////
155{
156 file.write<operation_t>(operation_t::create_table);
157 file.write_string(name);
158}
159
160/////////////////////////////////////////////////////////////////////////////
162/////////////////////////////////////////////////////////////////////////////
163{
164 file.write<operation_t>(operation_t::drop_table);
165 file.compact_write<>(to_underlying(table_id));
166}
167
168/////////////////////////////////////////////////////////////////////////////
170/////////////////////////////////////////////////////////////////////////////
171(
172 Table_Id table_id,
173 const std::string &name
174)
175{
176 file.write<operation_t>(operation_t::rename_table);
177 file.compact_write<>(to_underlying(table_id));
178 file.write_string(name);
179}
180
181/////////////////////////////////////////////////////////////////////////////
183/////////////////////////////////////////////////////////////////////////////
184(
185 Table_Id table_id,
186 const std::string &name,
187 Type type
188)
189{
190 file.write<operation_t>(operation_t::add_field);
191 file.compact_write<>(to_underlying(table_id));
192 file.write_string(name);
193 file.write<Type_Id_Storage>(Type_Id_Storage(type.get_type_id()));
194 if (type.get_type_id() == Type::Type_Id::reference)
195 file.compact_write<>(to_underlying(type.get_table_id()));
196}
197
198/////////////////////////////////////////////////////////////////////////////
200/////////////////////////////////////////////////////////////////////////////
201(
202 Table_Id table_id,
203 Field_Id field_id
204)
205{
206 file.write<operation_t>(operation_t::drop_field);
207 file.compact_write<>(to_underlying(table_id));
208 file.compact_write<>(to_underlying(field_id));
209}
210
211/////////////////////////////////////////////////////////////////////////////
213/////////////////////////////////////////////////////////////////////////////
214(
215 Table_Id table_id,
216 Field_Id field_id,
217 const std::string &name
218)
219{
220 file.write<operation_t>(operation_t::rename_field);
221 file.compact_write<>(to_underlying(table_id));
222 file.compact_write<>(to_underlying(field_id));
223 file.write_string(name);
224}
225
226/////////////////////////////////////////////////////////////////////////////
227void joedb::Writable_Journal::custom(const std::string &name)
228/////////////////////////////////////////////////////////////////////////////
229{
230 file.write<operation_t>(operation_t::custom);
231 file.write_string(name);
232}
233
234/////////////////////////////////////////////////////////////////////////////
235void joedb::Writable_Journal::comment(const std::string &comment)
236/////////////////////////////////////////////////////////////////////////////
237{
238 file.write<operation_t>(operation_t::comment);
239 file.write_string(comment);
240}
241
242/////////////////////////////////////////////////////////////////////////////
244/////////////////////////////////////////////////////////////////////////////
245{
246 file.write<operation_t>(operation_t::timestamp);
247 file.write<int64_t>(timestamp);
248}
249
250/////////////////////////////////////////////////////////////////////////////
252/////////////////////////////////////////////////////////////////////////////
253{
254 file.write<operation_t>(operation_t::valid_data);
255}
256
257/////////////////////////////////////////////////////////////////////////////
259/////////////////////////////////////////////////////////////////////////////
260(
261 Table_Id table_id,
262 Record_Id record_id
263)
264{
265 if (table_id == table_of_last_operation &&
266 record_id == record_of_last_operation + 1)
267 {
268 file.write<operation_t>(operation_t::append);
269 }
270 else
271 {
272 file.write<operation_t>(operation_t::insert_into);
273 file.compact_write<>(to_underlying(table_id));
274 file.write_reference(record_id);
275 }
276
277 table_of_last_operation = table_id;
278 record_of_last_operation = record_id;
279}
280
281/////////////////////////////////////////////////////////////////////////////
283/////////////////////////////////////////////////////////////////////////////
284(
285 Table_Id table_id,
286 Record_Id record_id
287)
288{
289 file.write<operation_t>(operation_t::delete_from);
290 file.compact_write<>(to_underlying(table_id));
291 file.write_reference(record_id);
292}
293
294/////////////////////////////////////////////////////////////////////////////
296/////////////////////////////////////////////////////////////////////////////
297(
298 Table_Id table_id,
299 Record_Id record_id,
300 size_t size
301)
302{
303 file.write<operation_t>(operation_t::insert_vector);
304 file.compact_write<>(to_underlying(table_id));
305 file.write_reference(record_id);
306 file.compact_write<>(size);
307
308 table_of_last_operation = table_id;
309 record_of_last_operation = record_id;
310}
311
312/////////////////////////////////////////////////////////////////////////////
314/////////////////////////////////////////////////////////////////////////////
315(
316 Table_Id table_id,
317 Record_Id record_id,
318 size_t size
319)
320{
321 file.write<operation_t>(operation_t::delete_vector);
322 file.compact_write<>(to_underlying(table_id));
323 file.write_reference(record_id);
324 file.compact_write<>(size);
325}
326
327/////////////////////////////////////////////////////////////////////////////
328void joedb::Writable_Journal::generic_update
329/////////////////////////////////////////////////////////////////////////////
330(
331 Table_Id table_id,
332 Record_Id record_id,
333 Field_Id field_id,
334 operation_t operation
335)
336{
337 if
338 (
339 table_id == table_of_last_operation &&
340 record_id == record_of_last_operation
341 )
342 {
343 constexpr int last =
344 int(operation_t::update_last_int8) -
345 int(operation_t::update_int8);
346
347 file.write<operation_t>(operation_t(int(operation) + last));
348 file.compact_write<>(to_underlying(field_id));
349 field_of_last_update = field_id;
350 }
351 else if
352 (
353 table_id == table_of_last_operation &&
354 record_id == record_of_last_operation + 1 &&
355 field_id == field_of_last_update
356 )
357 {
358 constexpr int next =
359 int(operation_t::update_next_int8) -
360 int(operation_t::update_int8);
361 file.write<operation_t>(operation_t(int(operation) + next));
362 ++record_of_last_operation;
363 }
364 else
365 {
366 file.write<operation_t>(operation);
367 file.compact_write<>(to_underlying(table_id));
368 file.write_reference(record_id);
369 file.compact_write<>(to_underlying(field_id));
370 table_of_last_operation = table_id;
371 record_of_last_operation = record_id;
372 field_of_last_update = field_id;
373 }
374}
375
376/////////////////////////////////////////////////////////////////////////////
377#define TYPE_MACRO(type, return_type, type_id, R, write_method)\
378void joedb::Writable_Journal::update_##type_id\
379(\
380 Table_Id table_id,\
381 Record_Id record_id,\
382 Field_Id field_id,\
383 return_type value\
384)\
385{\
386 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
387 file.write_method(value);\
388}\
389void joedb::Writable_Journal::update_vector_##type_id\
390(\
391 Table_Id table_id,\
392 Record_Id record_id,\
393 Field_Id field_id,\
394 size_t size,\
395 const type *value\
396)\
397{\
398 file.write<operation_t>(operation_t::update_vector_##type_id);\
399 file.compact_write<>(to_underlying(table_id));\
400 file.write_reference(record_id);\
401 file.compact_write<>(to_underlying(field_id));\
402 file.compact_write<>(size);\
403 table_of_last_operation = table_id;\
404 record_of_last_operation = record_id;\
405 field_of_last_update = field_id;\
406\
407 if constexpr\
408 (\
409 Type::Type_Id::type_id == Type::Type_Id::blob ||\
410 Type::Type_Id::type_id == Type::Type_Id::string ||\
411 Type::Type_Id::type_id == Type::Type_Id::reference\
412 )\
413 {\
414 for (size_t i = 0; i < size; i++)\
415 file.write_method(value[i]);\
416 }\
417 else\
418 file.write_data((const char *)value, size * sizeof(type));\
419}
420#include "joedb/TYPE_MACRO.h"
421
422/////////////////////////////////////////////////////////////////////////////
424/////////////////////////////////////////////////////////////////////////////
425(
426 const std::string &data
427)
428{
429 file.write<operation_t>(operation_t::blob);
430 file.compact_write<size_t>(data.size());
431 const int64_t blob_position = get_position();
432 file.flush();
433 file.sequential_write(data.data(), data.size());
434 return Blob(blob_position, int64_t(data.size()));
435}
436
437/////////////////////////////////////////////////////////////////////////////
439/////////////////////////////////////////////////////////////////////////////
440{
441 if (file.is_shared())
442 {
443 file.exclusive_lock_tail();
444 pull_without_locking();
445 }
446}
447
448/////////////////////////////////////////////////////////////////////////////
450/////////////////////////////////////////////////////////////////////////////
451{
452 if (file.is_shared())
453 file.unlock_tail();
454}
455
456/////////////////////////////////////////////////////////////////////////////
458/////////////////////////////////////////////////////////////////////////////
459{
460 if (ahead_of_checkpoint() > 0)
461 Destructor_Logger::write("Ahead_of_checkpoint in Writable_Journal destructor");
462}
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)
Blob write_blob(const std::string &data) override
int64_t ahead_of_checkpoint() const noexcept
void soft_checkpoint_at(int64_t position)
void start_writing(int64_t position) override
void end_writing(int64_t position) override
void hard_checkpoint_at(int64_t position)
#define JOEDB_DEBUG_ASSERT(x)
assertion tested in debug mode
Definition assert.h:19
@ overwrite
allow overwriting an uncheckpointed tail
uint8_t Type_Id_Storage
Definition Type.h:11
constexpr index_t to_underlying(Record_Id id)
Definition index_types.h:59
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