Rustler NIF bindings for Bitcask record I/O, hint files, and mmap-backed probabilistic data structure file operations.
Summary
Functions
Append one binary and fdatasync it without following a final symlink.
Append and fdatasync only when the opened regular file stays within max_bytes.
Durably replace a file atomically when the payload is within max_bytes.
Stream-copy a locked regular file and atomically replace the destination.
Stream-copy a regular file into a new destination without following final symlinks.
Does the path exist? Follows symlinks (broken symlink → false). Never returns an error for the common kinds (missing, no-permission).
Atomically replace the destination with a hard link to a locked regular file.
Is the path a directory? Follows symlinks. Returns false for
missing paths (matches File.dir?/1).
List the entries in a directory (names only, no path prefix). Yields every 256 entries to keep BEAM reductions accurate on huge directories.
Recursive mkdir -p. Idempotent when the directory already exists.
Equivalent to File.mkdir_p/1.
Read at most max_bytes from a regular file while refusing a symlink at the
final path component. The size is checked before the BEAM binary is allocated.
Read a private regular file without following a final symlink.
Atomic rename. On POSIX, rename replaces the target atomically.
Cross-device renames return {:error, {:other, _}} — caller must
handle with copy+remove.
Remove a single file. Use fs_rm_rf_async/3 for directory trees.
Async recursive remove. Runs on the Tokio blocking pool; sends
{:tokio_complete, correlation_id, :ok} or
{:tokio_complete, correlation_id, :error, {kind, msg}} to the
caller on completion. Idempotent: removing a non-existent path sends
:ok.
Creates an empty file if it does not exist. Idempotent on an existing
file (does not truncate). Equivalent to File.touch!/1 without the
timestamp update (matches our callers' usage).
Fsyncs a directory so that recent File.rename/2, File.rm/1,
File.touch!/1, or File.create/1 operations on files inside it are
durable. Use after any namespace mutation that must survive a kernel
panic — rotation, compaction rename, hint-file creation, prob-file
create/delete, shard init.
Strictly scans at most max_records physical log records for tombstones.
Types
@type append_op() :: {:put, binary(), binary(), non_neg_integer()} | {:delete, binary()}
@type append_op_location() :: {:put, non_neg_integer(), non_neg_integer()} | {:delete, non_neg_integer(), non_neg_integer()}
@type flow_index_resource() :: reference()
@type flow_record_claim_history_entry() :: {binary(), binary(), non_neg_integer(), non_neg_integer(), binary(), binary(), non_neg_integer() | nil, non_neg_integer() | nil, boolean()}
@type flow_record_claim_history_plan() :: {binary(), flow_index_claim_entry(), binary(), non_neg_integer() | nil, flow_record_claim_history_entry()}
@type flow_record_claim_plan() :: {binary(), flow_index_claim_entry(), binary(), non_neg_integer() | nil}
@type pread_batch_result() :: [pread_batch_value()]
Functions
@spec bloom_file_add_at( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, 0 | 1} | {:error, term()}
@spec bloom_file_card(binary()) :: {:ok, non_neg_integer()} | {:error, term()}
@spec bloom_file_create(binary(), non_neg_integer(), non_neg_integer()) :: :ok | {:error, term()}
@spec bloom_file_info(binary()) :: {:ok, {non_neg_integer(), non_neg_integer(), non_neg_integer()}} | {:error, term()}
@spec bloom_file_madd_at( binary(), binary(), [binary()], non_neg_integer(), non_neg_integer() ) :: {:ok, [0 | 1]} | {:error, term()}
@spec cms_file_create(binary(), non_neg_integer(), non_neg_integer()) :: :ok | {:error, term()}
@spec cms_file_incrby(binary(), [{binary(), non_neg_integer()}]) :: :ok | {:error, term()}
@spec cms_file_incrby_at( binary(), binary(), [{binary(), integer()}], non_neg_integer(), non_neg_integer() ) :: {:ok, [integer()]} | {:error, term()}
@spec cms_file_info(binary()) :: {:ok, {non_neg_integer(), non_neg_integer(), non_neg_integer()}} | {:error, term()}
@spec cms_file_merge_at( binary(), binary(), [binary()], [integer()], non_neg_integer(), non_neg_integer() ) :: :ok | {:error, term()}
@spec cms_file_query(binary(), [binary()]) :: {:ok, [non_neg_integer()]} | {:error, term()}
@spec cuckoo_file_add_at( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, 0 | 1} | {:error, term()}
@spec cuckoo_file_addnx_at( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, 0 | 1} | {:error, term()}
@spec cuckoo_file_count(binary(), binary()) :: {:ok, non_neg_integer()} | {:error, term()}
@spec cuckoo_file_create(binary(), non_neg_integer(), non_neg_integer()) :: :ok | {:error, term()}
@spec cuckoo_file_del_at( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, 0 | 1} | {:error, term()}
@spec flow_history_encode( binary(), non_neg_integer() | nil, non_neg_integer() | nil, binary() | nil, binary() | nil, binary() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() ) :: binary()
@spec flow_index_apply_claim_entries(flow_index_resource(), [flow_index_claim_entry()]) :: :ok
@spec flow_index_claim_due_candidates( flow_index_resource(), [binary()], float(), non_neg_integer(), non_neg_integer() ) :: [{binary(), [{binary(), float()}]}]
@spec flow_index_count_all(flow_index_resource(), binary()) :: non_neg_integer()
@spec flow_index_count_keys_page( flow_index_resource(), binary() | nil, non_neg_integer() ) :: [binary()]
@spec flow_index_count_many(flow_index_resource(), [binary()]) :: [non_neg_integer()]
@spec flow_index_delete_count(flow_index_resource(), binary()) :: :ok
@spec flow_index_delete_entries(flow_index_resource(), [{binary(), binary()}]) :: :ok
@spec flow_index_delete_members(flow_index_resource(), binary(), [binary()]) :: :ok
@spec flow_index_due_count_keys_page( flow_index_resource(), binary() | nil, non_neg_integer() ) :: [binary()]
@spec flow_index_due_keys_present(flow_index_resource(), [binary()], float()) :: [ binary() ]
@spec flow_index_move_entries(flow_index_resource(), [ {binary(), binary(), binary(), float()} ]) :: :ok
@spec flow_index_new() :: flow_index_resource()
@spec flow_index_put_entries(flow_index_resource(), [{binary(), binary(), float()}]) :: :ok
@spec flow_index_put_new_entries(flow_index_resource(), [ {binary(), binary(), float()} ]) :: :ok
@spec flow_index_range_after_slice( flow_index_resource(), binary(), non_neg_integer(), float(), non_neg_integer(), float(), float(), binary(), non_neg_integer(), non_neg_integer() ) :: [{binary(), float()}]
@spec flow_index_range_cursor_slice( flow_index_resource(), binary(), non_neg_integer(), float(), non_neg_integer(), float(), float(), binary(), non_neg_integer(), non_neg_integer() ) :: [{binary(), float()}]
@spec flow_index_range_slice( flow_index_resource(), binary(), non_neg_integer(), float(), non_neg_integer(), float(), boolean(), non_neg_integer(), non_neg_integer() ) :: [{binary(), float()}]
@spec flow_index_restore_count(flow_index_resource(), binary(), integer()) :: :ok
@spec flow_index_rollback_claim_entries(flow_index_resource(), [ flow_index_claim_entry() ]) :: :ok
@spec flow_index_score_of(flow_index_resource(), binary(), binary()) :: {:ok, float()} | :miss
@spec flow_index_take_due( flow_index_resource(), binary(), float(), non_neg_integer() ) :: [{binary(), float()}]
flow_record_encode(id, type, state, version, attempts, fencing_token, created_at_ms, updated_at_ms, next_run_at_ms, priority, ttl_ms, history_hot_max_events, history_max_events, retention_ttl_ms, terminal_retention_until_ms, max_active_ms, partition_key, payload_ref, parent_flow_id, parent_partition_key, root_flow_id, correlation_id, result_ref, error_ref, lease_owner, lease_token, lease_deadline_ms, run_state, rewound_to_event_id, child_groups_encoded)
@spec flow_record_encode( binary() | nil, binary() | nil, binary() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, non_neg_integer() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, binary() | nil, non_neg_integer() | nil, binary() | nil, binary() | nil, binary() ) :: binary()
@spec flow_record_plan_claims( [{binary(), float()}], [binary() | nil], binary(), binary(), binary(), non_neg_integer(), non_neg_integer(), non_neg_integer(), binary(), binary(), binary(), binary(), binary(), binary(), binary() ) :: {:ok, [flow_record_claim_plan()], [binary()], non_neg_integer()} | :fallback
@spec flow_record_plan_claims_with_history( [{binary(), float()}], [binary() | nil], binary(), binary(), binary(), non_neg_integer(), non_neg_integer(), non_neg_integer(), binary(), binary(), binary(), binary(), binary(), binary(), binary(), binary() ) :: {:ok, [flow_record_claim_history_plan()], [binary()], non_neg_integer()} | :fallback
Append one binary and fdatasync it without following a final symlink.
@spec fs_append_sync_nofollow_bounded(binary(), binary(), non_neg_integer()) :: :ok | fs_error()
Append and fdatasync only when the opened regular file stays within max_bytes.
@spec fs_atomic_replace_nofollow(binary(), binary(), non_neg_integer()) :: :ok | fs_error()
Durably replace a file atomically when the payload is within max_bytes.
Stream-copy a locked regular file and atomically replace the destination.
Stream-copy a regular file into a new destination without following final symlinks.
Does the path exist? Follows symlinks (broken symlink → false). Never returns an error for the common kinds (missing, no-permission).
Atomically replace the destination with a hard link to a locked regular file.
Is the path a directory? Follows symlinks. Returns false for
missing paths (matches File.dir?/1).
List the entries in a directory (names only, no path prefix). Yields every 256 entries to keep BEAM reductions accurate on huge directories.
Recursive mkdir -p. Idempotent when the directory already exists.
Equivalent to File.mkdir_p/1.
@spec fs_read_nofollow(binary(), non_neg_integer()) :: {:ok, binary()} | fs_error()
Read at most max_bytes from a regular file while refusing a symlink at the
final path component. The size is checked before the BEAM binary is allocated.
@spec fs_read_private_nofollow(binary(), non_neg_integer()) :: {:ok, binary()} | fs_error()
Read a private regular file without following a final symlink.
Atomic rename. On POSIX, rename replaces the target atomically.
Cross-device renames return {:error, {:other, _}} — caller must
handle with copy+remove.
Remove a single file. Use fs_rm_rf_async/3 for directory trees.
Async recursive remove. Runs on the Tokio blocking pool; sends
{:tokio_complete, correlation_id, :ok} or
{:tokio_complete, correlation_id, :error, {kind, msg}} to the
caller on completion. Idempotent: removing a non-existent path sends
:ok.
Creates an empty file if it does not exist. Idempotent on an existing
file (does not truncate). Equivalent to File.touch!/1 without the
timestamp update (matches our callers' usage).
@spec io_uring_available() :: boolean()
@spec lmdb_clear(binary(), non_neg_integer()) :: :ok | {:error, term()}
@spec lmdb_composite_range_entries_bounded( binary(), binary(), binary(), binary(), pos_integer(), pos_integer(), non_neg_integer() ) :: {:ok, [ {binary(), binary(), binary(), non_neg_integer(), non_neg_integer(), pos_integer(), binary() | nil} ], boolean(), non_neg_integer()} | {:error, term()}
@spec lmdb_delete(binary(), binary(), non_neg_integer()) :: :ok | {:error, term()}
@spec lmdb_get(binary(), binary(), non_neg_integer()) :: {:ok, binary()} | :not_found | {:error, term()}
@spec lmdb_get_many(binary(), [binary()], non_neg_integer()) :: {:ok, [{:ok, binary()} | :not_found]} | {:error, term()}
@spec lmdb_get_many_bounded(binary(), [binary()], pos_integer(), non_neg_integer()) :: {:ok, [{:ok, binary()} | :not_found], non_neg_integer()} | {:error, term()}
@spec lmdb_get_many_prefix_bounded( binary(), [binary()], pos_integer(), non_neg_integer() ) :: {:ok, [{:ok, binary()} | :not_found], non_neg_integer(), boolean()} | {:error, term()}
@spec lmdb_prefix_count(binary(), binary(), non_neg_integer()) :: {:ok, non_neg_integer()} | {:error, term()}
@spec lmdb_prefix_entries(binary(), binary(), non_neg_integer(), non_neg_integer()) :: {:ok, [{binary(), binary()}]} | {:error, term()}
@spec lmdb_prefix_entries_after( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, [{binary(), binary()}]} | {:error, term()}
@spec lmdb_prefix_entries_after_bounded( binary(), binary(), binary(), non_neg_integer(), non_neg_integer(), non_neg_integer() ) :: {:ok, [{binary(), binary()}]} | {:error, term()}
@spec lmdb_prefix_entries_reverse( binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, [{binary(), binary()}]} | {:error, term()}
@spec lmdb_prefix_entries_reverse_before( binary(), binary(), binary(), non_neg_integer(), non_neg_integer() ) :: {:ok, [{binary(), binary()}]} | {:error, term()}
@spec lmdb_prefix_keys_after_bounded( binary(), binary(), binary(), non_neg_integer(), non_neg_integer(), non_neg_integer() ) :: {:ok, [binary()]} | {:error, term()}
@spec lmdb_prefix_merge_entries( [binary()], binary(), non_neg_integer(), pos_integer(), non_neg_integer() ) :: {:ok, [{non_neg_integer(), binary(), binary()}], non_neg_integer()} | {:error, term()}
@spec lmdb_put(binary(), binary(), binary(), non_neg_integer()) :: :ok | {:error, term()}
@spec lmdb_range_entries_bounded( binary(), binary(), binary(), binary(), pos_integer(), pos_integer(), non_neg_integer() ) :: {:ok, [{binary(), binary()}], boolean(), non_neg_integer()} | {:error, term()}
@spec lmdb_release(binary()) :: {:ok, non_neg_integer()} | {:busy, non_neg_integer()} | {:error, term()}
@spec lmdb_release_all() :: {:ok, non_neg_integer()} | {:busy, non_neg_integer()} | {:error, term()}
@spec lmdb_write_batch(binary(), [lmdb_op()], non_neg_integer()) :: :ok | {:error, term()}
@spec lmdb_write_batch_with_originals(binary(), [lmdb_op()], non_neg_integer()) :: {:ok, [lmdb_original()]} | {:error, term()}
@spec rust_allocated_bytes() :: {:ok, non_neg_integer()} | {:error, term()}
@spec topk_file_add_v2_at( binary(), binary(), [binary()], non_neg_integer(), pos_integer() ) :: [binary() | nil] | {:error, term()}
@spec topk_file_count_v2(binary(), [binary()]) :: {:ok, [non_neg_integer()]} | {:error, term()}
@spec topk_file_create_v2( binary(), non_neg_integer(), non_neg_integer(), non_neg_integer() ) :: :ok | {:error, term()}
@spec topk_file_incrby_v2(binary(), [{binary(), non_neg_integer()}]) :: [binary() | nil] | {:error, term()}
@spec topk_file_incrby_v2_at( binary(), binary(), [{binary(), non_neg_integer()}], non_neg_integer(), pos_integer() ) :: [binary() | nil] | {:error, term()}
@spec topk_file_info_v2(binary()) :: {pos_integer(), pos_integer(), pos_integer()} | {:error, term()}
@spec topk_file_list_v2(binary()) :: {:ok, [{binary(), non_neg_integer()}]} | {:error, term()}
@spec topk_file_list_with_count(binary()) :: [binary() | non_neg_integer()] | {:error, term()}
@spec v2_append_batch(binary(), [{binary(), binary(), non_neg_integer()}]) :: {:ok, [{non_neg_integer(), non_neg_integer()}]} | {:error, term()}
@spec v2_append_batch_nosync(binary(), [{binary(), binary(), non_neg_integer()}]) :: {:ok, [{non_neg_integer(), non_neg_integer()}]} | {:error, term()}
@spec v2_append_ops_batch(binary(), [append_op()]) :: {:ok, [append_op_location()]} | {:error, term()}
@spec v2_append_ops_batch_nosync(binary(), [append_op()]) :: {:ok, [append_op_location()]} | {:error, term()}
@spec v2_append_record(binary(), binary(), binary(), non_neg_integer()) :: {:ok, {non_neg_integer(), non_neg_integer()}} | {:error, term()}
@spec v2_append_tombstone(binary(), binary()) :: {:ok, {non_neg_integer(), non_neg_integer()}} | {:error, term()}
@spec v2_available_disk_space(binary()) :: {:ok, non_neg_integer()} | {:error, term()}
@spec v2_build_hint_file_from_log(binary(), binary(), non_neg_integer()) :: {:ok, non_neg_integer(), non_neg_integer()} | {:error, term()}
@spec v2_copy_records(binary(), binary(), [non_neg_integer()]) :: {:ok, [{non_neg_integer(), non_neg_integer()}]} | {:error, term()}
@spec v2_copy_records_preserve_tombstones(binary(), binary(), [non_neg_integer()], [ non_neg_integer() ]) :: {:ok, [{non_neg_integer(), non_neg_integer()}]} | {:error, term()}
Fsyncs a directory so that recent File.rename/2, File.rm/1,
File.touch!/1, or File.create/1 operations on files inside it are
durable. Use after any namespace mutation that must survive a kernel
panic — rotation, compaction rename, hint-file creation, prob-file
create/delete, shard init.
Returns :ok on success or {:error, reason} where reason is a
short string suitable for logging.
POSIX: file-data fsync does NOT make the filename durable; only a directory fsync does.
@spec v2_pread_at(binary(), non_neg_integer()) :: {:ok, binary()} | {:error, term()}
@spec v2_pread_at_async(pid(), term(), binary(), non_neg_integer()) :: :ok | {:error, term()}
@spec v2_pread_batch(binary(), [non_neg_integer()]) :: {:ok, [binary() | nil]} | {:error, term()}
@spec v2_pread_batch_async(pid(), term(), [{binary(), non_neg_integer()}]) :: :ok | {:error, term()}
@spec v2_pread_batch_grouped_async( pid(), term(), [{binary(), [{non_neg_integer(), non_neg_integer()}]}] ) :: :ok | {:error, term()}
@spec v2_pread_batch_grouped_key_async( pid(), term(), [{binary(), [{non_neg_integer(), non_neg_integer(), binary()}]}] ) :: :ok | {:error, term()}
@spec v2_pread_batch_path_async(pid(), term(), binary(), [non_neg_integer()]) :: :ok | {:error, term()}
@spec v2_read_hint_file_page( binary(), non_neg_integer(), pos_integer(), pos_integer() ) :: {:ok, [ {binary(), non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer()} ], non_neg_integer(), boolean()} | {:error, term()}
@spec v2_scan_file_page(binary(), non_neg_integer(), pos_integer()) :: {:ok, [ {binary(), non_neg_integer(), non_neg_integer(), non_neg_integer(), boolean()} ], non_neg_integer(), boolean()} | {:error, term()}
@spec v2_scan_tombstones_page(binary(), non_neg_integer(), non_neg_integer()) :: {:ok, [{binary(), non_neg_integer(), non_neg_integer(), non_neg_integer()}], non_neg_integer(), boolean()} | {:error, term()}
Strictly scans at most max_records physical log records for tombstones.
The returned cursor points to the next physical record. done is true only
when that cursor reaches the file length captured when the page was opened.
@spec v2_validate_value_ref(binary(), non_neg_integer(), binary(), non_neg_integer()) :: {:ok, {non_neg_integer(), non_neg_integer()}} | :mismatch | {:error, term()}
@spec v2_write_hint_file(binary(), [ {binary(), non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer()} ]) :: :ok | {:error, term()}