14 throw Exception(
"Cannot create Writable_Journal with read-only file");
15 else if (lock.
size == 0)
33 ") is smaller than file size (" + std::to_string(lock.
size) +
34 "). This file may contain an aborted transaction. "
35 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
48 if (checkpoint_position < until)
50 const int64_t size = until - checkpoint_position;
51 journal.get_file().copy_to(file, checkpoint_position, size);
52 soft_checkpoint_at(until);
55 return checkpoint_position;
70 throw Exception(
"writing must start at checkpoint position");
78 throw Exception(
"end_writing position is not matching file position");
101 reinterpret_cast<const char *
>(&neg),
175 const std::string &name
178 file_buffer.write<
operation_t>(operation_t::rename_table);
180 file_buffer.write_string(name);
188 const std::string &name,
192 file_buffer.write<
operation_t>(operation_t::add_field);
194 file_buffer.write_string(name);
196 if (type.get_type_id() == Type::Type_Id::reference)
197 file_buffer.compact_write<>(
to_underlying(type.get_table_id()));
208 file_buffer.write<
operation_t>(operation_t::drop_field);
219 const std::string &name
222 file_buffer.write<
operation_t>(operation_t::rename_field);
225 file_buffer.write_string(name);
267 if (table_id == table_of_last_operation &&
268 record_id == record_of_last_operation + 1)
270 file_buffer.write<
operation_t>(operation_t::append);
274 file_buffer.write<
operation_t>(operation_t::insert_into);
276 file_buffer.write_reference(record_id);
279 table_of_last_operation = table_id;
280 record_of_last_operation = record_id;
291 file_buffer.write<
operation_t>(operation_t::delete_from);
293 file_buffer.write_reference(record_id);
305 file_buffer.write<
operation_t>(operation_t::insert_vector);
307 file_buffer.write_reference(record_id);
308 file_buffer.compact_write<>(size);
310 table_of_last_operation = table_id;
311 record_of_last_operation = record_id;
323 file_buffer.write<
operation_t>(operation_t::delete_vector);
325 file_buffer.write_reference(record_id);
326 file_buffer.compact_write<>(size);
330 void Writable_Journal::generic_update
336 operation_t operation
341 table_id == table_of_last_operation &&
342 record_id == record_of_last_operation
346 int(operation_t::update_last_int8) -
347 int(operation_t::update_int8);
349 file_buffer.write<operation_t>(operation_t(
int(operation) + last));
351 field_of_last_update = field_id;
355 table_id == table_of_last_operation &&
356 record_id == record_of_last_operation + 1 &&
357 field_id == field_of_last_update
361 int(operation_t::update_next_int8) -
362 int(operation_t::update_int8);
363 file_buffer.write<operation_t>(operation_t(
int(operation) + next));
364 ++record_of_last_operation;
368 file_buffer.write<operation_t>(operation);
370 file_buffer.write_reference(record_id);
372 table_of_last_operation = table_id;
373 record_of_last_operation = record_id;
374 field_of_last_update = field_id;
379 #define TYPE_MACRO(type, return_type, type_id, R, write_method)\
380 void Writable_Journal::update_##type_id\
383 Record_Id record_id,\
388 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
389 file_buffer.write_method(value);\
391 void Writable_Journal::update_vector_##type_id\
394 Record_Id record_id,\
400 file_buffer.write<operation_t>(operation_t::update_vector_##type_id);\
401 file_buffer.compact_write<>(to_underlying(table_id));\
402 file_buffer.write_reference(record_id);\
403 file_buffer.compact_write<>(to_underlying(field_id));\
404 file_buffer.compact_write<>(size);\
405 table_of_last_operation = table_id;\
406 record_of_last_operation = record_id;\
407 field_of_last_update = field_id;\
411 Type::Type_Id::type_id == Type::Type_Id::blob ||\
412 Type::Type_Id::type_id == Type::Type_Id::string ||\
413 Type::Type_Id::type_id == Type::Type_Id::reference\
416 for (size_t i = 0; i < size; i++)\
417 file_buffer.write_method(value[i]);\
420 file_buffer.write_data((const char *)value, size * sizeof(type));\
428 const std::string &data
432 file_buffer.compact_write<
size_t>(data.size());
433 const int64_t blob_position = get_position();
435 file_buffer.File_Iterator::write(data.data(), data.size());
436 return Blob(blob_position, int64_t(data.size()));
446 pull_without_locking();
471 throw Exception(
"locking journal with uncheckpointed data (try rollback?)");
virtual int64_t get_size() const
Get the size of the file, or -1 if it is unknown.
virtual void datasync()
Write data durably (no file-size change)
bool is_readonly() const noexcept
virtual void sync()
Write data durably (including file-size change)
bool is_shared() const noexcept
void exclusive_lock_tail()
void unlock_tail() noexcept
virtual void pwrite(const char *data, size_t size, int64_t offset)
Write a range of bytes. Extend file size if necessary.
static void warning(std::string_view message) noexcept
int64_t get_position() const noexcept
void write_string(const std::string &s)
Journal_Lock(Writable_Journal &journal)
static constexpr uint32_t format_version
friend class Writable_Journal
int64_t hard_checkpoint_position
int64_t checkpoint_position
int64_t get_checkpoint() const
int64_t pull_from(const Readonly_Journal &journal, int64_t until)
void valid_data() override
void soft_checkpoint() override
int64_t ahead_of_checkpoint() const noexcept
void soft_checkpoint_at(int64_t position)
void start_writing(int64_t position) override
int64_t get_position() const override
void end_writing(int64_t position) override
~Writable_Journal() override
void hard_checkpoint() override
Blob write_blob(const std::string &data) 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)