import "io/atomic_file";
AtomicFile provides a way to do atomic updates of files using transactions. The class is designed as a layer on top of the regular File. It is designed for creation of various custom file formats, the only requirement is that there are 32 bytes reserved somewhere in the file format header.
Concurrent access is supported (either in read only mode where multiple readers can use the file at once, or a single writer). This is achieved using the file locks and works between different processes and (if the OS implementation is not faulty) over network file systems too.
The maximum file size is based on the page size. In the default setting the limit is 16TB (4KB * 232).
It is recommended to use the transaction
statement when working with the transactions.
The implementation assumes that the file system (and the underlying layers and the hardware) is competent enough to not put garbage data into the file after synchronization and that the synchronization to the disk is guaranteed (it is actually written to the disk before it returns success). Therefore the implementation guards mainly against the partial writes (at byte granulity in any order or portions). The format uses CRC-32 checksum to detect corruption in the rollback.
The rollback is appended at the end of the file (with a hole between the original file size and the rollback to allow growth) and contains the original content of pages. If the file resizes into the rollback or beyond, the rollback is atomically moved to the new end of the file, increasing a hole between the new file size and the new rollback to allow more growth without moving the rollback again.
When there is a crash during the transaction the rollback is applied and the modified data is rewritten with its original content. After the rollback is applied the file is shrunk to remove the rollback. If there is a crash during applying of the rollback there is no problem, the process will repeat with the same result.
The rollback may contain duplicate pages, this is a result of using nested transactions. However only the first encounter of each page is restored on recovery. Each original content of the page is written first then commited into the rollback. When multiple pages are written at once, all pages except the first are pre-committed as the recovery will stop at any uncommited or partial page (eg. when the file was shrunk to remove the rollback but before the rollback was fully deactivated).
ATOMIC_FILE_HEADER_SIZE = 32
static function open(file: File, header_offset: Integer): AtomicFile
static function open(file: File, header_offset: Integer, page_size: Integer): AtomicFile
function close()
function register_cache_handler(flush_func, discard_func, data)
function begin()
function begin(write: Boolean)
function begin(write: Boolean, timeout: Integer): Boolean
function commit()
function rollback()
function in_transaction(): Boolean
function in_write_transaction(): Boolean
function set_on_rollback(container, key, value)
-1
to set the length of the array. For hash tables, if the value is null
the entry is removed. This function is provided to allow to reverse changes
to the in-memory structures related to the transaction.
function call_on_rollback(func, data, param)
set_on_rollback
function is insufficient, you can
register a call of a two parameter function (data is the first argument, and
the param is the second) on rollback.
function read(offset: Long, buf: Byte[])
function read(offset: Long, buf: Byte[], off: Integer, len: Integer)
function write(offset: Long, buf: Byte[])
function write(offset: Long, buf: Byte[], off: Integer, len: Integer)
function get_length(): Long
function set_length(new_size: Long)