Bitcoin Core  29.1.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 
14 namespace wallet {
15 // Magic bytes in both endianness's
16 constexpr uint32_t BTREE_MAGIC = 0x00053162; // If the file endianness matches our system, we see this magic
17 constexpr uint32_t BTREE_MAGIC_OE = 0x62310500; // If the file endianness is the other one, we will see this magic
18 
19 // Subdatabase name
20 static const std::vector<std::byte> SUBDATABASE_NAME = {std::byte{'m'}, std::byte{'a'}, std::byte{'i'}, std::byte{'n'}};
21 
22 enum 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 
44 enum 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 
51 enum 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 
68 class MetaPage
69 {
70 public:
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
170  if (page_num != expected_page_num) {
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 {
204 public:
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 {
235 public:
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 {
254 public:
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 
277  if (m_header.other_endian) {
280  }
281  }
282 };
283 
289 {
290 public:
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 
309  if (m_header.other_endian) {
312  }
313  }
314 };
315 
318 {
319 public:
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 
364  if (expected_page_num != page_num) {
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 {
376 public:
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;
396  if (m_header.other_endian) {
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 {
442 public:
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 {
466 public:
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;
486  if (m_header.other_endian) {
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 
518 static 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(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  }
655  case PageType::BTREE_LEAF: {
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 
702 std::unique_ptr<DatabaseBatch> BerkeleyRODatabase::MakeBatch(bool flush_on_close)
703 {
704  return std::make_unique<BerkeleyROBatch>(*this);
705 }
706 
707 bool 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 
771 std::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);
776  status = DatabaseStatus::SUCCESS;
777  return db;
778  } catch (const std::runtime_error& e) {
779  error.original = e.what();
781  return nullptr;
782  }
783 }
784 } // namespace wallet
std::vector< std::variant< DataRecord, OverflowRecord > > records
Definition: migrate.cpp:383
BSWAP_CONSTEXPR uint32_t internal_bswap_32(uint32_t x)
Definition: byteswap.h:53
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
bool Backup(const std::string &strDest) const override
Back up the entire database to a file.
Definition: migrate.cpp:707
BerkeleyROData::const_iterator m_cursor_end
Definition: migrate.h:80
uint8_t unused1
Definition: migrate.cpp:80
BerkeleyROData::const_iterator m_cursor
Definition: migrate.h:79
BTreeFlags flags
Definition: migrate.cpp:86
RecordHeader m_header
Definition: migrate.cpp:258
void Unserialize(Stream &s)
Definition: migrate.cpp:217
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
FILE * fopen(const fs::path &p, const char *mode)
Definition: fs.cpp:26
static const std::vector< std::byte > SUBDATABASE_NAME
Definition: migrate.cpp:20
static constexpr size_t SIZE
Definition: migrate.cpp:300
uint32_t ReadBE32(const B *ptr)
Definition: common.h:72
std::vector< std::byte > data
Definition: migrate.cpp:453
void Unserialize(Stream &s)
Definition: migrate.cpp:476
Bilingual messages:
Definition: translation.h:24
RecordHeader(bool other_endian)
Definition: migrate.cpp:213
Span< std::byte > AsWritableBytes(Span< T > s) noexcept
Definition: span.h:263
std::vector< uint16_t > indexes
Definition: migrate.cpp:472
PageHeader(uint32_t page_num, bool other_endian)
Definition: migrate.cpp:335
std::vector< InternalRecord > records
Definition: migrate.cpp:473
std::vector< std::byte > data
Definition: migrate.cpp:241
const char * prefix
Definition: rest.cpp:1009
PageType
Definition: migrate.cpp:22
uint32_t root
Definition: migrate.cpp:92
void Open() override
Open the database if it is not already opened.
Definition: migrate.cpp:524
InternalPage(const PageHeader &header)
Definition: migrate.cpp:467
A page of records in the database.
Definition: migrate.cpp:464
std::array< std::byte, 20 > uid
Definition: migrate.cpp:87
BTreeFlags
Definition: migrate.cpp:51
OverflowPage(const PageHeader &header)
Definition: migrate.cpp:443
uint32_t expected_page_num
Definition: migrate.cpp:100
uint32_t re_len
Definition: migrate.cpp:90
void write(Span< const value_type > src)
Definition: streams.h:251
void Unserialize(Stream &s)
Definition: migrate.cpp:386
General class for records in a BDB BTree database.
Definition: migrate.cpp:202
MetaPage(uint32_t expected_page_num)
Definition: migrate.cpp:102
A class representing a BerkeleyDB file from which we can only read records.
Definition: migrate.h:20
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:391
std::vector< std::byte > data
Definition: migrate.cpp:263
uint32_t lsn_file
Definition: migrate.cpp:320
unsigned char chksum[16]
Definition: migrate.cpp:97
static constexpr int64_t SIZE
Definition: migrate.cpp:330
void Unserialize(Stream &s)
Definition: migrate.cpp:106
uint8_t encrypt_algo
Definition: migrate.cpp:77
PageHeader m_header
Definition: migrate.cpp:446
uint32_t magic
Definition: migrate.cpp:74
void Unserialize(Stream &s)
Definition: migrate.cpp:456
int64_t tell()
Find position within the file.
Definition: streams.cpp:54
uint32_t crypto_magic
Definition: migrate.cpp:94
constexpr uint32_t BTREE_MAGIC
Definition: migrate.cpp:16
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
DataRecord(const RecordHeader &header)
Definition: migrate.cpp:236
uint32_t lsn_file
Definition: migrate.cpp:71
uint8_t metaflags
Definition: migrate.cpp:79
A generic data page in the database.
Definition: migrate.cpp:317
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:146
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:49
uint32_t page_num
Definition: migrate.cpp:73
PageType type
Definition: migrate.cpp:78
PageHeader m_header
Definition: migrate.cpp:470
unsigned char iv[20]
Definition: migrate.cpp:96
uint32_t version
Definition: migrate.cpp:75
Class for records representing internal nodes of the BTree.
Definition: migrate.cpp:252
RecordHeader m_header
Definition: migrate.cpp:294
Status Next(DataStream &key, DataStream &value) override
Definition: migrate.cpp:755
std::unique_ptr< DatabaseCursor > GetNewPrefixCursor(Span< const std::byte > prefix) override
Definition: migrate.cpp:766
uint32_t last_page
Definition: migrate.cpp:82
A page containing overflow data.
Definition: migrate.cpp:440
BerkeleyROCursor(const BerkeleyRODatabase &database, Span< const std::byte > prefix={})
Definition: migrate.cpp:749
uint32_t prev_page
Definition: migrate.cpp:323
std::unique_ptr< DatabaseBatch > MakeBatch(bool flush_on_close=true) override
Make a DatabaseBatch connected to this database.
Definition: migrate.cpp:702
std::vector< uint16_t > indexes
Definition: migrate.cpp:382
uint32_t expected_page_num
Definition: migrate.cpp:332
Class for records representing overflow records of the BTree.
Definition: migrate.cpp:288
bool HasKey(DataStream &&key) override
Definition: migrate.cpp:743
uint32_t minkey
Definition: migrate.cpp:89
char trash[12]
Definition: migrate.cpp:95
BerkeleyROData m_records
Definition: migrate.h:33
uint32_t partitions
Definition: migrate.cpp:83
DatabaseStatus
Definition: db.h:205
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:118
uint32_t page_num
Definition: migrate.cpp:322
uint32_t re_pad
Definition: migrate.cpp:91
void clear()
Definition: streams.h:187
void Unserialize(Stream &s)
Definition: migrate.cpp:339
bool ReadKey(DataStream &&key, DataStream &value) override
Definition: migrate.cpp:730
std::string original
Definition: translation.h:25
constexpr uint32_t BTREE_MAGIC_OE
Definition: migrate.cpp:17
uint32_t key_count
Definition: migrate.cpp:84
Berkeley DB BTree metadata page layout.
Definition: migrate.cpp:68
void Unserialize(Stream &s)
Definition: migrate.cpp:244
static void SeekToPage(AutoFile &s, uint32_t page_num, uint32_t page_size)
Definition: migrate.cpp:518
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:76
uint32_t next_page
Definition: migrate.cpp:324
RecordType
Definition: migrate.cpp:44
RecordHeader m_header
Definition: migrate.cpp:239
RecordsPage(const PageHeader &header)
Definition: migrate.cpp:377
uint32_t lsn_offset
Definition: migrate.cpp:321
A page of records in the database.
Definition: migrate.cpp:374
static constexpr size_t SIZE
Definition: migrate.cpp:209
void seek(int64_t offset, int origin)
Wrapper around fseek().
Definition: streams.cpp:33
uint32_t lsn_offset
Definition: migrate.cpp:72
char unused3[368]
Definition: migrate.cpp:93
PageHeader m_header
Definition: migrate.cpp:380
OverflowRecord(const RecordHeader &header)
Definition: migrate.cpp:291
uint32_t pagesize
Definition: migrate.cpp:76
const BerkeleyRODatabase & m_database
Definition: migrate.h:78
static bool exists(const path &p)
Definition: fs.h:89
#define LogPrintf(...)
Definition: logging.h:361
void Unserialize(Stream &s)
Definition: migrate.cpp:303
uint32_t unused2
Definition: migrate.cpp:88
uint32_t record_count
Definition: migrate.cpp:85
Class for data in the record directly.
Definition: migrate.cpp:233
Span(T *, EndOrSize) -> Span< T >
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:32
uint32_t free_list
Definition: migrate.cpp:81
const fs::path m_filepath
Definition: migrate.h:23
const BerkeleyRODatabase & m_database
Definition: migrate.h:93
InternalRecord(const RecordHeader &header)
Definition: migrate.cpp:255
static constexpr size_t FIXED_SIZE
Definition: migrate.cpp:265
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:128
uint16_t hf_offset
Definition: migrate.cpp:326
void Unserialize(Stream &s)
Definition: migrate.cpp:268
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:428
uint16_t entries
Definition: migrate.cpp:325
BSWAP_CONSTEXPR uint16_t internal_bswap_16(uint16_t x)
Definition: byteswap.h:44