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