Bitcoin Core 28.99.0
P2P Digital Currency
migrate.cpp
Go to the documentation of this file.
1// Distributed under the MIT software license, see the accompanying
2// file COPYING or http://www.opensource.org/licenses/mit-license.php.
3
4#include <compat/byteswap.h>
5#include <crypto/common.h> // For ReadBE32
6#include <logging.h>
7#include <streams.h>
8#include <util/translation.h>
9#include <wallet/migrate.h>
10
11#include <optional>
12#include <variant>
13
14namespace wallet {
15// Magic bytes in both endianness's
16constexpr uint32_t BTREE_MAGIC = 0x00053162; // If the file endianness matches our system, we see this magic
17constexpr uint32_t BTREE_MAGIC_OE = 0x62310500; // If the file endianness is the other one, we will see this magic
18
19// Subdatabase name
20static const std::vector<std::byte> SUBDATABASE_NAME = {std::byte{'m'}, std::byte{'a'}, std::byte{'i'}, std::byte{'n'}};
21
22enum class PageType : uint8_t {
23 /*
24 * BDB has several page types, most of which we do not use
25 * They are listed here for completeness, but commented out
26 * to avoid opening something unintended.
27 INVALID = 0, // Invalid page type
28 DUPLICATE = 1, // Duplicate. Deprecated and no longer used
29 HASH_UNSORTED = 2, // Hash pages. Deprecated.
30 RECNO_INTERNAL = 4, // Recno internal
31 RECNO_LEAF = 6, // Recno leaf
32 HASH_META = 8, // Hash metadata
33 QUEUE_META = 10, // Queue Metadata
34 QUEUE_DATA = 11, // Queue Data
35 DUPLICATE_LEAF = 12, // Off-page duplicate leaf
36 HASH_SORTED = 13, // Sorted hash page
37 */
38 BTREE_INTERNAL = 3, // BTree internal
39 BTREE_LEAF = 5, // BTree leaf
40 OVERFLOW_DATA = 7, // Overflow
41 BTREE_META = 9, // BTree metadata
42};
43
44enum class RecordType : uint8_t {
45 KEYDATA = 1,
46 // DUPLICATE = 2, Unused as our databases do not support duplicate records
47 OVERFLOW_DATA = 3,
48 DELETE = 0x80, // Indicate this record is deleted. This is OR'd with the real type.
49};
50
51enum class BTreeFlags : uint32_t {
52 /*
53 * BTree databases have feature flags, but we do not use them except for
54 * subdatabases. The unused flags are included for completeness, but commented out
55 * to avoid accidental use.
56 DUP = 1, // Duplicates
57 RECNO = 2, // Recno tree
58 RECNUM = 4, // BTree: Maintain record counts
59 FIXEDLEN = 8, // Recno: fixed length records
60 RENUMBER = 0x10, // Recno: renumber on insert/delete
61 DUPSORT = 0x40, // Duplicates are sorted
62 COMPRESS = 0x80, // Compressed
63 */
64 SUBDB = 0x20, // Subdatabases
65};
66
69{
70public:
71 uint32_t lsn_file; // Log Sequence Number file
72 uint32_t lsn_offset; // Log Sequence Number offset
73 uint32_t page_num; // Current page number
74 uint32_t magic; // Magic number
75 uint32_t version; // Version
76 uint32_t pagesize; // Page size
77 uint8_t encrypt_algo; // Encryption algorithm
78 PageType type; // Page type
79 uint8_t metaflags; // Meta-only flags
80 uint8_t unused1; // Unused
81 uint32_t free_list; // Free list page number
82 uint32_t last_page; // Page number of last page in db
83 uint32_t partitions; // Number of partitions
84 uint32_t key_count; // Cached key count
85 uint32_t record_count; // Cached record count
86 BTreeFlags flags; // Flags
87 std::array<std::byte, 20> uid; // 20 byte unique file ID
88 uint32_t unused2; // Unused
89 uint32_t minkey; // Minimum key
90 uint32_t re_len; // Recno: fixed length record length
91 uint32_t re_pad; // Recno: fixed length record pad
92 uint32_t root; // Root page number
93 char unused3[368]; // 92 * 4 bytes of unused space
94 uint32_t crypto_magic; // Crypto magic number
95 char trash[12]; // 3 * 4 bytes of trash space
96 unsigned char iv[20]; // Crypto IV
97 unsigned char chksum[16]; // Checksum
98
101
103 MetaPage() = delete;
104
105 template <typename Stream>
106 void Unserialize(Stream& s)
107 {
108 s >> lsn_file;
109 s >> lsn_offset;
110 s >> page_num;
111 s >> magic;
112 s >> version;
113 s >> pagesize;
114 s >> encrypt_algo;
115
117
118 uint8_t uint8_type;
119 s >> uint8_type;
120 type = static_cast<PageType>(uint8_type);
121
122 s >> metaflags;
123 s >> unused1;
124 s >> free_list;
125 s >> last_page;
126 s >> partitions;
127 s >> key_count;
128 s >> record_count;
129
130 uint32_t uint32_flags;
131 s >> uint32_flags;
132 if (other_endian) {
133 uint32_flags = internal_bswap_32(uint32_flags);
134 }
135 flags = static_cast<BTreeFlags>(uint32_flags);
136
137 s >> uid;
138 s >> unused2;
139 s >> minkey;
140 s >> re_len;
141 s >> re_pad;
142 s >> root;
143 s >> unused3;
144 s >> crypto_magic;
145 s >> trash;
146 s >> iv;
147 s >> chksum;
148
149 if (other_endian) {
167 }
168
169 // Page number must match
171 throw std::runtime_error("Meta page number mismatch");
172 }
173
174 // Check magic
175 if (magic != BTREE_MAGIC) {
176 throw std::runtime_error("Not a BDB file");
177 }
178
179 // Only version 9 is supported
180 if (version != 9) {
181 throw std::runtime_error("Unsupported BDB data file version number");
182 }
183
184 // Page size must be 512 <= pagesize <= 64k, and be a power of 2
185 if (pagesize < 512 || pagesize > 65536 || (pagesize & (pagesize - 1)) != 0) {
186 throw std::runtime_error("Bad page size");
187 }
188
189 // Page type must be the btree type
190 if (type != PageType::BTREE_META) {
191 throw std::runtime_error("Unexpected page type, should be 9 (BTree Metadata)");
192 }
193
194 // Only supported meta-flag is subdatabase
195 if (flags != BTreeFlags::SUBDB) {
196 throw std::runtime_error("Unexpected database flags, should only be 0x20 (subdatabases)");
197 }
198 }
199};
200
203{
204public:
205 uint16_t len; // Key/data item length
206 RecordType type; // Page type (BDB has this include a DELETE FLAG that we track separately)
207 bool deleted; // Whether the DELETE flag was set on type
208
209 static constexpr size_t SIZE = 3; // The record header is 3 bytes
210
212
214 RecordHeader() = delete;
215
216 template <typename Stream>
217 void Unserialize(Stream& s)
218 {
219 s >> len;
220
221 uint8_t uint8_type;
222 s >> uint8_type;
223 type = static_cast<RecordType>(uint8_type & ~static_cast<uint8_t>(RecordType::DELETE));
224 deleted = uint8_type & static_cast<uint8_t>(RecordType::DELETE);
225
226 if (other_endian) {
228 }
229 }
230};
231
234{
235public:
236 DataRecord(const RecordHeader& header) : m_header(header) {}
237 DataRecord() = delete;
238
240
241 std::vector<std::byte> data; // Variable length key/data item
242
243 template <typename Stream>
244 void Unserialize(Stream& s)
245 {
246 data.resize(m_header.len);
247 s.read(AsWritableBytes(Span(data.data(), data.size())));
248 }
249};
250
253{
254public:
255 InternalRecord(const RecordHeader& header) : m_header(header) {}
256 InternalRecord() = delete;
257
259
260 uint8_t unused; // Padding, unused
261 uint32_t page_num; // Page number of referenced page
262 uint32_t records; // Subtree record count
263 std::vector<std::byte> data; // Variable length key item
264
265 static constexpr size_t FIXED_SIZE = 9; // Size of fixed data is 9 bytes
266
267 template <typename Stream>
268 void Unserialize(Stream& s)
269 {
270 s >> unused;
271 s >> page_num;
272 s >> records;
273
274 data.resize(m_header.len);
275 s.read(AsWritableBytes(Span(data.data(), data.size())));
276
280 }
281 }
282};
283
289{
290public:
291 OverflowRecord(const RecordHeader& header) : m_header(header) {}
292 OverflowRecord() = delete;
293
295
296 uint8_t unused2; // Padding, unused
297 uint32_t page_number; // Page number where data begins
298 uint32_t item_len; // Total length of item
299
300 static constexpr size_t SIZE = 9; // Overflow record is always 9 bytes
301
302 template <typename Stream>
303 void Unserialize(Stream& s)
304 {
305 s >> unused2;
306 s >> page_number;
307 s >> item_len;
308
312 }
313 }
314};
315
318{
319public:
320 uint32_t lsn_file; // Log Sequence Number file
321 uint32_t lsn_offset; // Log Sequence Number offset
322 uint32_t page_num; // Current page number
323 uint32_t prev_page; // Previous page number
324 uint32_t next_page; // Next page number
325 uint16_t entries; // Number of items on the page
326 uint16_t hf_offset; // High free byte page offset
327 uint8_t level; // Btree page level
328 PageType type; // Page type
329
330 static constexpr int64_t SIZE = 26; // The header is 26 bytes
331
334
336 PageHeader() = delete;
337
338 template <typename Stream>
339 void Unserialize(Stream& s)
340 {
341 s >> lsn_file;
342 s >> lsn_offset;
343 s >> page_num;
344 s >> prev_page;
345 s >> next_page;
346 s >> entries;
347 s >> hf_offset;
348 s >> level;
349
350 uint8_t uint8_type;
351 s >> uint8_type;
352 type = static_cast<PageType>(uint8_type);
353
354 if (other_endian) {
362 }
363
365 throw std::runtime_error("Page number mismatch");
366 }
367 if ((type != PageType::OVERFLOW_DATA && level < 1) || (type == PageType::OVERFLOW_DATA && level != 0)) {
368 throw std::runtime_error("Bad btree level");
369 }
370 }
371};
372
375{
376public:
377 RecordsPage(const PageHeader& header) : m_header(header) {}
378 RecordsPage() = delete;
379
381
382 std::vector<uint16_t> indexes;
383 std::vector<std::variant<DataRecord, OverflowRecord>> records;
384
385 template <typename Stream>
386 void Unserialize(Stream& s)
387 {
388 // Current position within the page
389 int64_t pos = PageHeader::SIZE;
390
391 // Get the items
392 for (uint32_t i = 0; i < m_header.entries; ++i) {
393 // Get the index
394 uint16_t index;
395 s >> index;
397 index = internal_bswap_16(index);
398 }
399 indexes.push_back(index);
400 pos += sizeof(uint16_t);
401
402 // Go to the offset from the index
403 int64_t to_jump = index - pos;
404 if (to_jump < 0) {
405 throw std::runtime_error("Data record position not in page");
406 }
407 s.ignore(to_jump);
408
409 // Read the record
411 s >> rec_hdr;
412 to_jump += RecordHeader::SIZE;
413
414 switch (rec_hdr.type) {
415 case RecordType::KEYDATA: {
416 DataRecord record(rec_hdr);
417 s >> record;
418 records.emplace_back(record);
419 to_jump += rec_hdr.len;
420 break;
421 }
423 OverflowRecord record(rec_hdr);
424 s >> record;
425 records.emplace_back(record);
426 to_jump += OverflowRecord::SIZE;
427 break;
428 }
429 default:
430 throw std::runtime_error("Unknown record type in records page");
431 }
432
433 // Go back to the indexes
434 s.seek(-to_jump, SEEK_CUR);
435 }
436 }
437};
438
441{
442public:
443 OverflowPage(const PageHeader& header) : m_header(header) {}
444 OverflowPage() = delete;
445
447
448 // BDB overloads some page fields to store overflow page data
449 // hf_offset contains the length of the overflow data stored on this page
450 // entries contains a reference count for references to this item
451
452 // The overflow data itself. Begins immediately following header
453 std::vector<std::byte> data;
454
455 template <typename Stream>
456 void Unserialize(Stream& s)
457 {
458 data.resize(m_header.hf_offset);
459 s.read(AsWritableBytes(Span(data.data(), data.size())));
460 }
461};
462
465{
466public:
467 InternalPage(const PageHeader& header) : m_header(header) {}
468 InternalPage() = delete;
469
471
472 std::vector<uint16_t> indexes;
473 std::vector<InternalRecord> records;
474
475 template <typename Stream>
476 void Unserialize(Stream& s)
477 {
478 // Current position within the page
479 int64_t pos = PageHeader::SIZE;
480
481 // Get the items
482 for (uint32_t i = 0; i < m_header.entries; ++i) {
483 // Get the index
484 uint16_t index;
485 s >> index;
487 index = internal_bswap_16(index);
488 }
489 indexes.push_back(index);
490 pos += sizeof(uint16_t);
491
492 // Go to the offset from the index
493 int64_t to_jump = index - pos;
494 if (to_jump < 0) {
495 throw std::runtime_error("Internal record position not in page");
496 }
497 s.ignore(to_jump);
498
499 // Read the record
501 s >> rec_hdr;
502 to_jump += RecordHeader::SIZE;
503
504 if (rec_hdr.type != RecordType::KEYDATA) {
505 throw std::runtime_error("Unknown record type in internal page");
506 }
507 InternalRecord record(rec_hdr);
508 s >> record;
509 records.emplace_back(record);
510 to_jump += InternalRecord::FIXED_SIZE + rec_hdr.len;
511
512 // Go back to the indexes
513 s.seek(-to_jump, SEEK_CUR);
514 }
515 }
516};
517
518static void SeekToPage(AutoFile& s, uint32_t page_num, uint32_t page_size)
519{
520 int64_t pos = int64_t{page_num} * page_size;
521 s.seek(pos, SEEK_SET);
522}
523
525{
526 // Open the file
527 FILE* file = fsbridge::fopen(m_filepath, "rb");
528 AutoFile db_file(file);
529 if (db_file.IsNull()) {
530 throw std::runtime_error("BerkeleyRODatabase: Failed to open database file");
531 }
532
533 uint32_t page_size = 4096; // Default page size
534
535 // Read the outer metapage
536 // Expected page number is 0
537 MetaPage outer_meta(0);
538 db_file >> outer_meta;
539 page_size = outer_meta.pagesize;
540
541 // Verify the size of the file is a multiple of the page size
542 db_file.seek(0, SEEK_END);
543 int64_t size = db_file.tell();
544
545 // Since BDB stores everything in a page, the file size should be a multiple of the page size;
546 // However, BDB doesn't actually check that this is the case, and enforcing this check results
547 // in us rejecting a database that BDB would not, so this check needs to be excluded.
548 // This is left commented out as a reminder to not accidentally implement this in the future.
549 // if (size % page_size != 0) {
550 // throw std::runtime_error("File size is not a multiple of page size");
551 // }
552
553 // Check the last page number
554 uint32_t expected_last_page{uint32_t((size / page_size) - 1)};
555 if (outer_meta.last_page != expected_last_page) {
556 throw std::runtime_error("Last page number could not fit in file");
557 }
558
559 // Make sure encryption is disabled
560 if (outer_meta.encrypt_algo != 0) {
561 throw std::runtime_error("BDB builtin encryption is not supported");
562 }
563
564 // Check all Log Sequence Numbers (LSN) point to file 0 and offset 1 which indicates that the LSNs were
565 // reset and that the log files are not necessary to get all of the data in the database.
566 for (uint32_t i = 0; i < outer_meta.last_page; ++i) {
567 // The LSN is composed of 2 32-bit ints, the first is a file id, the second an offset
568 // It will always be the first 8 bytes of a page, so we deserialize it directly for every page
569 uint32_t file;
570 uint32_t offset;
571 SeekToPage(db_file, i, page_size);
572 db_file >> file >> offset;
573 if (outer_meta.other_endian) {
574 file = internal_bswap_32(file);
575 offset = internal_bswap_32(offset);
576 }
577 if (file != 0 || offset != 1) {
578 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");
579 }
580 }
581
582 // Read the root page
583 SeekToPage(db_file, outer_meta.root, page_size);
584 PageHeader header(outer_meta.root, outer_meta.other_endian);
585 db_file >> header;
586 if (header.type != PageType::BTREE_LEAF) {
587 throw std::runtime_error("Unexpected outer database root page type");
588 }
589 if (header.entries != 2) {
590 throw std::runtime_error("Unexpected number of entries in outer database root page");
591 }
592 RecordsPage page(header);
593 db_file >> page;
594
595 // First record should be the string "main"
596 if (!std::holds_alternative<DataRecord>(page.records.at(0)) || std::get<DataRecord>(page.records.at(0)).data != SUBDATABASE_NAME) {
597 throw std::runtime_error("Subdatabase has an unexpected name");
598 }
599 // Check length of page number for subdatabase location
600 if (!std::holds_alternative<DataRecord>(page.records.at(1)) || std::get<DataRecord>(page.records.at(1)).m_header.len != 4) {
601 throw std::runtime_error("Subdatabase page number has unexpected length");
602 }
603
604 // Read subdatabase page number
605 // It is written as a big endian 32 bit number
606 uint32_t main_db_page = ReadBE32(UCharCast(std::get<DataRecord>(page.records.at(1)).data.data()));
607
608 // The main database is in a page that doesn't exist
609 if (main_db_page > outer_meta.last_page) {
610 throw std::runtime_error("Page number is greater than database last page");
611 }
612
613 // Read the inner metapage
614 SeekToPage(db_file, main_db_page, page_size);
615 MetaPage inner_meta(main_db_page);
616 db_file >> inner_meta;
617
618 if (inner_meta.pagesize != page_size) {
619 throw std::runtime_error("Unexpected page size");
620 }
621
622 if (inner_meta.last_page > outer_meta.last_page) {
623 throw std::runtime_error("Subdatabase last page is greater than database last page");
624 }
625
626 // Make sure encryption is disabled
627 if (inner_meta.encrypt_algo != 0) {
628 throw std::runtime_error("BDB builtin encryption is not supported");
629 }
630
631 // Do a DFS through the BTree, starting at root
632 std::vector<uint32_t> pages{inner_meta.root};
633 while (pages.size() > 0) {
634 uint32_t curr_page = pages.back();
635 // It turns out BDB completely ignores this last_page field and doesn't actually update it to the correct
636 // last page. While we should be checking this, we can't.
637 // This is left commented out as a reminder to not accidentally implement this in the future.
638 // if (curr_page > inner_meta.last_page) {
639 // throw std::runtime_error("Page number is greater than subdatabase last page");
640 // }
641 pages.pop_back();
642 SeekToPage(db_file, curr_page, page_size);
643 PageHeader header(curr_page, inner_meta.other_endian);
644 db_file >> header;
645 switch (header.type) {
647 InternalPage int_page(header);
648 db_file >> int_page;
649 for (const InternalRecord& rec : int_page.records) {
650 if (rec.m_header.deleted) continue;
651 pages.push_back(rec.page_num);
652 }
653 break;
654 }
656 RecordsPage rec_page(header);
657 db_file >> rec_page;
658 if (rec_page.records.size() % 2 != 0) {
659 // BDB stores key value pairs in consecutive records, thus an odd number of records is unexpected
660 throw std::runtime_error("Records page has odd number of records");
661 }
662 bool is_key = true;
663 std::vector<std::byte> key;
664 for (const std::variant<DataRecord, OverflowRecord>& rec : rec_page.records) {
665 std::vector<std::byte> data;
666 if (const DataRecord* drec = std::get_if<DataRecord>(&rec)) {
667 if (drec->m_header.deleted) continue;
668 data = drec->data;
669 } else if (const OverflowRecord* orec = std::get_if<OverflowRecord>(&rec)) {
670 if (orec->m_header.deleted) continue;
671 uint32_t next_page = orec->page_number;
672 while (next_page != 0) {
673 SeekToPage(db_file, next_page, page_size);
674 PageHeader opage_header(next_page, inner_meta.other_endian);
675 db_file >> opage_header;
676 if (opage_header.type != PageType::OVERFLOW_DATA) {
677 throw std::runtime_error("Bad overflow record page type");
678 }
679 OverflowPage opage(opage_header);
680 db_file >> opage;
681 data.insert(data.end(), opage.data.begin(), opage.data.end());
682 next_page = opage_header.next_page;
683 }
684 }
685
686 if (is_key) {
687 key = data;
688 } else {
689 m_records.emplace(SerializeData{key.begin(), key.end()}, SerializeData{data.begin(), data.end()});
690 key.clear();
691 }
692 is_key = !is_key;
693 }
694 break;
695 }
696 default:
697 throw std::runtime_error("Unexpected page type");
698 }
699 }
700}
701
702std::unique_ptr<DatabaseBatch> BerkeleyRODatabase::MakeBatch(bool flush_on_close)
703{
704 return std::make_unique<BerkeleyROBatch>(*this);
705}
706
707bool BerkeleyRODatabase::Backup(const std::string& dest) const
708{
709 fs::path src(m_filepath);
710 fs::path dst(fs::PathFromString(dest));
711
712 if (fs::is_directory(dst)) {
713 dst = BDBDataFile(dst);
714 }
715 try {
716 if (fs::exists(dst) && fs::equivalent(src, dst)) {
717 LogPrintf("cannot backup to wallet source file %s\n", fs::PathToString(dst));
718 return false;
719 }
720
721 fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
722 LogPrintf("copied %s to %s\n", fs::PathToString(m_filepath), fs::PathToString(dst));
723 return true;
724 } catch (const fs::filesystem_error& e) {
726 return false;
727 }
728}
729
731{
732 SerializeData key_data{key.begin(), key.end()};
733 const auto it{m_database.m_records.find(key_data)};
734 if (it == m_database.m_records.end()) {
735 return false;
736 }
737 auto val = it->second;
738 value.clear();
739 value.write(Span(val));
740 return true;
741}
742
744{
745 SerializeData key_data{key.begin(), key.end()};
746 return m_database.m_records.count(key_data) > 0;
747}
748
750 : m_database(database)
751{
752 std::tie(m_cursor, m_cursor_end) = m_database.m_records.equal_range(BytePrefix{prefix});
753}
754
756{
757 if (m_cursor == m_cursor_end) {
759 }
760 ssKey.write(Span(m_cursor->first));
761 ssValue.write(Span(m_cursor->second));
762 m_cursor++;
764}
765
767{
768 return std::make_unique<BerkeleyROCursor>(m_database, prefix);
769}
770
771std::unique_ptr<BerkeleyRODatabase> MakeBerkeleyRODatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error)
772{
773 fs::path data_file = BDBDataFile(path);
774 try {
775 std::unique_ptr<BerkeleyRODatabase> db = std::make_unique<BerkeleyRODatabase>(data_file);
777 return db;
778 } catch (const std::runtime_error& e) {
779 error.original = e.what();
781 return nullptr;
782 }
783}
784} // namespace wallet
BSWAP_CONSTEXPR uint32_t internal_bswap_32(uint32_t x)
Definition: byteswap.h:53
BSWAP_CONSTEXPR uint16_t internal_bswap_16(uint16_t x)
Definition: byteswap.h:44
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:392
void seek(int64_t offset, int origin)
Wrapper around fseek().
Definition: streams.cpp:33
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:428
int64_t tell()
Find position within the file.
Definition: streams.cpp:54
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
void write(Span< const value_type > src)
Definition: streams.h:251
void clear()
Definition: streams.h:187
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: migrate.cpp:730
std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(Span< const std::byte > prefix) override
Definition: migrate.cpp:766
const BerkeleyRODatabase & m_database
Definition: migrate.h:93
bool HasKey(DataStream &&key) override
Definition: migrate.cpp:743
BerkeleyROData::const_iterator m_cursor_end
Definition: migrate.h:80
BerkeleyROCursor(const BerkeleyRODatabase &database, Span< const std::byte > prefix={})
Definition: migrate.cpp:749
BerkeleyROData::const_iterator m_cursor
Definition: migrate.h:79
const BerkeleyRODatabase & m_database
Definition: migrate.h:78
Status Next(DataStream &key, DataStream &value) override
Definition: migrate.cpp:755
A class representing a BerkeleyDB file from which we can only read records.
Definition: migrate.h:21
BerkeleyROData m_records
Definition: migrate.h:33
void Open() override
Open the database if it is not already opened.
Definition: migrate.cpp:524
const fs::path m_filepath
Definition: migrate.h:23
std::unique_ptr< DatabaseBatch > MakeBatch(bool flush_on_close=true) override
Make a DatabaseBatch connected to this database.
Definition: migrate.cpp:702
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Definition: migrate.cpp:707
Class for data in the record directly.
Definition: migrate.cpp:234
RecordHeader m_header
Definition: migrate.cpp:239
void Unserialize(Stream &s)
Definition: migrate.cpp:244
std::vector< std::byte > data
Definition: migrate.cpp:241
DataRecord(const RecordHeader &header)
Definition: migrate.cpp:236
A page of records in the database.
Definition: migrate.cpp:465
InternalPage(const PageHeader &header)
Definition: migrate.cpp:467
PageHeader m_header
Definition: migrate.cpp:470
void Unserialize(Stream &s)
Definition: migrate.cpp:476
std::vector< uint16_t > indexes
Definition: migrate.cpp:472
std::vector< InternalRecord > records
Definition: migrate.cpp:473
Class for records representing internal nodes of the BTree.
Definition: migrate.cpp:253
std::vector< std::byte > data
Definition: migrate.cpp:263
static constexpr size_t FIXED_SIZE
Definition: migrate.cpp:265
InternalRecord(const RecordHeader &header)
Definition: migrate.cpp:255
void Unserialize(Stream &s)
Definition: migrate.cpp:268
RecordHeader m_header
Definition: migrate.cpp:258
Berkeley DB BTree metadata page layout.
Definition: migrate.cpp:69
uint32_t version
Definition: migrate.cpp:75
uint32_t pagesize
Definition: migrate.cpp:76
uint8_t encrypt_algo
Definition: migrate.cpp:77
uint8_t metaflags
Definition: migrate.cpp:79
uint32_t re_pad
Definition: migrate.cpp:91
char unused3[368]
Definition: migrate.cpp:93
uint32_t re_len
Definition: migrate.cpp:90
uint32_t crypto_magic
Definition: migrate.cpp:94
void Unserialize(Stream &s)
Definition: migrate.cpp:106
uint8_t unused1
Definition: migrate.cpp:80
PageType type
Definition: migrate.cpp:78
uint32_t unused2
Definition: migrate.cpp:88
uint32_t free_list
Definition: migrate.cpp:81
uint32_t partitions
Definition: migrate.cpp:83
char trash[12]
Definition: migrate.cpp:95
uint32_t page_num
Definition: migrate.cpp:73
unsigned char iv[20]
Definition: migrate.cpp:96
unsigned char chksum[16]
Definition: migrate.cpp:97
uint32_t minkey
Definition: migrate.cpp:89
MetaPage(uint32_t expected_page_num)
Definition: migrate.cpp:102
uint32_t expected_page_num
Definition: migrate.cpp:100
uint32_t magic
Definition: migrate.cpp:74
uint32_t lsn_offset
Definition: migrate.cpp:72
BTreeFlags flags
Definition: migrate.cpp:86
uint32_t root
Definition: migrate.cpp:92
uint32_t record_count
Definition: migrate.cpp:85
uint32_t last_page
Definition: migrate.cpp:82
uint32_t lsn_file
Definition: migrate.cpp:71
uint32_t key_count
Definition: migrate.cpp:84
std::array< std::byte, 20 > uid
Definition: migrate.cpp:87
A page containing overflow data.
Definition: migrate.cpp:441
std::vector< std::byte > data
Definition: migrate.cpp:453
void Unserialize(Stream &s)
Definition: migrate.cpp:456
OverflowPage(const PageHeader &header)
Definition: migrate.cpp:443
PageHeader m_header
Definition: migrate.cpp:446
Class for records representing overflow records of the BTree.
Definition: migrate.cpp:289
OverflowRecord(const RecordHeader &header)
Definition: migrate.cpp:291
RecordHeader m_header
Definition: migrate.cpp:294
void Unserialize(Stream &s)
Definition: migrate.cpp:303
static constexpr size_t SIZE
Definition: migrate.cpp:300
A generic data page in the database.
Definition: migrate.cpp:318
uint32_t prev_page
Definition: migrate.cpp:323
static constexpr int64_t SIZE
Definition: migrate.cpp:330
uint32_t next_page
Definition: migrate.cpp:324
uint32_t lsn_offset
Definition: migrate.cpp:321
uint16_t entries
Definition: migrate.cpp:325
void Unserialize(Stream &s)
Definition: migrate.cpp:339
uint32_t page_num
Definition: migrate.cpp:322
uint16_t hf_offset
Definition: migrate.cpp:326
uint32_t lsn_file
Definition: migrate.cpp:320
PageHeader(uint32_t page_num, bool other_endian)
Definition: migrate.cpp:335
uint32_t expected_page_num
Definition: migrate.cpp:332
General class for records in a BDB BTree database.
Definition: migrate.cpp:203
RecordHeader(bool other_endian)
Definition: migrate.cpp:213
void Unserialize(Stream &s)
Definition: migrate.cpp:217
static constexpr size_t SIZE
Definition: migrate.cpp:209
A page of records in the database.
Definition: migrate.cpp:375
std::vector< std::variant< DataRecord, OverflowRecord > > records
Definition: migrate.cpp:383
void Unserialize(Stream &s)
Definition: migrate.cpp:386
RecordsPage(const PageHeader &header)
Definition: migrate.cpp:377
PageHeader m_header
Definition: migrate.cpp:380
std::vector< uint16_t > indexes
Definition: migrate.cpp:382
static uint32_t ReadBE32(const unsigned char *ptr)
Definition: common.h:59
#define LogPrintf(...)
Definition: logging.h:266
static bool exists(const path &p)
Definition: fs.h:89
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:128
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:118
BTreeFlags
Definition: migrate.cpp:51
static const std::vector< std::byte > SUBDATABASE_NAME
Definition: migrate.cpp:20
constexpr uint32_t BTREE_MAGIC
Definition: migrate.cpp:16
PageType
Definition: migrate.cpp:22
RecordType
Definition: migrate.cpp:44
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:76
constexpr uint32_t BTREE_MAGIC_OE
Definition: migrate.cpp:17
static void SeekToPage(AutoFile &s, uint32_t page_num, uint32_t page_size)
Definition: migrate.cpp:518
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.
Definition: migrate.cpp:771
DatabaseStatus
Definition: db.h:205
const char * prefix
Definition: rest.cpp:1009
Span< std::byte > AsWritableBytes(Span< T > s) noexcept
Definition: span.h:264
Span(T *, EndOrSize) -> Span< T >
unsigned char * UCharCast(char *c)
Definition: span.h:281
Bilingual messages:
Definition: translation.h:21
std::string original
Definition: translation.h:22
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:49