An open B+-tree. Pure data plus the open unit — the comparator and
its context are stateless and supplied per call, so a handle can be
closed and reopened freely and carries nothing un-persistable.
A forward cursor over entries in ascending (key,payload) order.
Obtained from bt_first (whole tree) or bt_seek (lower bound on a
key); advanced and read with bt_next.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public, | parameter | :: | BT_OK | = | 0 |
Success |
| integer, | public, | parameter | :: | BT_ERR | = | 1 |
I/O / filesystem failure |
| integer, | public, | parameter | :: | BT_CORRUPT | = | 2 |
Corrupt on-disk metadata |
| integer, | public, | parameter | :: | BT_VERSION | = | 3 |
Unsupported on-disk format On-disk format version of the paged file. Bumped 1->2 when the page geometry was widened to provision the transient over-full node a split builds in place (child area MAXK+2, sep area MAXK+1). Bumped 2->3 when a byte-order mark was added to the meta page (so a tree written on a different-endian host is rejected, not silently misread). Earlier versions use the old offsets and are rejected with BT_VERSION; an index is derived data, so rebuild it. |
| integer, | public, | parameter | :: | BT_FORMAT_VERSION | = | 3 |
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(out) | :: | bt |
Tree handle (overwritten) |
||
| character(len=*), | intent(in) | :: | path |
Paged-file path |
||
| integer, | intent(in) | :: | key_len |
Fixed key length in bytes |
||
| logical, | intent(in) | :: | writable |
Open read-write |
||
| logical, | intent(in) | :: | create |
Truncate + initialise empty |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Tree handle |
||
| integer, | intent(out), | optional | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Open tree handle, re-synced in place |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(in) | :: | bt |
Open tree handle |
||
| integer, | intent(out), | optional | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Tree handle |
||
| character(len=*), | intent(in) | :: | key |
Key bytes ( |
||
| integer(kind=int32), | intent(in) | :: | payload |
Associated payload |
||
| procedure(bt_compare) | :: | cmp |
Key order |
|||
| class(*), | intent(in) | :: | ctx |
Opaque comparator context |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Tree handle |
||
| character(len=*), | intent(in) | :: | key |
Key bytes ( |
||
| integer(kind=int32), | intent(in) | :: | payload |
Payload identifying the entry |
||
| procedure(bt_compare) | :: | cmp |
Key order |
|||
| class(*), | intent(in) | :: | ctx |
Opaque comparator context |
||
| logical, | intent(out) | :: | found |
|
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Tree handle |
||
| character(len=*), | intent(in) | :: | keys(:) |
Keys (each |
||
| integer(kind=int32), | intent(in) | :: | payloads(:) |
Payload per key |
||
| procedure(bt_compare) | :: | cmp |
Key order |
|||
| class(*), | intent(in) | :: | ctx |
Opaque comparator context |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(in) | :: | bt |
Tree handle |
||
| character(len=*), | intent(in) | :: | key |
Lower-bound key ( |
||
| procedure(bt_compare) | :: | cmp |
Key order |
|||
| class(*), | intent(in) | :: | ctx |
Opaque comparator context |
||
| type(bt_cursor_t), | intent(out) | :: | cur |
Positioned cursor |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(in) | :: | bt |
Tree handle |
||
| type(bt_cursor_t), | intent(out) | :: | cur |
Positioned cursor |
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(in) | :: | bt |
Tree handle |
||
| type(bt_cursor_t), | intent(inout) | :: | cur |
Cursor (advanced) |
||
| character(len=*), | intent(out) | :: | key |
Receives the key (must be exactly |
||
| integer(kind=int32), | intent(out) | :: | payload |
Receives the payload |
||
| logical, | intent(out) | :: | ok |
|
||
| integer, | intent(out) | :: | stat |
|
Open an existing tree (create=.false.) or create a fresh empty
one (create=.true., file truncated). writable=.false. opens
read-only. On a non-create open key_len must match the value
stored in the file or BT_CORRUPT is returned.
Flush the meta page (read-write opens) and close the unit. Safe
to call on an already-closed handle.
Re-read the mutable meta fields (root, free_head, npages,
first_leaf, nentries) from the on-disk meta page into the open
handle, discarding the cached in-memory copies. This re-syncs a
tree whose file was changed underneath it — specifically after a
journal rollback restores the meta page, the cached fields are
stale and must be reloaded before the tree is touched again. The
unit stays open; page_size/key_len are immutable and a mismatch
(or a failed geometry self-check) is reported as BT_CORRUPT.
Push a writable tree's buffered page writes out to the operating
system so a subsequent fsync of the file makes them durable. Every
mutator already writes the meta page last, so the on-disk image is
coherent; this only drains the open unit's buffer and performs no
fsync itself (the journal layer owns durability, by path). A no-op
on a closed or read-only handle.
Insert (key, payload). Duplicate keys are allowed; the pair
is ordered by key then payload so the entry is uniquely
addressable for bt_remove.
Remove the entry matching (key, payload) exactly. found
is .false. (with stat == BT_OK) if no such entry exists.
Lazy: an emptied leaf is left in place, not merged.
Rebuild the whole tree from keys/payloads: sort (key,payload)
then write perfectly-packed leaves and the internal levels
bottom-up. O(N log N) — the proper replacement for per-row
reinsertion. keys is a rank-1 array of key_len byte strings,
payloads(i) the payload for keys(i).
Note: this resets the logical page count and rewrites from page 2,
but does NOT shrink the underlying file — pages above the new high
water remain allocated on disk (harmless; never read). To actually
reclaim space (e.g. repacking after many lazy deletes), recreate the
file with bt_open(create=.true.) and load into the fresh tree.
Position cur at the first entry whose key is not ordered
before key (lower bound). Callers iterate with bt_next and
stop themselves once the yielded key compares greater.
Position cur at the leftmost entry (whole-tree ascending
iteration). The cursor is exhausted immediately for an empty
tree.
Yield the entry at the cursor and advance. ok is .false.
when the cursor is exhausted (no entry returned).
key must be exactly key_len bytes: only key(1:key_len) is
assigned, so a longer buffer keeps undefined trailing bytes.
Install (or, called with no hook, remove) the pre-write journal
hook on an open writable tree. Installing records the current page
high-water as the new-page boundary for the transaction about to
run; clearing it returns the tree to un-journalled writes. ctx
must be supplied whenever hook is, and must out-live the tree.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(btree_t), | intent(inout) | :: | bt |
Tree handle |
||
| procedure(bt_journal_hook), | optional | :: | hook |
Hook (absent = clear) |
||
| class(*), | intent(in), | optional, | pointer | :: | ctx |
Opaque hook context |
Optional pre-write journal hook. Invoked by every page write
before the page is overwritten, so a transaction layer can
capture an undo image. offset is the page's 1-based byte
position in the file. For an in-place overwrite is_new is
.false. and old_bytes is the page's current page_size-byte
pre-image; for a freshly allocated page is_new is .true.,
old_bytes is empty, and the layer should record the file's
pre-growth length instead. A non-zero stat aborts the write,
so a journalling failure never lets an un-recorded overwrite
through. ctx is the caller's opaque context, threaded
unchanged.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(*), | intent(in) | :: | ctx |
Opaque caller context |
||
| integer(kind=int64), | intent(in) | :: | offset |
1-based byte position of the page |
||
| character(len=*), | intent(in) | :: | old_bytes |
Page pre-image (empty if |
||
| logical, | intent(in) | :: | is_new |
Page is newly allocated this txn |
||
| integer, | intent(out) | :: | stat |
|
Total order on keys. Returns <0, 0, >0 for a ordering
before / equal to / after b. Must be pure; a and b are
exactly key_len bytes. ctx is the caller's opaque context,
threaded through every comparison unchanged.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| character(len=*), | intent(in) | :: | a | |||
| character(len=*), | intent(in) | :: | b | |||
| class(*), | intent(in) | :: | ctx |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public | :: | unit | = | -1 |
Open Fortran unit, -1 if closed |
|
| integer, | public | :: | page_size | = | 0 |
Bytes per page (derived from |
|
| integer, | public | :: | key_len | = | 0 |
Fixed key length in bytes |
|
| integer, | public | :: | root | = | 0 |
Root page id |
|
| integer, | public | :: | free_head | = | 0 |
Head of the free-page list (0 = none) |
|
| integer, | public | :: | npages | = | 0 |
Highest page id ever allocated |
|
| integer, | public | :: | first_leaf | = | 0 |
Leftmost leaf page id (iteration start) |
|
| integer(kind=int64), | public | :: | nentries | = | 0_int64 |
Number of live |
|
| logical, | public | :: | writable | = | .false. |
Opened read-write ( |
|
| procedure(bt_journal_hook), | public, | pointer, nopass | :: | jhook | => | null() |
Pre-write undo hook |
| class(*), | public, | pointer | :: | jctx | => | null() |
Hook context |
| integer, | public | :: | jbase | = | 0 |
Page high-water when the hook was installed |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | public | :: | leaf | = | 0 |
Current leaf page id (0 = exhausted) |
|
| integer, | public | :: | slot | = | 0 |
0-based index of the next entry to yield |
|
| logical, | public | :: | valid | = | .false. |
|