40# ifndef TPL_FILE_BPLUS_TREE_H
41# define TPL_FILE_BPLUS_TREE_H
51# include <type_traits>
151 template <
typename Key,
158 static_assert(
MinDegree >= 2,
"File_BPlus_Tree requires MinDegree >= 2");
159 static_assert(std::default_initializable<Key>,
160 "File_BPlus_Tree requires default-initializable keys");
161 static_assert(std::copy_constructible<Key>
and std::is_copy_assignable_v<Key>,
162 "File_BPlus_Tree requires copyable keys");
164 "File_BPlus_Tree requires a fixed-size key codec");
165 static_assert(std::same_as<
decltype(Codec::decode(
166 static_cast<const unsigned char *
>(
nullptr))),
168 "File_BPlus_Tree codec must decode back to Key");
180 static_cast<std::uint32_t
>(Codec::encoded_size);
183 std::endian::native == std::endian::little ? 1 : 2;
246 return "File_BPlus_Tree";
265 <<
"(): file was opened in read-only mode";
292 +
sizeof(std::uint64_t) * 6 +
sizeof(std::uint8_t) + 7;
307 return sizeof(std::uint8_t) +
sizeof(std::uint16_t) * 2 + 3
325 return sizeof(std::uint8_t) +
sizeof(std::uint16_t) * 2 + 3
326 +
sizeof(
page_id_t) +
sizeof(std::uint64_t)
327 + Codec::encoded_size *
MaxKeys
337 const std::uint32_t version)
noexcept
345 const std::uint32_t version)
noexcept
354 const std::uint32_t version)
noexcept
360 const std::uint32_t version)
noexcept
368 const std::uint32_t version)
noexcept
372 :
static_cast<std::uint32_t
>(
sizeof(Key));
375 [[
nodiscard]]
static constexpr std::array<char, 7>
381 const auto codec_id = Codec::storage_id;
393 page.
kind =
static_cast<std::uint8_t
>(kind);
399 const std::uint32_t version)
401 if constexpr (
not std::is_trivially_copyable_v<Key>)
404 <<
" uses legacy native format version " << version
405 <<
", which requires trivially copyable keys; reopen or rewrite it "
414 if constexpr (
not std::is_trivially_copyable_v<Key>)
417 <<
" uses legacy native format version " <<
wal_version
418 <<
", which requires trivially copyable keys; recover it with a "
419 <<
"trivially copyable instantiation or discard the stale WAL";
454 namespace fs = std::filesystem;
457 if (
not path.has_parent_path())
461 (
void) fs::create_directories(path.parent_path(),
ec);
463 <<
"File_BPlus_Tree: cannot create directory "
464 << path.parent_path().string() <<
" for " <<
file_path_
465 <<
" (" <<
ec.message() <<
")";
481 std::ofstream create(
file_path_, std::ios::binary | std::ios::trunc);
483 <<
"File_BPlus_Tree: cannot create " <<
file_path_;
487 ? (std::ios::binary | std::ios::in)
488 : (std::ios::binary | std::ios::in | std::ios::out);
491 <<
"File_BPlus_Tree: cannot open " <<
file_path_;
503 template <
typename T>
509 out.write(
reinterpret_cast<const char *
>(&value),
sizeof(value));
511 <<
"File_BPlus_Tree: cannot write " <<
what <<
" to " <<
file_path;
514 template <
typename T>
520 in.read(
reinterpret_cast<char *
>(&value),
sizeof(value));
522 <<
"File_BPlus_Tree: cannot read " <<
what <<
" from " <<
file_path;
531 if constexpr (std::is_trivially_copyable_v<Key>)
533 const auto bytes = std::bit_cast<std::array<
char,
sizeof(Key)>>(key);
534 out.write(bytes.data(), bytes.size());
536 <<
"File_BPlus_Tree: cannot write " <<
what <<
" to "
541 <<
"File_BPlus_Tree: cannot write legacy native " <<
what <<
" to "
542 <<
file_path <<
" because legacy native formats require trivially "
551 std::array<unsigned char, Codec::encoded_size> bytes = {};
552 Codec::encode(key, bytes.data());
553 out.write(
reinterpret_cast<const char *
>(bytes.data()), bytes.size());
555 <<
"File_BPlus_Tree: cannot write " <<
what <<
" to " <<
file_path;
570 if constexpr (std::is_trivially_copyable_v<Key>)
572 std::array<
char,
sizeof(Key)> bytes = {};
573 in.read(bytes.data(), bytes.size());
575 <<
"File_BPlus_Tree: cannot read " <<
what <<
" from "
577 return std::bit_cast<Key>(bytes);
582 <<
"File_BPlus_Tree: cannot read legacy native " <<
what
584 <<
" because legacy native formats require trivially copyable "
594 std::array<unsigned char, Codec::encoded_size> bytes = {};
595 in.read(
reinterpret_cast<char *
>(bytes.data()), bytes.size());
597 <<
"File_BPlus_Tree: cannot read " <<
what <<
" from " <<
file_path;
598 return Codec::decode(bytes.data());
604 const std::uint32_t version)
612 const std::uint32_t
crc,
615 return Codec::add_to_crc(
crc, key);
619 const std::uint32_t
crc,
622 if constexpr (std::is_trivially_copyable_v<Key>)
627 <<
"File_BPlus_Tree: cannot checksum legacy native keys because "
628 <<
"legacy native formats require trivially copyable keys";
634 const std::uint32_t version,
635 const std::uint64_t
size,
657 const std::uint32_t version,
658 const std::uint64_t
size,
684 const std::array<char, 3>
padding = {};
691 for (
size_t i = 0; i <
MaxKeys; ++i)
700 const std::array<char, 3>
padding = {};
708 for (
size_t i = 0; i <
MaxKeys; ++i)
717 const std::array<char, 3>
padding = {};
725 for (
size_t i = 0; i <
MaxKeys; ++i)
736 const std::array<char, 3>
padding = {};
745 for (
size_t i = 0; i <
MaxKeys; ++i)
757 const std::array<char, 3>
padding = {};
766 for (
size_t i = 0; i <
MaxKeys; ++i)
778 const std::array<char, 3>
padding = {};
786 for (
size_t i = 0; i <
MaxKeys; ++i)
801 const std::array<char, 3>
padding = {};
804 <<
"File_BPlus_Tree: cannot write page padding to " <<
target_path;
808 "page checkpoint sequence");
810 for (
size_t i = 0; i <
MaxKeys; ++i)
824 <<
"File_BPlus_Tree: cannot seek for writing in " <<
file_path_;
842 file_.write(magic.data(), magic.size());
844 <<
"File_BPlus_Tree: cannot write magic to " <<
file_path_;
852 "header minimum degree");
857 <<
"File_BPlus_Tree: cannot write reserved header bytes to "
865 "header checkpoint sequence");
877 static_cast<std::uint64_t
>(
pages_.size() - 1),
900 +
sizeof(std::uint64_t) * 8 +
sizeof(std::uint8_t) + 7;
903 [[
nodiscard]]
static constexpr std::uint32_t
920 const std::uint64_t
size,
951 +
sizeof(std::uint64_t) * 2 +
sizeof(std::uint32_t);
957 std::ofstream
out(
target_path, std::ios::binary | std::ios::trunc);
959 <<
"File_BPlus_Tree: cannot open " <<
target_path <<
" for writing";
962 out.write(magic.data(), magic.size());
964 <<
"File_BPlus_Tree: cannot write WAL magic to " <<
target_path;
967 const auto size =
static_cast<std::uint64_t
>(
size_);
976 "WAL minimum degree");
981 <<
"File_BPlus_Tree: cannot write WAL reserved bytes to " <<
target_path;
988 "WAL checkpoint sequence");
1008 <<
"File_BPlus_Tree: cannot write WAL commit trailer to "
1011 "WAL trailer checkpoint sequence");
1014 "WAL payload checksum");
1018 <<
"File_BPlus_Tree: cannot flush " <<
target_path;
1021 <<
"File_BPlus_Tree: cannot close " <<
target_path;
1028 const std::string & path,
1029 const std::uint32_t version)
1036 std::array<char, 3>
padding = {};
1039 <<
"File_BPlus_Tree: cannot read page padding from " << path;
1047 for (
size_t i = 0; i <
MaxKeys; ++i)
1062 <<
"File_BPlus_Tree: page checksum mismatch in " << path;
1073 out.write(magic.data(), magic.size());
1075 <<
"File_BPlus_Tree: cannot write magic to " <<
target_path;
1078 const auto size =
static_cast<std::uint64_t
>(
size_);
1085 "header minimum degree");
1090 <<
"File_BPlus_Tree: cannot write reserved header bytes to "
1098 "header checkpoint sequence");
1112 namespace fs = std::filesystem;
1114 if (path.has_parent_path())
1117 (
void) fs::create_directories(path.parent_path(),
ec);
1119 <<
"File_BPlus_Tree: cannot create directory "
1120 << path.parent_path().string() <<
" for " <<
target_path
1121 <<
" (" <<
ec.message() <<
")";
1124 std::ofstream
out(
target_path, std::ios::binary | std::ios::trunc);
1126 <<
"File_BPlus_Tree: cannot open " <<
target_path <<
" for writing";
1131 <<
"File_BPlus_Tree: cannot flush " <<
target_path;
1134 <<
"File_BPlus_Tree: cannot close " <<
target_path;
1144 if (
file_.is_open())
1164 <<
"File_BPlus_Tree: cannot flush " <<
file_path_;
1172 namespace fs = std::filesystem;
1177 <<
"File_BPlus_Tree: cannot open read-only while WAL recovery "
1178 <<
"sidecars are pending for " <<
file_path_;
1188 <<
"File_BPlus_Tree: cannot open WAL " <<
wal_path_ <<
" for reading";
1191 std::array<char, detail::Ordered_Tree_Snapshot_Magic_Size> magic = {};
1192 in.read(magic.data(), magic.size());
1194 <<
"File_BPlus_Tree: cannot read WAL magic from " <<
wal_path_;
1196 <<
"File_BPlus_Tree: incompatible WAL file " <<
wal_path_;
1203 <<
"File_BPlus_Tree: unsupported WAL version " <<
wal_version
1212 <<
"File_BPlus_Tree: WAL " <<
wal_path_ <<
" was created for key size "
1213 << key_size <<
", but this instantiation expects "
1216 const auto min_degree =
1220 <<
" was created with minimum degree " << min_degree
1221 <<
", but this instantiation expects " <<
MinDegree;
1228 <<
" was created with an incompatible encoding";
1233 <<
"File_BPlus_Tree: cannot read WAL reserved bytes from " <<
wal_path_;
1238 <<
" was created with an incompatible key codec";
1261 <<
"File_BPlus_Tree: WAL checksum mismatch in " <<
wal_path_;
1266 <<
"File_BPlus_Tree: cannot determine the size of WAL " <<
wal_path_
1267 <<
" (" <<
ec.message() <<
")";
1273 <<
"File_BPlus_Tree: WAL size mismatch in " <<
wal_path_
1274 <<
" (expected " << expected_size <<
", got " <<
actual_size <<
")";
1276 if (
file_.is_open())
1290 <<
"File_BPlus_Tree: invalid WAL page id " << page_id
1309 std::array<char, detail::Ordered_Tree_Snapshot_Magic_Size>
1313 <<
"File_BPlus_Tree: cannot read WAL commit trailer from "
1316 <<
"File_BPlus_Tree: missing WAL commit trailer in "
1321 "WAL trailer checkpoint sequence");
1329 <<
"File_BPlus_Tree: WAL trailer checkpoint mismatch in "
1332 <<
"File_BPlus_Tree: WAL trailer dirty-count mismatch in "
1336 <<
"File_BPlus_Tree: WAL payload checksum mismatch in "
1379 <<
"File_BPlus_Tree: cannot flush recovered data to " <<
file_path_;
1388 namespace fs = std::filesystem;
1394 <<
"File_BPlus_Tree: cannot open read-only while journal recovery "
1395 <<
"sidecars are pending for " <<
file_path_;
1405 if (
file_.is_open())
1414 namespace fs = std::filesystem;
1418 <<
"File_BPlus_Tree: cannot open " <<
source_path <<
" for reading";
1421 std::array<char, detail::Ordered_Tree_Snapshot_Magic_Size> magic = {};
1422 in.read(magic.data(), magic.size());
1424 <<
"File_BPlus_Tree: cannot read header magic from " <<
source_path;
1428 <<
" does not contain a compatible paged B+ Tree";
1430 const auto version =
1437 <<
"File_BPlus_Tree: unsupported format version " << version
1442 const auto key_size =
1445 <<
"File_BPlus_Tree: file " <<
source_path <<
" was created for key size "
1446 << key_size <<
", but this instantiation expects "
1449 const auto min_degree =
1453 <<
" was created with minimum degree " << min_degree
1454 <<
", but this instantiation expects " <<
MinDegree;
1460 <<
" was created with an incompatible encoding";
1465 <<
"File_BPlus_Tree: cannot read reserved header bytes from "
1469 <<
" was created with an incompatible key codec";
1475 image.first_leaf_page =
1479 image.free_page_head =
1484 image.checkpoint_sequence =
1486 "header checkpoint sequence");
1491 static_cast<std::uint64_t
>(
image.size),
1494 image.checkpoint_sequence))
1495 <<
"File_BPlus_Tree: header checksum mismatch in " <<
source_path;
1502 version,
static_cast<std::uint64_t
>(
image.size),
1505 <<
"File_BPlus_Tree: header checksum mismatch in " <<
source_path;
1511 <<
"File_BPlus_Tree: cannot determine the size of " <<
source_path
1512 <<
" (" <<
ec.message() <<
")";
1513 const auto expected_size =
1516 <<
"File_BPlus_Tree: file size mismatch in " <<
source_path
1517 <<
" (expected " << expected_size <<
", got " <<
actual_size <<
")";
1519 image.pages.empty();
1526 <<
"File_BPlus_Tree: invalid root page id in " <<
source_path;
1528 <<
"File_BPlus_Tree: invalid first leaf id in " <<
source_path;
1530 <<
"File_BPlus_Tree: invalid free-list head in " <<
source_path;
1549 for (
size_t i = 0; i <
pages_.size(); ++i)
1554 <<
"File_BPlus_Tree: structural verification failed for " <<
file_path_;
1568 return std::ifstream(
file_path_, std::ios::binary).good();
1576 return std::nullopt;
1580 return std::nullopt;
1582 std::array<char, detail::Ordered_Tree_Snapshot_Magic_Size> magic = {};
1583 in.read(magic.data(), magic.size());
1585 return std::nullopt;
1591 return std::nullopt;
1599 return std::nullopt;
1605 file_.seekg(0, std::ios::end);
1607 return std::nullopt;
1614 return std::nullopt;
1619 return std::nullopt;
1628 return std::nullopt;
1671 <<
"File_BPlus_Tree: invalid page id " << page_id;
1678 <<
"File_BPlus_Tree: invalid page id " << page_id;
1699 const Key & key)
const
1708 const Key & key)
const
1769 return pages_.size() - 1;
1789 <<
"File_BPlus_Tree: invalid subtree minimum request";
1800 <<
"File_BPlus_Tree: internal page without children";
1951 for (
size_t i = 0; i < right.
key_count; ++i)
1993 if (idx + 1 <
page(parent_id).child_count
2000 if (idx + 1 <
page(parent_id).child_count)
2040 std::optional<Key> prev;
2044 if (++steps >
pages_.size())
2051 for (
size_t i = 0; i < leaf.
key_count; ++i)
2055 prev = leaf.
keys[i];
2075 const std::optional<Key> &
min_key,
2076 const std::optional<Key> &
max_key,
2078 size_t & leaf_depth,
2109 if (leaf_depth ==
static_cast<size_t>(-1))
2111 return leaf_depth == depth;
2132 depth + 1, leaf_depth,
counted))
2172 if (
idx_ >= leaf.key_count)
2215 <<
"File_BPlus_Tree::Iterator(): invalid range ["
2216 << first <<
", " << last <<
"]";
2240 <<
"File_BPlus_Tree::Iterator::get_curr(): no current key";
2251 <<
"File_BPlus_Tree::Iterator::next_ne(): no current key";
2295 const Compare &
cmp = Compare())
2315 const Compare &
cmp = Compare())
2323 <<
"File_BPlus_Tree requires a non-empty file path";
2329 <<
"File_BPlus_Tree: cannot open missing file " <<
file_path_
2330 <<
" in read-only mode";
2336 file_.seekg(0, std::ios::end);
2339 <<
"File_BPlus_Tree: cannot determine the size of " <<
file_path_;
2364 const Compare &
cmp = Compare())
2384 const Compare &
cmp = Compare())
2406 if (
file_.is_open())
2498 return pages_.size() - 1;
2556 <<
"File_BPlus_Tree: backing file " <<
file_path_ <<
" no longer exists";
2684 Key
copy = std::move(key);
2732 return std::nullopt;
2743 return std::nullopt;
2757 return std::nullopt;
2764 return leaf.
keys[idx];
2769 return std::nullopt;
2781 return std::nullopt;
2788 return leaf.
keys[idx];
2793 return std::nullopt;
2814 return Iterator(*
this, first, last);
2830 out.append(it.get_curr());
2845 out.append(it.get_curr());
2865 size_t leaf_depth =
static_cast<size_t>(-1);
2875 template <
typename Key,
C++20 concepts for constraining comparison functors.
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
#define ah_runtime_error()
Throws std::runtime_error unconditionally.
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
#define ah_invalid_argument_if(C)
Throws std::invalid_argument if condition holds.
Standard functor implementations and comparison objects.
Simple dynamic array with automatic resizing and functional operations.
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
void empty() noexcept
Empties the container.
T & append(const T &data)
Append a copy of data
void reserve(size_t cap)
Reserves cap cells into the array.
Lazy iterator over ordered keys stored in leaf pages.
void next_ne()
Advance to the next key.
Iterator(const tree_type &tree, const Key &first, const Key &last)
Construct an iterator over the inclusive range [first, last].
void next()
Synonym for next_ne().
bool has_curr() const noexcept
Return whether the iterator still points to a key.
std::optional< Key > last_
const Key & get_curr() const
Return the current key.
const Key * operator->() const
Member-access shorthand for the current key.
Iterator() noexcept=default
Construct an empty iterator.
const Key & operator*() const
Dereference the iterator.
Persistent page-managed B+ Tree stored in a single binary file.
static void erase_child_at(Page &page, const size_t idx)
void write_current_page_to_storage(const page_id_t page_id, const Page &page) const
std::streamoff current_page_offset(const page_id_t page_id) const noexcept
static void write_pod(std::ostream &out, const T &value, const std::string &file_path, const char *what)
const Compare & key_comp() const noexcept
Return the comparison object.
static void insert_key_at(Page &page, const size_t idx, const Key &key)
static constexpr size_t MaxChildren
static std::uint32_t header_checksum_v2(const std::uint32_t version, const std::uint64_t size, const page_id_t root_page, const page_id_t first_leaf_page, const std::uint64_t page_count, const page_id_t free_page_head) noexcept
page_id_t free_page_head_
std::string journal_path_
static constexpr size_t page_bytes() noexcept
static constexpr bool is_internal(const Page &page) noexcept
void apply_current_cache_to_storage(const std::uint64_t checkpoint_sequence) const
size_t child_index(const Page &page, const Key &key) const
bool is_read_only() const noexcept
Return whether this handle is read-only.
void mark_page_dirty(const page_id_t page_id)
bool insert(const Key &key)
Insert a key if it is not already present.
static constexpr size_t serialized_header_bytes(const std::uint32_t version) noexcept
Page & page(const page_id_t page_id)
static void ensure_legacy_native_format_supported(const std::string &source_path, const std::uint32_t version)
void insert_nonfull(const page_id_t page_id, const Key &key)
static Page read_page_from_stream(std::istream &in, const std::string &path, const std::uint32_t version)
void seekp_to(const std::streamoff offset) const
Gen_File_BPlus_Tree(Gen_File_BPlus_Tree &&)=delete
Moving is disabled.
size_t lower_bound_index(const Page &page, const Key &key) const
void write_wal_to_path(const std::string &target_path, const std::uint64_t checkpoint_sequence) const
page_id_t page_id_type
Type of on-disk page identifiers.
bool empty() const noexcept
Return whether the tree has no keys.
page_id_t rightmost_leaf_page(page_id_t page_id) const
static void ensure_legacy_native_wal_supported(const std::string &source_path, const std::uint32_t wal_version)
static constexpr std::array< char, 7 > reserved_bytes_for_version(const std::uint32_t version) noexcept
static constexpr std::uint32_t WalVersion
Gen_File_BPlus_Tree & operator=(const Gen_File_BPlus_Tree &)=delete
Assignment is disabled.
static void write_key(std::ostream &out, const Key &key, const std::string &file_path, const char *what)
static constexpr size_t wal_trailer_bytes() noexcept
const Page & page(const page_id_t page_id) const
static constexpr size_t checksummed_header_bytes() noexcept
static constexpr size_t checksummed_page_bytes() noexcept
static std::uint32_t wal_header_checksum(const std::uint32_t wal_version, const std::uint64_t size, const page_id_t root_page, const page_id_t first_leaf_page, const std::uint64_t page_count, const page_id_t free_page_head, const std::uint64_t checkpoint_sequence, const std::uint64_t dirty_count) noexcept
bool verify_leaf_chain() const
Key subtree_min(const page_id_t page_id) const
const std::string & file_path() const noexcept
Return the backing file path.
bool strictly_sorted(const Page &page) const
const std::string & get_file_path() const noexcept
Synonym for file_path().
void mark_header_dirty() const noexcept
static std::uint32_t wal_record_checksum_add(std::uint32_t crc, const page_id_t page_id, const Page &page)
static std::uint32_t add_native_key_to_crc(const std::uint32_t crc, const Key &key)
Iterator get_it() const noexcept
Return a lazy iterator over the full key order.
static Key read_native_key(std::istream &in, const std::string &file_path, const char *what)
Paged_File_Open_Mode open_mode() const noexcept
Return the access mode used to open the file.
page_id_t find_leaf_page(const Key &key) const
void release_page(const page_id_t page_id)
static constexpr std::uint32_t ChecksummedFormatVersion
void ensure_parent_dir() const
bool verify_node(const page_id_t page_id, const std::optional< Key > &min_key, const std::optional< Key > &max_key, const size_t depth, size_t &leaf_depth, size_t &counted) const
static constexpr bool is_leaf(const Page &page) noexcept
static constexpr size_t MinKeys
Gen_File_BPlus_Tree(const char *file_path, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a paged persistent B+ Tree file for read-write access.
std::optional< std::uint32_t > storage_format_version_on_disk() const
static std::uint32_t wal_record_checksum_add_v3(std::uint32_t crc, const page_id_t page_id, const Page &page)
static Key read_key(std::istream &in, const std::string &file_path, const char *what, const std::uint32_t version)
static constexpr std::uint32_t wal_record_format_version(const std::uint32_t wal_version) noexcept
static constexpr size_t wal_record_bytes(const std::uint32_t wal_version) noexcept
std::optional< Key > max_key() const
Return the maximum key, if any.
static constexpr std::uint8_t EndianMarker
std::uint64_t checkpoint_sequence() const noexcept
Return the durable checkpoint sequence stored in the backing file.
void borrow_from_next(const page_id_t parent_id, const size_t idx)
std::uint32_t storage_format_version_
static constexpr bool is_free(const Page &page) noexcept
void sync() const
Flush the current tree image using redo WAL or full-image fallback.
static constexpr const char * tree_kind() noexcept
static constexpr std::uint32_t key_size_for_version(const std::uint32_t version) noexcept
bool auto_sync_enabled() const noexcept
Return whether automatic synchronization is enabled.
Loaded_Image read_image(const std::string &source_path) const
static constexpr size_t portable_page_bytes() noexcept
bool verify() const
Verify structural B+ Tree invariants across cached pages.
static constexpr std::uint32_t PortableFormatVersion
static std::uint32_t add_key_to_crc(const std::uint32_t crc, const Key &key)
void clear_dirty_state() const noexcept
page_id_t first_leaf_page_
void write_header_to_storage(const std::uint64_t size, const page_id_t root_page, const page_id_t first_leaf_page, const std::uint64_t page_count, const page_id_t free_page_head, const std::uint64_t checkpoint_sequence) const
Gen_File_BPlus_Tree(std::string file_path, const Paged_File_Open_Mode open_mode, const bool auto_sync=true, const Compare &cmp=Compare())
Open a paged persistent B+ Tree file with an explicit access mode.
static T read_pod(std::istream &in, const std::string &file_path, const char *what)
bool remove(const Key &key)
Remove a key if present.
const Compare & get_compare() const noexcept
Return the comparison object.
static constexpr auto Read_Only
void open_storage(const bool truncate=false) const
Key key_type
Stored key type.
Gen_File_BPlus_Tree(const char *file_path, const Paged_File_Open_Mode open_mode, const bool auto_sync=true, const Compare &cmp=Compare())
Open a paged persistent B+ Tree file with an explicit access mode.
static constexpr size_t legacy_header_bytes() noexcept
static std::uint32_t wal_record_checksum_add_v2(std::uint32_t crc, const page_id_t page_id, const Page &page)
std::uint64_t checkpoint_sequence_
static void write_native_key(std::ostream &out, const Key &key, const std::string &file_path, const char *what)
static constexpr size_t serialized_page_bytes(const std::uint32_t version) noexcept
void reload()
Discard unsynchronized changes and reload pages from disk.
static constexpr auto wal_trailer_magic() noexcept
bool search(const Key &key) const
Synonym for contains().
bool is_empty() const noexcept
Synonym for empty().
Array< unsigned char > dirty_pages_
Gen_File_BPlus_Tree(const Gen_File_BPlus_Tree &)=delete
Copying is disabled.
void clear()
Remove every key from the tree.
void rebuild_separators(const page_id_t page_id)
void write_current_header_to_storage(const std::uint64_t checkpoint_sequence) const
static constexpr std::uint32_t LegacyWalVersion
static std::uint32_t page_checksum_v3(const Page &page)
static std::uint32_t header_checksum(const std::uint32_t version, const std::uint64_t size, const page_id_t root_page, const page_id_t first_leaf_page, const std::uint64_t page_count, const page_id_t free_page_head, const std::uint64_t checkpoint_sequence) noexcept
std::optional< Key > min_key() const
Return the minimum key, if any.
static constexpr bool version_uses_portable_codec(const std::uint32_t version) noexcept
static constexpr std::uint8_t PortableEncodingMarker
static void erase_key_at(Page &page, const size_t idx)
std::string journal_tmp_path_
size_t size() const noexcept
Return the number of stored keys.
void merge_children(const page_id_t parent_id, const size_t left_idx)
page_id_t leftmost_leaf_page(page_id_t page_id) const
Array< Key > range(const Key &first, const Key &last) const
Collect all keys in the inclusive range [first, last].
page_id_t allocate_page(const PageKind kind)
static constexpr size_t header_bytes() noexcept
Paged_File_Open_Mode open_mode_
static std::uint32_t page_checksum_v4(const Page &page)
static constexpr std::uint32_t CommitTrailerWalVersion
bool remove_from(const page_id_t page_id, const Key &key)
static constexpr std::uint32_t PortableWalVersion
static void write_portable_key(std::ostream &out, const Key &key, const std::string &file_path, const char *what)
~Gen_File_BPlus_Tree() noexcept
Close the backing file.
void set_auto_sync(const bool enabled) noexcept
Enable or disable automatic flushing of dirty pages.
detail::Pid_File_Lock lock_
bool read_only() const noexcept
static constexpr std::uint32_t HeaderCheckpointFormatVersion
static constexpr std::uint32_t EncodedKeySize
Gen_File_BPlus_Tree(std::string file_path, const bool auto_sync=true, const Compare &cmp=Compare())
Open or create a paged persistent B+ Tree file for read-write access.
size_t upper_bound_index(const Page &page, const Key &key) const
detail::Pid_File_Lock_Mode lock_mode() const noexcept
static constexpr size_t MaxKeys
size_t dirty_page_count() const noexcept
static constexpr size_t native_page_bytes() noexcept
void split_child(const page_id_t parent_id, const size_t idx)
static constexpr std::uint8_t encoding_marker_for_version(const std::uint32_t version) noexcept
static constexpr auto Read_Write
static constexpr size_t wal_header_bytes() noexcept
static constexpr std::uint32_t NativeWalVersion
std::string wal_tmp_path_
size_t page_count() const noexcept
Return the number of allocated pages currently tracked.
static void write_page_record(std::ostream &out, const Page &page, const std::string &target_path)
void fix_underflow(const page_id_t parent_id, const size_t idx)
void checkpoint() const
Synonym for sync().
Array< Key > keys() const
Materialize the tree contents in sorted order.
static Key read_portable_key(std::istream &in, const std::string &file_path, const char *what)
static constexpr size_t legacy_page_bytes() noexcept
static constexpr auto wal_magic() noexcept
static constexpr std::uint32_t LegacyFormatVersion
void borrow_from_prev(const page_id_t parent_id, const size_t idx)
Iterator get_range_it(const Key &first, const Key &last) const
Return a lazy iterator over an inclusive key range.
bool contains(const Key &key) const
Return whether a key is present.
static constexpr std::uint32_t NativeCheckpointFormatVersion
bool insert(Key &&key)
Insert a key by move if it is not already present.
std::optional< Page > read_storage_page_if_current(const page_id_t page_id) const
std::optional< Key > upper_bound(const Key &key) const
Return the first key strictly greater than key.
void ensure_writable(const char *operation) const
size_t page_size_bytes() const noexcept
Return the fixed serialized page size.
bool has_pending_changes() const noexcept
size_t height() const noexcept
Return the current height of the paged tree.
void stamp_all_pages_for_checkpoint(const std::uint64_t checkpoint_sequence) noexcept
static void insert_child_at(Page &page, const size_t idx, const page_id_t child_id)
static constexpr auto file_magic() noexcept
void write_full_image_to_path(const std::string &target_path, const std::uint64_t checkpoint_sequence) const
std::optional< Key > lower_bound(const Key &key) const
Return the first key not less than key.
static constexpr Page make_page(const PageKind kind) noexcept
static std::uint32_t page_checksum(const Page &page)
static constexpr std::uint32_t FormatVersion
bool equals(const Key &lhs, const Key &rhs) const
void init_sidecar_paths()
void write_full_image(std::ostream &out, const std::string &target_path, const std::uint64_t checkpoint_sequence) const
void acquire(const std::string &path, const char *kind, const Pid_File_Lock_Mode mode=Pid_File_Lock_Mode::Exclusive)
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
std::uint32_t crc32_add_bytes(std::uint32_t crc, const void *data, const size_t size) noexcept
void sync_parent_directory(const std::string &path, const char *kind)
constexpr std::array< char, Ordered_Tree_Snapshot_Magic_Size > ordered_tree_snapshot_magic(const char(&text)[N]) noexcept
void copy_file_contents(const std::string &src, const std::string &dst, const char *kind)
void remove_file_if_exists(const std::string &path, const char *kind)
std::uint32_t crc32_begin() noexcept
std::uint32_t crc32_add(std::uint32_t crc, const T &value) noexcept
constexpr size_t Ordered_Tree_Snapshot_Magic_Size
void rename_file_atomic(const std::string &src, const std::string &dst, const char *kind)
std::uint32_t crc32_finish(const std::uint32_t crc) noexcept
void sync_file_by_path(const std::string &path, const char *kind)
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
Paged_File_Open_Mode
Open mode for paged persistent tree files.
Itor2 copy(Itor1 sourceBeg, const Itor1 &sourceEnd, Itor2 destBeg)
Copy elements from one range to another.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::decay_t< typename HeadC::Item_Type > T
void next()
Advance all underlying iterators (bounds-checked).
auto mode(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the mode (most frequent value).
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
std::uint64_t checkpoint_sequence
page_id_t first_leaf_page
page_id_t children[MaxChildren]
std::uint16_t child_count
std::uint64_t checkpoint_sequence
Dynamic array container with automatic resizing.
Helpers for durable paged-tree files.
Fixed-size portable codecs for paged persistent tree payloads.
Comprehensive sorting algorithms and search utilities for Aleph-w.
Internal helpers for snapshot-backed persistent tree wrappers.