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