Joedb 9.1.4
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Writable_Journal.cpp
Go to the documentation of this file.
5
6/////////////////////////////////////////////////////////////////////////////
8/////////////////////////////////////////////////////////////////////////////
9(
11 Check check,
12 Commit_Level commit_level
13):
14 Readonly_Journal(lock, check),
15 Writable(commit_level),
16 current_commit_level(Commit_Level::no_commit)
17{
18 if (file.is_readonly())
19 {
20 throw Exception("Cannot create Writable_Journal with read-only file");
21 }
22 else if (lock.is_creating_new())
23 {
24 file.write<uint8_t>('j');
25 file.write<uint8_t>('o');
26 file.write<uint8_t>('e');
27 file.write<uint8_t>('d');
28 file.write<uint8_t>('b');
29 file.write<uint32_t>(version_number);
30 file.write<int64_t>(header_size);
31 file.write<int64_t>(header_size);
32 file.write<int64_t>(0);
33 file.write<int64_t>(0);
34 flush_and_may_sync();
35 }
36 else
37 {
38 if (lock.pos[0] != lock.pos[1] || lock.pos[2] != lock.pos[3])
39 {
41 throw Exception("Checkpoint mismatch");
42 else
43 {
49 flush_and_may_sync();
50 }
51 }
52
54 {
57 file.write<uint32_t>(file_version);
59 flush_and_may_sync();
60 }
61 }
62}
63
64/////////////////////////////////////////////////////////////////////////////
66/////////////////////////////////////////////////////////////////////////////
67(
69 Check check,
70 Commit_Level commit_level
71):
72 Writable_Journal(lock, check, commit_level)
73{
74}
75
76/////////////////////////////////////////////////////////////////////////////
78/////////////////////////////////////////////////////////////////////////////
79(
80 Buffered_File &file,
81 Check check,
82 Commit_Level commit_level
83):
84 Writable_Journal(Journal_Construction_Lock(file), check, commit_level)
85{
86}
87
88/////////////////////////////////////////////////////////////////////////////
90/////////////////////////////////////////////////////////////////////////////
91(
92 Readonly_Journal &journal,
93 const int64_t until_checkpoint
94)
95{
96 const int64_t source_checkpoint = std::min
97 (
98 journal.get_checkpoint_position(),
99 until_checkpoint
100 );
101
102 if (checkpoint_position < source_checkpoint)
103 {
104 const int64_t initial_position = get_position();
105 const int64_t initial_source_position = journal.get_position();
106
107 journal.file.copy_to
108 (
109 file,
110 checkpoint_position,
111 source_checkpoint - checkpoint_position
112 );
113
114 default_checkpoint();
115
116 set_position(initial_position);
117 journal.set_position(initial_source_position);
118 }
119
120 return checkpoint_position;
121}
122
123/////////////////////////////////////////////////////////////////////////////
125/////////////////////////////////////////////////////////////////////////////
126{
127 return file.get_position() - checkpoint_position;
128}
129
130/////////////////////////////////////////////////////////////////////////////
132/////////////////////////////////////////////////////////////////////////////
133{
134 if
135 (
136 ahead_of_checkpoint() > 0 ||
137 (ahead_of_checkpoint() == 0 && commit_level > current_commit_level)
138 )
139 {
140 file.flush();
141
142 checkpoint_index ^= 1;
143 checkpoint_position = file.get_position();
144 current_commit_level = commit_level;
145
146 {
147 file.exclusive_lock_head();
148
149 file.pwrite
150 (
151 reinterpret_cast<const char *>(&checkpoint_position),
152 sizeof(checkpoint_position),
153 checkpoint_offset +
154 int64_t(sizeof(checkpoint_position)) * (2 * checkpoint_index)
155 );
156
157 if (commit_level > Commit_Level::no_commit)
158 file.flush_and_sync();
159
160 file.pwrite
161 (
162 reinterpret_cast<const char *>(&checkpoint_position),
163 sizeof(checkpoint_position),
164 checkpoint_offset +
165 int64_t(sizeof(checkpoint_position)) * (2 * checkpoint_index + 1)
166 );
167
168 if (commit_level > Commit_Level::half_commit)
169 file.flush_and_sync();
170
171 file.unlock_head();
172 }
173
174 file.set_position(checkpoint_position);
175 }
176}
177
178/////////////////////////////////////////////////////////////////////////////
179void joedb::Writable_Journal::create_table(const std::string &name)
180/////////////////////////////////////////////////////////////////////////////
181{
182 file.write<operation_t>(operation_t::create_table);
183 file.write_string(name);
184}
185
186/////////////////////////////////////////////////////////////////////////////
188/////////////////////////////////////////////////////////////////////////////
189{
190 file.write<operation_t>(operation_t::drop_table);
191 file.compact_write<>(to_underlying(table_id));
192}
193
194/////////////////////////////////////////////////////////////////////////////
196/////////////////////////////////////////////////////////////////////////////
197(
198 Table_Id table_id,
199 const std::string &name
200)
201{
202 file.write<operation_t>(operation_t::rename_table);
203 file.compact_write<>(to_underlying(table_id));
204 file.write_string(name);
205}
206
207/////////////////////////////////////////////////////////////////////////////
209/////////////////////////////////////////////////////////////////////////////
210(
211 Table_Id table_id,
212 const std::string &name,
213 Type type
214)
215{
216 file.write<operation_t>(operation_t::add_field);
217 file.compact_write<>(to_underlying(table_id));
218 file.write_string(name);
219 file.write<Type_Id_Storage>(Type_Id_Storage(type.get_type_id()));
220 if (type.get_type_id() == Type::Type_Id::reference)
221 file.compact_write<>(to_underlying(type.get_table_id()));
222}
223
224/////////////////////////////////////////////////////////////////////////////
226/////////////////////////////////////////////////////////////////////////////
227(
228 Table_Id table_id,
229 Field_Id field_id
230)
231{
232 file.write<operation_t>(operation_t::drop_field);
233 file.compact_write<>(to_underlying(table_id));
234 file.compact_write<>(to_underlying(field_id));
235}
236
237/////////////////////////////////////////////////////////////////////////////
239/////////////////////////////////////////////////////////////////////////////
240(
241 Table_Id table_id,
242 Field_Id field_id,
243 const std::string &name
244)
245{
246 file.write<operation_t>(operation_t::rename_field);
247 file.compact_write<>(to_underlying(table_id));
248 file.compact_write<>(to_underlying(field_id));
249 file.write_string(name);
250}
251
252/////////////////////////////////////////////////////////////////////////////
253void joedb::Writable_Journal::custom(const std::string &name)
254/////////////////////////////////////////////////////////////////////////////
255{
256 file.write<operation_t>(operation_t::custom);
257 file.write_string(name);
258}
259
260/////////////////////////////////////////////////////////////////////////////
261void joedb::Writable_Journal::comment(const std::string &comment)
262/////////////////////////////////////////////////////////////////////////////
263{
264 file.write<operation_t>(operation_t::comment);
265 file.write_string(comment);
266}
267
268/////////////////////////////////////////////////////////////////////////////
270/////////////////////////////////////////////////////////////////////////////
271{
272 file.write<operation_t>(operation_t::timestamp);
273 file.write<int64_t>(timestamp);
274}
275
276/////////////////////////////////////////////////////////////////////////////
278/////////////////////////////////////////////////////////////////////////////
279{
280 file.write<operation_t>(operation_t::valid_data);
281}
282
283/////////////////////////////////////////////////////////////////////////////
285/////////////////////////////////////////////////////////////////////////////
286(
287 Table_Id table_id,
288 Record_Id record_id
289)
290{
291 if (table_id == table_of_last_operation &&
292 record_id == record_of_last_operation + 1)
293 {
294 file.write<operation_t>(operation_t::append);
295 }
296 else
297 {
298 file.write<operation_t>(operation_t::insert_into);
299 file.compact_write<>(to_underlying(table_id));
300 file.compact_write<>(to_underlying(record_id));
301 }
302
303 table_of_last_operation = table_id;
304 record_of_last_operation = record_id;
305}
306
307/////////////////////////////////////////////////////////////////////////////
309/////////////////////////////////////////////////////////////////////////////
310(
311 Table_Id table_id,
312 Record_Id record_id,
313 size_t size
314)
315{
316 file.write<operation_t>(operation_t::insert_vector);
317 file.compact_write<>(to_underlying(table_id));
318 file.compact_write<>(to_underlying(record_id));
319 file.compact_write<>(size);
320
321 table_of_last_operation = table_id;
322 record_of_last_operation = record_id;
323}
324
325/////////////////////////////////////////////////////////////////////////////
327/////////////////////////////////////////////////////////////////////////////
328(
329 Table_Id table_id,
330 Record_Id record_id
331)
332{
333 file.write<operation_t>(operation_t::delete_from);
334 file.compact_write<>(to_underlying(table_id));
335 file.compact_write<>(to_underlying(record_id));
336}
337
338/////////////////////////////////////////////////////////////////////////////
339void joedb::Writable_Journal::generic_update
340/////////////////////////////////////////////////////////////////////////////
341(
342 Table_Id table_id,
343 Record_Id record_id,
344 Field_Id field_id,
345 operation_t operation
346)
347{
348 if
349 (
350 table_id == table_of_last_operation &&
351 record_id == record_of_last_operation
352 )
353 {
354 constexpr int last =
355 int(operation_t::update_last_int8) -
356 int(operation_t::update_int8);
357
358 file.write<operation_t>(operation_t(int(operation) + last));
359 file.compact_write<>(to_underlying(field_id));
360 field_of_last_update = field_id;
361 }
362 else if
363 (
364 table_id == table_of_last_operation &&
365 record_id == record_of_last_operation + 1 &&
366 field_id == field_of_last_update
367 )
368 {
369 constexpr int next =
370 int(operation_t::update_next_int8) -
371 int(operation_t::update_int8);
372 file.write<operation_t>(operation_t(int(operation) + next));
373 ++record_of_last_operation;
374 }
375 else
376 {
377 file.write<operation_t>(operation);
378 file.compact_write<>(to_underlying(table_id));
379 file.compact_write<>(to_underlying(record_id));
380 file.compact_write<>(to_underlying(field_id));
381 table_of_last_operation = table_id;
382 record_of_last_operation = record_id;
383 field_of_last_update = field_id;
384 }
385}
386
387/////////////////////////////////////////////////////////////////////////////
388#define TYPE_MACRO(type, return_type, type_id, R, write_method)\
389void joedb::Writable_Journal::update_##type_id\
390(\
391 Table_Id table_id,\
392 Record_Id record_id,\
393 Field_Id field_id,\
394 return_type value\
395)\
396{\
397 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
398 file.write_method(value);\
399}\
400void joedb::Writable_Journal::update_vector_##type_id\
401(\
402 Table_Id table_id,\
403 Record_Id record_id,\
404 Field_Id field_id,\
405 size_t size,\
406 const type *value\
407)\
408{\
409 file.write<operation_t>(operation_t::update_vector_##type_id);\
410 file.compact_write<>(to_underlying(table_id));\
411 file.compact_write<>(to_underlying(record_id));\
412 file.compact_write<>(to_underlying(field_id));\
413 file.compact_write<>(size);\
414 table_of_last_operation = table_id;\
415 record_of_last_operation = record_id;\
416 field_of_last_update = field_id;\
417\
418 if\
419 (\
420 Type::Type_Id::type_id == Type::Type_Id::blob ||\
421 Type::Type_Id::type_id == Type::Type_Id::string ||\
422 Type::Type_Id::type_id == Type::Type_Id::reference\
423 )\
424 {\
425 for (size_t i = 0; i < size; i++)\
426 file.write_method(value[i]);\
427 }\
428 else\
429 file.write_data((const char *)value, size * sizeof(type));\
430}
431#include "joedb/TYPE_MACRO.h"
432
433/////////////////////////////////////////////////////////////////////////////
435/////////////////////////////////////////////////////////////////////////////
436(
437 const std::string &data
438)
439{
440 file.write<operation_t>(operation_t::blob);
441 const int64_t blob_position = get_position();
442 file.compact_write<size_t>(data.size());
443 file.flush();
444 file.sequential_write(data.data(), data.size());
445 return Blob(blob_position);
446}
447
448/////////////////////////////////////////////////////////////////////////////
450/////////////////////////////////////////////////////////////////////////////
451{
452 if (file.is_shared())
453 {
454 file.exclusive_lock_tail();
455 pull_without_locking();
456 }
457}
458
459/////////////////////////////////////////////////////////////////////////////
461/////////////////////////////////////////////////////////////////////////////
462{
463 if (file.is_shared())
464 file.unlock_tail();
465}
466
467/////////////////////////////////////////////////////////////////////////////
469/////////////////////////////////////////////////////////////////////////////
470{
471 if (ahead_of_checkpoint() > 0)
472 Destructor_Logger::write("Ahead_of_checkpoint in Writable_Journal destructor");
473}
void set_position(int64_t position)
bool is_readonly() const noexcept
static void write(const char *message) noexcept
static constexpr uint32_t version_number
static bool check_flag(Check check, Check flag)
static constexpr int64_t checkpoint_offset
static constexpr int64_t header_size
Blob write_blob_data(const std::string &data) final
int64_t ahead_of_checkpoint() const noexcept
int64_t pull_from(Readonly_Journal &journal, int64_t until_checkpoint=std::numeric_limits< int64_t >::max())
void checkpoint(Commit_Level commit_level) final
constexpr std::underlying_type< Table_Id >::type to_underlying(Table_Id id)
Definition index_types.h:15
uint8_t Type_Id_Storage
Definition Type.h:11
Commit_Level
Definition Writable.h:13