Joedb 10.3.0
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Readonly_Journal.cpp
Go to the documentation of this file.
3
4#include <vector>
5
6namespace joedb
7{
8 /////////////////////////////////////////////////////////////////////////////
10 /////////////////////////////////////////////////////////////////////////////
11 {
12 private:
13 Abstract_File &file;
14
15 public:
17 {
18 file.shared_lock_head();
19 }
20
23
25 {
26 file.unlock_head();
27 }
28 };
29}
30
31/////////////////////////////////////////////////////////////////////////////
32#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
33void joedb::Readonly_Journal::perform_update_##type_id(Writable &writable)\
34{\
35 const cpp_type value = read_method();\
36 writable.update_##type_id\
37 (\
38 table_of_last_operation,\
39 record_of_last_operation,\
40 field_of_last_update,\
41 value\
42 );\
43}
44#include "joedb/TYPE_MACRO.h"
45
46/////////////////////////////////////////////////////////////////////////////
48/////////////////////////////////////////////////////////////////////////////
49{
53}
54
55/////////////////////////////////////////////////////////////////////////////
57/////////////////////////////////////////////////////////////////////////////
58 file(lock.file),
59 file_buffer(file),
60 hard_index(0),
61 soft_index(0),
62 checkpoint_position(Header::size),
63 hard_checkpoint_position(Header::size)
64{
65 if (lock.size != 0)
66 {
67 Header header;
68 if (file.pread((char *)(&header), Header::size, 0) < Header::size)
70
72
74 {
75 if (lock.size > checkpoint_position)
77 }
78 else
79 {
80 if (header.signature != Header::joedb)
81 throw Exception("missing joedb signature");
82
83 if (header.version != format_version)
84 throw Exception("unsupported file format version");
85
86 read_checkpoint(header.checkpoint, lock.size);
87
88 if (lock.size > 0 && lock.size < checkpoint_position)
89 throw Exception("Checkpoint is bigger than file size");
90 }
91 }
92 else if (!lock.is_for_writable_journal())
93 throw Exception("file is empty");
94
96}
97
98/////////////////////////////////////////////////////////////////////////////
99void joedb::Readonly_Journal::read_checkpoint
100/////////////////////////////////////////////////////////////////////////////
101(
102 const std::array<int64_t, 4> &pos,
103 int64_t file_size
104)
105{
106 for (int i = 0; i < 2; i++)
107 {
108 if (pos[2 * i] == pos[2 * i + 1] && pos[2 * i] >= hard_checkpoint_position)
109 {
110 hard_checkpoint_position = pos[2 * i];
111 hard_index = i;
112 }
113
114 for (int j = 0; j < 2; j++)
115 {
116 if
117 (
118 -pos[2 * i + j] >= checkpoint_position &&
119 (file_size < 0 || -pos[2 * i + j] <= file_size)
120 )
121 {
122 checkpoint_position = -pos[2 * i + j];
123 hard_index = i ^ 1;
124 soft_index = j;
125 }
126 }
127 }
128
129 if (hard_checkpoint_position > checkpoint_position)
130 checkpoint_position = hard_checkpoint_position;
131}
132
133/////////////////////////////////////////////////////////////////////////////
134void joedb::Readonly_Journal::pull_without_locking()
135/////////////////////////////////////////////////////////////////////////////
136{
137 std::array<int64_t, 4> pos;
138 file.pread((char *)&pos, sizeof(pos), 0);
139 read_checkpoint(pos, -1);
140}
141
142/////////////////////////////////////////////////////////////////////////////
144/////////////////////////////////////////////////////////////////////////////
145{
146 const int64_t old_checkpoint = checkpoint_position;
147
148 Head_Shared_Lock lock(file);
149 pull_without_locking();
150
151 return checkpoint_position - old_checkpoint;
152}
153
154/////////////////////////////////////////////////////////////////////////////
156/////////////////////////////////////////////////////////////////////////////
157{
158 rewind();
159 play_until_checkpoint(writable);
160}
161
162/////////////////////////////////////////////////////////////////////////////
164/////////////////////////////////////////////////////////////////////////////
165(
166 Writable &writable
167)
168{
169 rewind();
170 writable.start_writing(get_position());
171 while(get_position() < checkpoint_position)
172 {
173 one_step(writable);
174 writable.comment(std::to_string(get_position()));
175 }
176 writable.end_writing(get_position());
177 file_buffer.flush();
178}
179
180/////////////////////////////////////////////////////////////////////////////
182/////////////////////////////////////////////////////////////////////////////
183{
184 file_buffer.set_position(Header::size);
185 reset_context();
186}
187
188/////////////////////////////////////////////////////////////////////////////
190/////////////////////////////////////////////////////////////////////////////
191{
192 while (get_position() < end)
193 one_step(writable);
194}
195
196/////////////////////////////////////////////////////////////////////////////
198/////////////////////////////////////////////////////////////////////////////
199{
200 if (get_position() < end)
201 {
202 const int64_t writable_position = writable.get_position();
203 if (get_position() < writable_position)
204 {
205 Dummy_Writable dummy_writable;
206 raw_play_until(dummy_writable, writable_position);
207 }
208 writable.start_writing(get_position());
209 raw_play_until(writable, end);
210 writable.end_writing(get_position());
211 writable.soft_checkpoint();
212 }
213
214 file_buffer.flush();
215}
216
217/////////////////////////////////////////////////////////////////////////////
219/////////////////////////////////////////////////////////////////////////////
220{
221 switch(file_buffer.read<operation_t>())
222 {
223 case operation_t::create_table:
224 {
225 const std::string name = safe_read_string();
226 writable.create_table(name);
227 }
228 break;
229
230 case operation_t::drop_table:
231 {
232 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
233 writable.drop_table(table_id);
234 }
235 break;
236
237 case operation_t::rename_table:
238 {
239 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
240 const std::string name = safe_read_string();
241 writable.rename_table(table_id, name);
242 }
243 break;
244
245 case operation_t::add_field:
246 {
247 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
248 const std::string name = safe_read_string();
249 const Type type = read_type();
250 writable.add_field(table_id, name, type);
251 }
252 break;
253
254 case operation_t::drop_field:
255 {
256 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
257 const Field_Id field_id = file_buffer.read_strong_type<Field_Id>();
258 writable.drop_field(table_id, field_id);
259 }
260 break;
261
262 case operation_t::rename_field:
263 {
264 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
265 const Field_Id field_id = file_buffer.read_strong_type<Field_Id>();
266 const std::string name = safe_read_string();
267 writable.rename_field(table_id, field_id, name);
268 }
269 break;
270
271 case operation_t::insert_into:
272 {
273 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
274 const Record_Id record_id = file_buffer.read_reference();
275 writable.insert_into(table_id, record_id);
276 table_of_last_operation = table_id;
277 record_of_last_operation = record_id;
278 }
279 break;
280
281 case operation_t::delete_from:
282 {
283 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
284 const Record_Id record_id = file_buffer.read_reference();
285 writable.delete_from(table_id, record_id);
286 }
287 break;
288
289 case operation_t::insert_vector:
290 {
291 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
292 const Record_Id record_id = file_buffer.read_reference();
293 const size_t size = file_buffer.compact_read<size_t>();
294 writable.insert_vector(table_id, record_id, size);
295 table_of_last_operation = table_id;
296 record_of_last_operation = record_id;
297 }
298 break;
299
300 case operation_t::delete_vector:
301 {
302 const Table_Id table_id = file_buffer.read_strong_type<Table_Id>();
303 const Record_Id record_id = file_buffer.read_reference();
304 const size_t size = file_buffer.compact_read<size_t>();
305 writable.delete_vector(table_id, record_id, size);
306 }
307 break;
308
309 case operation_t::append:
310 writable.insert_into(table_of_last_operation, ++record_of_last_operation);
311 break;
312
313 #define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
314 case operation_t::update_##type_id:\
315 table_of_last_operation = file_buffer.read_strong_type<Table_Id>();\
316 record_of_last_operation = file_buffer.read_reference();\
317 field_of_last_update = file_buffer.read_strong_type<Field_Id>();\
318 perform_update_##type_id(writable);\
319 break;\
320\
321 case operation_t::update_last_##type_id:\
322 field_of_last_update = file_buffer.read_strong_type<Field_Id>();\
323 perform_update_##type_id(writable);\
324 break;\
325\
326 case operation_t::update_next_##type_id:\
327 ++record_of_last_operation;\
328 perform_update_##type_id(writable);\
329 break;
330 #include "joedb/TYPE_MACRO.h"
331
332 #define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
333 case operation_t::update_vector_##type_id:\
334 {\
335 table_of_last_operation = file_buffer.read_strong_type<Table_Id>();\
336 record_of_last_operation = file_buffer.read_reference();\
337 field_of_last_update = file_buffer.read_strong_type<Field_Id>();\
338 const size_t size = file_buffer.compact_read<size_t>();\
339 if (size == 0)\
340 break;\
341 if (int64_t(size) > checkpoint_position)\
342 throw Exception("update_vector too big");\
343 size_t capacity;\
344 cpp_type *data = writable.get_own_##type_id##_storage\
345 (\
346 table_of_last_operation,\
347 record_of_last_operation,\
348 field_of_last_update,\
349 capacity\
350 );\
351 std::vector<cpp_type> buffer;\
352 if (!data)\
353 {\
354 buffer.resize(size);\
355 data = &buffer[0];\
356 }\
357 else if (to_underlying(record_of_last_operation) < 0 || to_underlying(record_of_last_operation) + size > capacity)\
358 throw Exception("update_vector out of range");\
359 read_vector_of_##type_id(data, size);\
360 writable.update_vector_##type_id\
361 (\
362 table_of_last_operation,\
363 record_of_last_operation,\
364 field_of_last_update,\
365 size,\
366 data\
367 );\
368 }\
369 break;
370 #include "joedb/TYPE_MACRO.h"
371
372 case operation_t::custom:
373 {
374 const std::string name = safe_read_string();
375 writable.custom(name);
376 }
377 break;
378
379 case operation_t::comment:
380 {
381 const std::string comment = safe_read_string();
382 writable.comment(comment);
383 }
384 break;
385
386 case operation_t::timestamp:
387 {
388 const int64_t timestamp = file_buffer.read<int64_t>();
389 writable.timestamp(timestamp);
390 }
391 break;
392
393 case operation_t::valid_data:
394 writable.valid_data();
395 break;
396
397 case operation_t::blob:
398 {
399 const int64_t size = file_buffer.compact_read<int64_t>();
400 writable.on_blob(Blob(get_position(), size));
401
402 if (writable.wants_blob_data() && size < checkpoint_position)
403 {
404 std::string s(size_t(size), 0);
405 if (size > 0)
406 file_buffer.read_data(s.data(), s.size());
407 writable.write_blob(s);
408 }
409 else
410 file_buffer.ignore(size);
411 }
412 break;
413
414 default:
415 {
416 throw Exception("Unexpected operation: get_position() = " + std::to_string(get_position()));
417 }
418 }
419}
420
421/////////////////////////////////////////////////////////////////////////////
423/////////////////////////////////////////////////////////////////////////////
424{
425 const Type::Type_Id type_id = Type::Type_Id(file_buffer.read<Type_Id_Storage>());
426 if (type_id == Type::Type_Id::reference)
427 return Type::reference(file_buffer.read_strong_type<Table_Id>());
428 else
429 return Type(type_id);
430}
431
432/////////////////////////////////////////////////////////////////////////////
434/////////////////////////////////////////////////////////////////////////////
435{
436 return file_buffer.safe_read_string(checkpoint_position);
437}
438
439#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
440void joedb::Readonly_Journal::read_vector_of_##type_id(cpp_type *data, size_t size)\
441{\
442 for (size_t i = 0; i < size; i++)\
443 data[i] = read_method();\
444}
445#define TYPE_MACRO_NO_INT
446#define TYPE_MACRO_NO_FLOAT
447#include "joedb/TYPE_MACRO.h"
448
449#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
450void joedb::Readonly_Journal::read_vector_of_##type_id(cpp_type *data, size_t size)\
451{\
452 file_buffer.read_data((char *)data, size * sizeof(cpp_type));\
453}
454#define TYPE_MACRO_NO_STRING
455#define TYPE_MACRO_NO_REFERENCE
456#define TYPE_MACRO_NO_BLOB
457#include "joedb/TYPE_MACRO.h"
static void reading_past_end_of_file()
void unlock_head() noexcept
virtual size_t pread(char *data, size_t size, int64_t offset) const
Read a range of bytes.
Writable with empty insert_vector and delete_vector.
Definition Writable.h:120
void set_position(int64_t position)
Head_Shared_Lock(const Head_Shared_Lock &)=delete
Head_Shared_Lock(Abstract_File &file)
Head_Shared_Lock & operator=(const Head_Shared_Lock &)=delete
void play_until(Writable &writable, int64_t end)
void one_step(Writable &writable)
static constexpr uint32_t format_version
void replay_with_checkpoint_comments(Writable &writable)
void replay_log(Writable &writable)
void raw_play_until(Writable &writable, int64_t end)
Readonly_Journal(Journal_Construction_Lock &lock)
static Type reference(Table_Id table_id)
Definition Type.h:52
Superclass with all joedb journal event listeners as virtual functions.
Definition Writable.h:17
virtual void insert_vector(Table_Id table_id, Record_Id record_id, size_t size)=0
Definition Writable.cpp:33
virtual Blob write_blob(const std::string &data)
Definition Writable.h:111
virtual void insert_into(Table_Id table_id, Record_Id record_id)
Definition Writable.h:50
virtual void drop_table(Table_Id table_id)
Definition Writable.h:27
virtual void create_table(const std::string &name)
Definition Writable.h:26
virtual void drop_field(Table_Id table_id, Field_Id field_id)
Definition Writable.h:36
virtual void rename_table(Table_Id table_id, const std::string &name)
Definition Writable.h:28
virtual void delete_vector(Table_Id table_id, Record_Id record_id, size_t size)=0
Definition Writable.cpp:44
virtual void soft_checkpoint()
Definition Writable.h:23
virtual bool wants_blob_data() const
Definition Writable.h:110
virtual void custom(const std::string &name)
Definition Writable.h:44
virtual void start_writing(int64_t position)
Definition Writable.h:20
virtual void add_field(Table_Id table_id, const std::string &name, Type type)
Definition Writable.h:31
virtual void delete_from(Table_Id table_id, Record_Id record_id)
Definition Writable.h:51
virtual void end_writing(int64_t position)
Definition Writable.h:21
virtual int64_t get_position() const
Definition Writable.h:19
virtual void comment(const std::string &comment)
Definition Writable.h:45
virtual void on_blob(Blob blob)
Definition Writable.h:109
virtual void valid_data()
Definition Writable.h:47
virtual void rename_field(Table_Id table_id, Field_Id field_id, const std::string &name)
Definition Writable.h:38
virtual void timestamp(int64_t timestamp)
Definition Writable.h:46
@ ignore_header
use file size as checkpoint
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