bdb.h raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2022 The Limenka developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #ifndef LIMENKA_WALLET_BDB_H
   7  #define LIMENKA_WALLET_BDB_H
   8  
   9  #include <clientversion.h>
  10  #include <common/system.h>
  11  #include <serialize.h>
  12  #include <streams.h>
  13  #include <util/fs.h>
  14  #include <wallet/db.h>
  15  
  16  #include <atomic>
  17  #include <condition_variable>
  18  #include <map>
  19  #include <memory>
  20  #include <string>
  21  #include <unordered_map>
  22  #include <vector>
  23  
  24  struct bilingual_str;
  25  
  26  class DbEnv;
  27  class DbTxn;
  28  class Db;
  29  class Dbc;
  30  
  31  // This constant was introduced in BDB 4.0.14 and has never changed, but there
  32  // is a belt-and-suspenders check in the cpp file just in case.
  33  #define BDB_DB_FILE_ID_LEN 20 /* Unique file ID length. */
  34  
  35  namespace wallet {
  36  
  37  struct WalletDatabaseFileId {
  38      uint8_t value[BDB_DB_FILE_ID_LEN];
  39      bool operator==(const WalletDatabaseFileId& rhs) const;
  40  };
  41  
  42  class BerkeleyDatabase;
  43  
  44  class BerkeleyEnvironment
  45  {
  46  private:
  47      bool fDbEnvInit;
  48      bool fMockDb;
  49      // Don't change into fs::path, as that can result in
  50      // shutdown problems/crashes caused by a static initialized internal pointer.
  51      std::string strPath;
  52  
  53  public:
  54      std::unique_ptr<DbEnv> dbenv;
  55      std::map<fs::path, std::reference_wrapper<BerkeleyDatabase>> m_databases;
  56      std::unordered_map<std::string, WalletDatabaseFileId> m_fileids;
  57      std::condition_variable_any m_db_in_use;
  58      bool m_use_shared_memory;
  59  
  60      explicit BerkeleyEnvironment(const fs::path& env_directory, bool use_shared_memory);
  61      BerkeleyEnvironment();
  62      ~BerkeleyEnvironment();
  63      void Reset();
  64  
  65      bool IsMock() const { return fMockDb; }
  66      bool IsInitialized() const { return fDbEnvInit; }
  67      fs::path Directory() const { return fs::PathFromString(strPath); }
  68  
  69      bool Open(bilingual_str& error);
  70      void Close();
  71      void Flush(bool fShutdown);
  72      [[nodiscard]] bool CheckpointLSN(const std::string& strFile);
  73  
  74      void CloseDb(const fs::path& filename);
  75      void ReloadDbEnv();
  76  
  77      DbTxn* TxnBegin(int flags);
  78  };
  79  
  80  /** Get BerkeleyEnvironment given a directory path. */
  81  std::shared_ptr<BerkeleyEnvironment> GetBerkeleyEnv(const fs::path& env_directory, bool use_shared_memory);
  82  
  83  class BerkeleyBatch;
  84  
  85  /** An instance of this class represents one database.
  86   * For BerkeleyDB this is just a (env, strFile) tuple.
  87   **/
  88  class BerkeleyDatabase : public WalletDatabase
  89  {
  90  public:
  91      BerkeleyDatabase() = delete;
  92  
  93      /** Create DB handle to real database */
  94      BerkeleyDatabase(std::shared_ptr<BerkeleyEnvironment> env, fs::path filename, const DatabaseOptions& options);
  95  
  96      ~BerkeleyDatabase() override;
  97  
  98      /** Open the database if it is not already opened. */
  99      void Open() override;
 100  
 101      /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
 102       */
 103      bool Rewrite(const char* pszSkip=nullptr) override;
 104  
 105      /** Indicate that a new database user has begun using the database. */
 106      void AddRef() override;
 107      /** Indicate that database user has stopped using the database and that it could be flushed or closed. */
 108      void RemoveRef() override;
 109  
 110      /** Back up the entire database to a file.
 111       */
 112      bool Backup(const std::string& strDest) const override;
 113  
 114      /** Make sure all changes are flushed to database file.
 115       */
 116      void Flush() override;
 117      /** Flush to the database file and close the database.
 118       *  Also close the environment if no other databases are open in it.
 119       */
 120      void Close() override;
 121      /* flush the wallet passively (TRY_LOCK)
 122         ideal to be called periodically */
 123      bool PeriodicFlush() override;
 124  
 125      void IncrementUpdateCounter() override;
 126  
 127      void ReloadDbEnv() override;
 128  
 129      /** Verifies the environment and database file */
 130      bool Verify(bilingual_str& error);
 131  
 132      /** Return path to main database filename */
 133      std::string Filename() override { return fs::PathToString(env->Directory() / m_filename); }
 134  
 135      std::vector<fs::path> Files() override;
 136  
 137      std::string Format() override { return "bdb"; }
 138      /**
 139       * Pointer to shared database environment.
 140       *
 141       * Normally there is only one BerkeleyDatabase object per
 142       * BerkeleyEnvivonment, but in the special, backwards compatible case where
 143       * multiple wallet BDB data files are loaded from the same directory, this
 144       * will point to a shared instance that gets freed when the last data file
 145       * is closed.
 146       */
 147      std::shared_ptr<BerkeleyEnvironment> env;
 148  
 149      /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */
 150      std::unique_ptr<Db> m_db;
 151  
 152      // Whether to byteswap
 153      bool m_byteswap;
 154  
 155      fs::path m_filename;
 156      int64_t m_max_log_mb;
 157  
 158      /** Make a BerkeleyBatch connected to this database */
 159      std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override;
 160  };
 161  
 162  class BerkeleyCursor : public DatabaseCursor
 163  {
 164  private:
 165      Dbc* m_cursor;
 166      std::vector<std::byte> m_key_prefix;
 167      bool m_first{true};
 168  
 169  public:
 170      // Constructor for cursor for records matching the prefix
 171      // To match all records, an empty prefix may be provided.
 172      explicit BerkeleyCursor(BerkeleyDatabase& database, const BerkeleyBatch& batch, Span<const std::byte> prefix = {});
 173      ~BerkeleyCursor() override;
 174  
 175      Status Next(DataStream& key, DataStream& value) override;
 176      Dbc* dbc() const { return m_cursor; }
 177  };
 178  
 179  /** RAII class that provides access to a Berkeley database */
 180  class BerkeleyBatch : public DatabaseBatch
 181  {
 182  private:
 183      bool ReadKey(DataStream&& key, DataStream& value) override;
 184      bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
 185      bool EraseKey(DataStream&& key) override;
 186      bool HasKey(DataStream&& key) override;
 187      bool ErasePrefix(Span<const std::byte> prefix) override;
 188  
 189  protected:
 190      Db* pdb{nullptr};
 191      std::string strFile;
 192      DbTxn* activeTxn{nullptr};
 193      bool fReadOnly;
 194      bool fFlushOnClose;
 195      BerkeleyEnvironment *env;
 196      BerkeleyDatabase& m_database;
 197  
 198  public:
 199      explicit BerkeleyBatch(BerkeleyDatabase& database, const bool fReadOnly, bool fFlushOnCloseIn=true);
 200      ~BerkeleyBatch() override;
 201  
 202      BerkeleyBatch(const BerkeleyBatch&) = delete;
 203      BerkeleyBatch& operator=(const BerkeleyBatch&) = delete;
 204  
 205      void Flush() override;
 206      void Close() override;
 207  
 208      std::unique_ptr<DatabaseCursor> GetNewCursor() override;
 209      std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) override;
 210      bool TxnBegin() override;
 211      bool TxnCommit() override;
 212      bool TxnAbort() override;
 213      bool HasActiveTxn() override { return activeTxn != nullptr; }
 214      DbTxn* txn() const { return activeTxn; }
 215  };
 216  
 217  std::string BerkeleyDatabaseVersion();
 218  
 219  /** Perform sanity check of runtime BDB version versus linked BDB version.
 220   */
 221  bool BerkeleyDatabaseSanityCheck();
 222  
 223  //! Return object giving access to Berkeley database at specified path.
 224  std::unique_ptr<BerkeleyDatabase> MakeBerkeleyDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
 225  } // namespace wallet
 226  
 227  #endif // LIMENKA_WALLET_BDB_H
 228