25static const std::vector<std::byte>
SUBDATABASE_NAME = {std::byte{
'm'}, std::byte{
'a'}, std::byte{
'i'}, std::byte{
'n'}};
92 std::array<std::byte, 20>
uid;
101 unsigned char iv[20];
110 template <
typename Stream>
176 throw std::runtime_error(
"Meta page number mismatch");
181 throw std::runtime_error(
"Not a BDB file");
186 throw std::runtime_error(
"Unsupported BDB data file version number");
191 throw std::runtime_error(
"Bad page size");
196 throw std::runtime_error(
"Unexpected page type, should be 9 (BTree Metadata)");
201 throw std::runtime_error(
"Unexpected database flags, should only be 0x20 (subdatabases)");
214 static constexpr size_t SIZE = 3;
221 template <
typename Stream>
248 template <
typename Stream>
252 s.read(std::as_writable_bytes(std::span(
data.data(),
data.size())));
272 template <
typename Stream>
280 s.read(std::as_writable_bytes(std::span(
data.data(),
data.size())));
305 static constexpr size_t SIZE = 9;
307 template <
typename Stream>
343 template <
typename Stream>
370 throw std::runtime_error(
"Page number mismatch");
373 throw std::runtime_error(
"Bad btree level");
388 std::vector<std::variant<DataRecord, OverflowRecord>>
records;
390 template <
typename Stream>
410 throw std::runtime_error(
"Data record position not in page");
435 throw std::runtime_error(
"Unknown record type in records page");
460 template <
typename Stream>
464 s.read(std::as_writable_bytes(std::span(
data.data(),
data.size())));
480 template <
typename Stream>
500 throw std::runtime_error(
"Internal record position not in page");
510 throw std::runtime_error(
"Unknown record type in internal page");
535 throw std::runtime_error(
"BerkeleyRODatabase: Failed to open database file");
560 throw std::runtime_error(
"Last page number could not fit in file");
565 throw std::runtime_error(
"BDB builtin encryption is not supported");
581 if (file != 0 || offset != 1) {
582 throw std::runtime_error(
"LSNs are not reset, this database is not completely flushed. Please reopen then close the database with a version that has BDB support");
591 throw std::runtime_error(
"Unexpected outer database root page type");
594 throw std::runtime_error(
"Unexpected number of entries in outer database root page");
600 if (!std::holds_alternative<DataRecord>(
page.records.at(0)) || std::get<DataRecord>(
page.records.at(0)).data !=
SUBDATABASE_NAME) {
601 throw std::runtime_error(
"Subdatabase has an unexpected name");
604 if (!std::holds_alternative<DataRecord>(
page.records.at(1)) || std::get<DataRecord>(
page.records.at(1)).m_header.len != 4) {
605 throw std::runtime_error(
"Subdatabase page number has unexpected length");
614 throw std::runtime_error(
"Page number is greater than database last page");
623 throw std::runtime_error(
"Unexpected page size");
627 throw std::runtime_error(
"Subdatabase last page is greater than database last page");
632 throw std::runtime_error(
"BDB builtin encryption is not supported");
637 while (
pages.size() > 0) {
649 switch (header.
type) {
654 if (rec.m_header.deleted)
continue;
655 pages.push_back(rec.page_num);
662 if (
rec_page.records.size() % 2 != 0) {
664 throw std::runtime_error(
"Records page has odd number of records");
667 std::vector<std::byte> key;
668 for (
const std::variant<DataRecord, OverflowRecord>& rec :
rec_page.records) {
669 std::vector<std::byte> data;
671 if (
drec->m_header.deleted)
continue;
674 if (
orec->m_header.deleted)
continue;
676 while (next_page != 0) {
681 throw std::runtime_error(
"Bad overflow record page type");
685 data.insert(data.end(),
opage.data.begin(),
opage.data.end());
701 throw std::runtime_error(
"Unexpected page type");
708 return std::make_unique<BerkeleyROBatch>(*
this);
716 if (fs::is_directory(
dst)) {
728 }
catch (
const fs::filesystem_error&
e) {
741 auto val = it->second;
743 value.
write(std::span(val));
779 std::unique_ptr<BerkeleyRODatabase>
db = std::make_unique<BerkeleyRODatabase>(
data_file);
782 }
catch (
const std::runtime_error&
e) {
BSWAP_CONSTEXPR uint32_t internal_bswap_32(uint32_t x)
BSWAP_CONSTEXPR uint16_t internal_bswap_16(uint16_t x)
Non-refcounted RAII wrapper for FILE*.
Double ended buffer combining vector and stream-like interfaces.
void write(std::span< const value_type > src)
bool ReadKey(DataStream &&key, DataStream &value) override
std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(std::span< const std::byte > prefix) override
const BerkeleyRODatabase & m_database
bool HasKey(DataStream &&key) override
BerkeleyROData::const_iterator m_cursor_end
BerkeleyROData::const_iterator m_cursor
const BerkeleyRODatabase & m_database
BerkeleyROCursor(const BerkeleyRODatabase &database, std::span< const std::byte > prefix={})
Status Next(DataStream &key, DataStream &value) override
A class representing a BerkeleyDB file from which we can only read records.
std::unique_ptr< DatabaseBatch > MakeBatch() override
Make a DatabaseBatch connected to this database.
void Open() override
Open the database if it is not already opened.
const fs::path m_filepath
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Class for data in the record directly.
void Unserialize(Stream &s)
std::vector< std::byte > data
DataRecord(const RecordHeader &header)
A page of records in the database.
InternalPage(const PageHeader &header)
void Unserialize(Stream &s)
std::vector< uint16_t > indexes
std::vector< InternalRecord > records
Class for records representing internal nodes of the BTree.
std::vector< std::byte > data
static constexpr size_t FIXED_SIZE
InternalRecord(const RecordHeader &header)
void Unserialize(Stream &s)
Berkeley DB BTree metadata page layout.
void Unserialize(Stream &s)
MetaPage(uint32_t expected_page_num)
uint32_t expected_page_num
std::array< std::byte, 20 > uid
A page containing overflow data.
std::vector< std::byte > data
void Unserialize(Stream &s)
OverflowPage(const PageHeader &header)
Class for records representing overflow records of the BTree.
OverflowRecord(const RecordHeader &header)
void Unserialize(Stream &s)
static constexpr size_t SIZE
A page of records in the database.
std::vector< std::variant< DataRecord, OverflowRecord > > records
void Unserialize(Stream &s)
RecordsPage(const PageHeader &header)
std::vector< uint16_t > indexes
uint32_t ReadBE32(const B *ptr)
static bool exists(const path &p)
static bool copy_file(const path &from, const path &to, copy_options options)
static std::string PathToString(const path &path)
Convert path object to a byte string.
static path PathFromString(const std::string &string)
Convert byte string to path object.
FILE * fopen(const fs::path &p, const char *mode)
static const std::vector< std::byte > SUBDATABASE_NAME
constexpr uint32_t BTREE_MAGIC
fs::path BDBDataFile(const fs::path &wallet_path)
constexpr uint32_t BTREE_MAGIC_OE
static void SeekToPage(AutoFile &s, uint32_t page_num, uint32_t page_size)
std::unique_ptr< BerkeleyRODatabase > MakeBerkeleyRODatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Return object giving access to Berkeley Read Only database at specified path.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.