12 throw Exception(
"Cannot create Writable_Journal with read-only file");
13 else if (lock.
size == 0)
31 ") is smaller than file size (" + std::to_string(lock.
size) +
32 "). This file may contain an aborted transaction. "
33 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
46 if (checkpoint_position < until)
48 const int64_t size = until - checkpoint_position;
49 journal.get_file().copy_to(file, checkpoint_position, size);
50 soft_checkpoint_at(until);
53 return checkpoint_position;
60 return file.get_position() - checkpoint_position;
67 if (position != checkpoint_position)
68 throw Exception(
"writing must start at checkpoint position");
75 if (position != file.get_position())
76 throw Exception(
"end_writing position is not matching file position");
83 if (checkpoint_position >= position)
91 checkpoint_position = position;
95 const int64_t neg = -checkpoint_position;
99 reinterpret_cast<const char *
>(&neg),
101 int64_t(
sizeof(neg)) * (2 * (hard_index ^ 1) + soft_index)
109 if (hard_checkpoint_position >= position)
115 hard_checkpoint_position = checkpoint_position = position;
121 reinterpret_cast<const char *
>(&checkpoint_position),
122 sizeof(checkpoint_position),
123 int64_t(
sizeof(checkpoint_position)) * (2 * hard_index)
130 reinterpret_cast<const char *
>(&checkpoint_position),
131 sizeof(checkpoint_position),
132 int64_t(
sizeof(checkpoint_position)) * (2 * hard_index + 1)
142 soft_checkpoint_at(file.get_position());
149 hard_checkpoint_at(file.get_position());
156 file.write<
operation_t>(operation_t::create_table);
157 file.write_string(name);
173 const std::string &name
176 file.write<
operation_t>(operation_t::rename_table);
178 file.write_string(name);
186 const std::string &name,
192 file.write_string(name);
194 if (type.get_type_id() == Type::Type_Id::reference)
217 const std::string &name
220 file.write<
operation_t>(operation_t::rename_field);
223 file.write_string(name);
231 file.write_string(name);
239 file.write_string(comment);
247 file.write<int64_t>(timestamp);
265 if (table_id == table_of_last_operation &&
266 record_id == record_of_last_operation + 1)
274 file.write_reference(record_id);
277 table_of_last_operation = table_id;
278 record_of_last_operation = record_id;
291 file.write_reference(record_id);
303 file.write<
operation_t>(operation_t::insert_vector);
305 file.write_reference(record_id);
306 file.compact_write<>(size);
308 table_of_last_operation = table_id;
309 record_of_last_operation = record_id;
321 file.write<
operation_t>(operation_t::delete_vector);
323 file.write_reference(record_id);
324 file.compact_write<>(size);
328void joedb::Writable_Journal::generic_update
334 operation_t operation
339 table_id == table_of_last_operation &&
340 record_id == record_of_last_operation
344 int(operation_t::update_last_int8) -
345 int(operation_t::update_int8);
347 file.write<operation_t>(operation_t(
int(operation) + last));
349 field_of_last_update = field_id;
353 table_id == table_of_last_operation &&
354 record_id == record_of_last_operation + 1 &&
355 field_id == field_of_last_update
359 int(operation_t::update_next_int8) -
360 int(operation_t::update_int8);
361 file.write<operation_t>(operation_t(
int(operation) + next));
362 ++record_of_last_operation;
366 file.write<operation_t>(operation);
368 file.write_reference(record_id);
370 table_of_last_operation = table_id;
371 record_of_last_operation = record_id;
372 field_of_last_update = field_id;
377#define TYPE_MACRO(type, return_type, type_id, R, write_method)\
378void joedb::Writable_Journal::update_##type_id\
381 Record_Id record_id,\
386 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
387 file.write_method(value);\
389void joedb::Writable_Journal::update_vector_##type_id\
392 Record_Id record_id,\
398 file.write<operation_t>(operation_t::update_vector_##type_id);\
399 file.compact_write<>(to_underlying(table_id));\
400 file.write_reference(record_id);\
401 file.compact_write<>(to_underlying(field_id));\
402 file.compact_write<>(size);\
403 table_of_last_operation = table_id;\
404 record_of_last_operation = record_id;\
405 field_of_last_update = field_id;\
409 Type::Type_Id::type_id == Type::Type_Id::blob ||\
410 Type::Type_Id::type_id == Type::Type_Id::string ||\
411 Type::Type_Id::type_id == Type::Type_Id::reference\
414 for (size_t i = 0; i < size; i++)\
415 file.write_method(value[i]);\
418 file.write_data((const char *)value, size * sizeof(type));\
426 const std::string &data
430 file.compact_write<
size_t>(data.size());
431 const int64_t blob_position = get_position();
433 file.sequential_write(data.data(), data.size());
434 return Blob(blob_position, int64_t(data.size()));
441 if (file.is_shared())
443 file.exclusive_lock_tail();
444 pull_without_locking();
452 if (file.is_shared())
460 if (ahead_of_checkpoint() > 0)
bool is_readonly() const noexcept
static void write(const char *message) noexcept
static constexpr uint32_t format_version
friend class Writable_Journal
int64_t checkpoint_position
void sequential_write(const char *data, size_t size)
int64_t pull_from(const Readonly_Journal &journal, int64_t until)
void valid_data() override
void soft_checkpoint() override
Blob write_blob(const std::string &data) override
int64_t ahead_of_checkpoint() const noexcept
void soft_checkpoint_at(int64_t position)
void start_writing(int64_t position) override
void end_writing(int64_t position) override
~Writable_Journal() override
void hard_checkpoint() override
void hard_checkpoint_at(int64_t position)
#define JOEDB_DEBUG_ASSERT(x)
assertion tested in debug mode
@ overwrite
allow overwriting an uncheckpointed tail
constexpr index_t to_underlying(Record_Id id)