36 throw Exception(
"Cannot create Writable_Journal with read-only file");
37 else if (lock.
size == 0)
55 ") is smaller than file size (" + std::to_string(lock.
size) +
56 "). This file may contain an aborted transaction. "
57 "'joedb_push file.joedb file fixed.joedb' can be used to truncate it."
77 if (checkpoint_position < until)
79 const int64_t size = until - checkpoint_position;
80 journal.get_file().copy_to(file, checkpoint_position, size);
81 soft_checkpoint_at(until);
84 return checkpoint_position;
99 throw Exception(
"writing must start at checkpoint position");
107 throw Exception(
"end_writing position is not matching file position");
130 reinterpret_cast<const char *
>(&neg),
204 const std::string &name
207 file_buffer.write<
operation_t>(operation_t::rename_table);
209 file_buffer.write_string(name);
217 const std::string &name,
221 file_buffer.write<
operation_t>(operation_t::add_field);
223 file_buffer.write_string(name);
225 if (type.get_type_id() == Type::Type_Id::reference)
226 file_buffer.compact_write<>(
to_underlying(type.get_table_id()));
237 file_buffer.write<
operation_t>(operation_t::drop_field);
248 const std::string &name
251 file_buffer.write<
operation_t>(operation_t::rename_field);
254 file_buffer.write_string(name);
296 if (table_id == table_of_last_operation &&
297 record_id == record_of_last_operation + 1)
299 file_buffer.write<
operation_t>(operation_t::append);
303 file_buffer.write<
operation_t>(operation_t::insert_into);
305 file_buffer.write_reference(record_id);
308 table_of_last_operation = table_id;
309 record_of_last_operation = record_id;
320 file_buffer.write<
operation_t>(operation_t::delete_from);
322 file_buffer.write_reference(record_id);
334 file_buffer.write<
operation_t>(operation_t::insert_vector);
336 file_buffer.write_reference(record_id);
337 file_buffer.compact_write<>(size);
339 table_of_last_operation = table_id;
340 record_of_last_operation = record_id;
352 file_buffer.write<
operation_t>(operation_t::delete_vector);
354 file_buffer.write_reference(record_id);
355 file_buffer.compact_write<>(size);
359 void Writable_Journal::generic_update
365 operation_t operation
370 table_id == table_of_last_operation &&
371 record_id == record_of_last_operation
375 int(operation_t::update_last_int8) -
376 int(operation_t::update_int8);
378 file_buffer.write<operation_t>(operation_t(
int(operation) + last));
380 field_of_last_update = field_id;
384 table_id == table_of_last_operation &&
385 record_id == record_of_last_operation + 1 &&
386 field_id == field_of_last_update
390 int(operation_t::update_next_int8) -
391 int(operation_t::update_int8);
392 file_buffer.write<operation_t>(operation_t(
int(operation) + next));
393 ++record_of_last_operation;
397 file_buffer.write<operation_t>(operation);
399 file_buffer.write_reference(record_id);
401 table_of_last_operation = table_id;
402 record_of_last_operation = record_id;
403 field_of_last_update = field_id;
408 #define TYPE_MACRO(type, return_type, type_id, R, write_method)\
409 void Writable_Journal::update_##type_id\
412 Record_Id record_id,\
417 generic_update(table_id, record_id, field_id, operation_t::update_##type_id);\
418 file_buffer.write_method(value);\
420 void Writable_Journal::update_vector_##type_id\
423 Record_Id record_id,\
429 file_buffer.write<operation_t>(operation_t::update_vector_##type_id);\
430 file_buffer.compact_write<>(to_underlying(table_id));\
431 file_buffer.write_reference(record_id);\
432 file_buffer.compact_write<>(to_underlying(field_id));\
433 file_buffer.compact_write<>(size);\
434 table_of_last_operation = table_id;\
435 record_of_last_operation = record_id;\
436 field_of_last_update = field_id;\
440 Type::Type_Id::type_id == Type::Type_Id::blob ||\
441 Type::Type_Id::type_id == Type::Type_Id::string ||\
442 Type::Type_Id::type_id == Type::Type_Id::reference\
445 for (size_t i = 0; i < size; i++)\
446 file_buffer.write_method(value[i]);\
449 file_buffer.write_data((const char *)value, size * sizeof(type));\
461 file_buffer.File_Iterator::write(data.data(), data.size());
462 return Blob(blob_position, int64_t(data.size()));
472 pull_without_locking();
492 offsetof(
Header, signature)
510 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)
virtual void unlock(int64_t start, int64_t size) noexcept
Remove a lock. The range should match the range of a corresponding lock.
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.
virtual void exclusive_lock(int64_t start, int64_t size)
Lock a range of bytes for writing (prevents both writes and reads)
static void warning(beman::cstring_view message) noexcept
int64_t get_position() const noexcept
void write_string(std::string_view s)
Head_Exclusive_Lock(Abstract_File &file)
Head_Exclusive_Lock(const Head_Exclusive_Lock &)=delete
Head_Exclusive_Lock & operator=(const Head_Exclusive_Lock &)=delete
static constexpr uint32_t format_version
friend class Writable_Journal
int64_t hard_checkpoint_position
int64_t checkpoint_position
int64_t get_checkpoint() const
Tail_Exclusive_Lock(Writable_Journal &journal)
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(std::string_view 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)