7#if __cplusplus < 201703L
14#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
15void joedb::Readonly_Journal::perform_update_##type_id(Writable &writable)\
17 const cpp_type value = read_method();\
18 writable.update_##type_id\
20 table_of_last_operation,\
21 record_of_last_operation,\
22 field_of_last_update,\
35 file(lock.get_file()),
38 checkpoint_position(header_size),
39 table_of_last_operation(
Table_Id(0)),
48 if (!lock.is_creating_new())
60 throw Exception(
"File does not start by 'joedb'");
71 if (file_version < compatible_version || file_version >
version_number)
72 throw Exception(
"Unsupported format version");
77 for (
int i = 0; i < 4; i++)
80 read_checkpoint(lock.pos);
102 std::to_string(file_size) +
"). This file may contain an aborted transaction. "
103 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
113 throw Exception(
"Checkpoint is bigger than file size");
122void joedb::Readonly_Journal::read_checkpoint
125 const std::array<int64_t, 4> &pos
128 for (
unsigned i = 0; i < 2; i++)
130 if (pos[2 * i] == pos[2 * i + 1] && pos[2 * i] >= checkpoint_position)
132 checkpoint_position = pos[2 * i];
133 checkpoint_index = i;
139void joedb::Readonly_Journal::pull_without_locking()
142 const int64_t old_position = file.get_position();
143 std::array<int64_t, 4> pos;
144 file.pread((
char *)&pos,
sizeof(pos), checkpoint_offset);
145 read_checkpoint(pos);
146 file.set_position(old_position);
153 file.shared_lock_head();
154 pull_without_locking();
163 play_until_checkpoint(writable);
174 while(file.get_position() < checkpoint_position)
177 writable.comment(std::to_string(file.get_position()));
179 writable.default_checkpoint();
186 file.set_position(header_size);
193 file.set_position(position);
200 while(file.get_position() < end)
202 file.set_position(file.get_position());
209 return file.get_position() >= checkpoint_position;
218 case operation_t::create_table:
220 std::string name = safe_read_string();
225 case operation_t::drop_table:
232 case operation_t::rename_table:
235 std::string name = safe_read_string();
240 case operation_t::add_field:
243 std::string name = safe_read_string();
244 const Type type = read_type();
245 writable.
add_field(table_id, name, type);
249 case operation_t::drop_field:
257 case operation_t::rename_field:
261 std::string name = safe_read_string();
266 case operation_t::insert_into:
271 table_of_last_operation = table_id;
272 record_of_last_operation = record_id;
276 case operation_t::insert_vector:
280 const size_t size = file.compact_read<
size_t>();
282 table_of_last_operation = table_id;
283 record_of_last_operation = record_id;
287 case operation_t::append:
289 ++record_of_last_operation);
292 case operation_t::delete_from:
300 #define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
301 case operation_t::update_##type_id:\
302 table_of_last_operation = file.read_strong_type<Table_Id>();\
303 record_of_last_operation = file.read_strong_type<Record_Id>();\
304 field_of_last_update = file.read_strong_type<Field_Id>();\
305 perform_update_##type_id(writable);\
308 case operation_t::update_last_##type_id:\
309 field_of_last_update = file.read_strong_type<Field_Id>();\
310 perform_update_##type_id(writable);\
313 case operation_t::update_next_##type_id:\
314 ++record_of_last_operation;\
315 perform_update_##type_id(writable);\
319 #define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
320 case operation_t::update_vector_##type_id:\
322 table_of_last_operation = file.read_strong_type<Table_Id>();\
323 record_of_last_operation = file.read_strong_type<Record_Id>();\
324 field_of_last_update = file.read_strong_type<Field_Id>();\
325 const size_t size = file.compact_read<size_t>();\
326 if (int64_t(size) > checkpoint_position)\
327 throw Exception("update_vector too big");\
329 cpp_type *data = writable.get_own_##type_id##_storage\
331 table_of_last_operation,\
332 record_of_last_operation,\
333 field_of_last_update,\
336 std::vector<cpp_type> buffer;\
339 buffer.resize(size);\
342 else if (to_underlying(record_of_last_operation) <= 0 || to_underlying(record_of_last_operation) + size - 1 > capacity)\
343 throw Exception("update_vector out of range");\
344 read_vector_of_##type_id(data, size);\
345 writable.update_vector_##type_id\
347 table_of_last_operation,\
348 record_of_last_operation,\
349 field_of_last_update,\
357 case operation_t::custom:
359 const std::string name = safe_read_string();
364 case operation_t::comment:
366 const std::string comment = safe_read_string();
371 case operation_t::timestamp:
373 const int64_t timestamp = file.read<int64_t>();
378 case operation_t::valid_data:
382 case operation_t::blob:
390 const int64_t size = file.compact_read<int64_t>();
398 throw Exception(
"Unexpected operation: file.get_position() = " + std::to_string(file.get_position()));
408 if (type_id == Type::Type_Id::reference)
411 return Type(type_id);
418 return file.safe_read_string(checkpoint_position);
421#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
422void joedb::Readonly_Journal::read_vector_of_##type_id(cpp_type *data, size_t size)\
424 for (size_t i = 0; i < size; i++)\
425 data[i] = read_method();\
427#define TYPE_MACRO_NO_INT
428#define TYPE_MACRO_NO_FLOAT
431#define TYPE_MACRO(cpp_type, return_type, type_id, read_method, W)\
432void joedb::Readonly_Journal::read_vector_of_##type_id(cpp_type *data, size_t size)\
434 file.read_data((char *)data, size * sizeof(cpp_type));\
436#define TYPE_MACRO_NO_STRING
437#define TYPE_MACRO_NO_REFERENCE
438#define TYPE_MACRO_NO_BLOB
virtual int64_t get_size() const
void set_position(int64_t position)
static constexpr uint32_t version_number
void play_until(Writable &writable, int64_t end)
void one_step(Writable &writable)
std::string safe_read_string()
void replay_with_checkpoint_comments(Writable &writable)
Readonly_Journal(Journal_Construction_Lock &lock, Check check)
static constexpr uint32_t compatible_version
void set_position(int64_t position)
void replay_log(Writable &writable)
static bool check_flag(Check check, Check flag)
bool at_end_of_file() const
int64_t checkpoint_position
static constexpr int64_t header_size
static Type reference(Table_Id table_id)
virtual void insert_into(Table_Id table_id, Record_Id record_id)
virtual void drop_table(Table_Id table_id)
virtual void create_table(const std::string &name)
virtual void drop_field(Table_Id table_id, Field_Id field_id)
virtual Blob write_blob_data(const std::string &data)
virtual void rename_table(Table_Id table_id, const std::string &name)
virtual void insert_vector(Table_Id table_id, Record_Id record_id, size_t size)
virtual bool wants_blob_data() const
virtual void custom(const std::string &name)
virtual void add_field(Table_Id table_id, const std::string &name, Type type)
virtual void delete_from(Table_Id table_id, Record_Id record_id)
virtual void comment(const std::string &comment)
virtual void on_blob(Blob blob)
virtual void valid_data()
virtual void rename_field(Table_Id table_id, Field_Id field_id, const std::string &name)
virtual void timestamp(int64_t timestamp)