db.h raw

   1  // Copyright (c) 2009-2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2021 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_DB_H
   7  #define LIMENKA_WALLET_DB_H
   8  
   9  #include <clientversion.h>
  10  #include <streams.h>
  11  #include <support/allocators/secure.h>
  12  #include <util/fs.h>
  13  
  14  #include <atomic>
  15  #include <memory>
  16  #include <optional>
  17  #include <string>
  18  
  19  class ArgsManager;
  20  struct bilingual_str;
  21  
  22  namespace wallet {
  23  // BytePrefix compares equality with other byte spans that begin with the same prefix.
  24  struct BytePrefix {
  25      Span<const std::byte> prefix;
  26  };
  27  bool operator<(BytePrefix a, Span<const std::byte> b);
  28  bool operator<(Span<const std::byte> a, BytePrefix b);
  29  
  30  class DatabaseCursor
  31  {
  32  public:
  33      explicit DatabaseCursor() = default;
  34      virtual ~DatabaseCursor() = default;
  35  
  36      DatabaseCursor(const DatabaseCursor&) = delete;
  37      DatabaseCursor& operator=(const DatabaseCursor&) = delete;
  38  
  39      enum class Status
  40      {
  41          FAIL,
  42          MORE,
  43          DONE,
  44      };
  45  
  46      virtual Status Next(DataStream& key, DataStream& value) { return Status::FAIL; }
  47  };
  48  
  49  /** RAII class that provides access to a WalletDatabase */
  50  class DatabaseBatch
  51  {
  52  private:
  53      virtual bool ReadKey(DataStream&& key, DataStream& value) = 0;
  54      virtual bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) = 0;
  55      virtual bool EraseKey(DataStream&& key) = 0;
  56      virtual bool HasKey(DataStream&& key) = 0;
  57  
  58  public:
  59      explicit DatabaseBatch() = default;
  60      virtual ~DatabaseBatch() = default;
  61  
  62      DatabaseBatch(const DatabaseBatch&) = delete;
  63      DatabaseBatch& operator=(const DatabaseBatch&) = delete;
  64  
  65      virtual void Flush() = 0;
  66      virtual void Close() = 0;
  67  
  68      template <typename K, typename T>
  69      bool Read(const K& key, T& value)
  70      {
  71          DataStream ssKey{};
  72          ssKey.reserve(1000);
  73          ssKey << key;
  74  
  75          DataStream ssValue{};
  76          if (!ReadKey(std::move(ssKey), ssValue)) return false;
  77          try {
  78              ssValue >> value;
  79              return true;
  80          } catch (const std::exception&) {
  81              return false;
  82          }
  83      }
  84  
  85      template <typename K, typename T>
  86      bool Write(const K& key, const T& value, bool fOverwrite = true)
  87      {
  88          DataStream ssKey{};
  89          ssKey.reserve(1000);
  90          ssKey << key;
  91  
  92          DataStream ssValue{};
  93          ssValue.reserve(10000);
  94          ssValue << value;
  95  
  96          return WriteKey(std::move(ssKey), std::move(ssValue), fOverwrite);
  97      }
  98  
  99      template <typename K>
 100      bool Erase(const K& key)
 101      {
 102          DataStream ssKey{};
 103          ssKey.reserve(1000);
 104          ssKey << key;
 105  
 106          return EraseKey(std::move(ssKey));
 107      }
 108  
 109      template <typename K>
 110      bool Exists(const K& key)
 111      {
 112          DataStream ssKey{};
 113          ssKey.reserve(1000);
 114          ssKey << key;
 115  
 116          return HasKey(std::move(ssKey));
 117      }
 118      virtual bool ErasePrefix(Span<const std::byte> prefix) = 0;
 119  
 120      virtual std::unique_ptr<DatabaseCursor> GetNewCursor() = 0;
 121      virtual std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(Span<const std::byte> prefix) = 0;
 122      virtual bool TxnBegin() = 0;
 123      virtual bool TxnCommit() = 0;
 124      virtual bool TxnAbort() = 0;
 125      virtual bool HasActiveTxn() = 0;
 126  };
 127  
 128  /** An instance of this class represents one database.
 129   **/
 130  class WalletDatabase
 131  {
 132  public:
 133      /** Create dummy DB handle */
 134      WalletDatabase() : nUpdateCounter(0) {}
 135      virtual ~WalletDatabase() = default;
 136  
 137      /** Open the database if it is not already opened. */
 138      virtual void Open() = 0;
 139  
 140      //! Counts the number of active database users to be sure that the database is not closed while someone is using it
 141      std::atomic<int> m_refcount{0};
 142      /** Indicate the a new database user has began using the database. Increments m_refcount */
 143      virtual void AddRef() = 0;
 144      /** Indicate that database user has stopped using the database and that it could be flushed or closed. Decrement m_refcount */
 145      virtual void RemoveRef() = 0;
 146  
 147      /** Rewrite the entire database on disk, with the exception of key pszSkip if non-zero
 148       */
 149      virtual bool Rewrite(const char* pszSkip=nullptr) = 0;
 150  
 151      /** Back up the entire database to a file.
 152       */
 153      virtual bool Backup(const std::string& strDest) const = 0;
 154  
 155      /** Make sure all changes are flushed to database file.
 156       */
 157      virtual void Flush() = 0;
 158      /** Flush to the database file and close the database.
 159       *  Also close the environment if no other databases are open in it.
 160       */
 161      virtual void Close() = 0;
 162      /* flush the wallet passively (TRY_LOCK)
 163         ideal to be called periodically */
 164      virtual bool PeriodicFlush() = 0;
 165  
 166      virtual void IncrementUpdateCounter() = 0;
 167  
 168      virtual void ReloadDbEnv() = 0;
 169  
 170      /** Return path to main database file for logs and error messages. */
 171      virtual std::string Filename() = 0;
 172  
 173      /** Return paths to all database created files */
 174      virtual std::vector<fs::path> Files() = 0;
 175  
 176      virtual std::string Format() = 0;
 177  
 178      std::atomic<unsigned int> nUpdateCounter;
 179      unsigned int nLastSeen{0};
 180      unsigned int nLastFlushed{0};
 181      int64_t nLastWalletUpdate{0};
 182  
 183      /** Make a DatabaseBatch connected to this database */
 184      virtual std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) = 0;
 185  };
 186  
 187  enum class DatabaseFormat {
 188      BERKELEY,
 189      SQLITE,
 190      BERKELEY_RO,
 191      BERKELEY_SWAP,
 192  };
 193  
 194  struct DatabaseOptions {
 195      bool require_existing = false;
 196      bool require_create = false;
 197      std::optional<DatabaseFormat> require_format;
 198      uint64_t create_flags = 0;
 199      SecureString create_passphrase;
 200  
 201      // Specialized options. Not every option is supported by every backend.
 202      bool verify = true;             //!< Check data integrity on load.
 203      bool use_unsafe_sync = false;   //!< Disable file sync for faster performance.
 204      bool use_shared_memory = false; //!< Let other processes access the database.
 205      int64_t max_log_mb = 100;       //!< Max log size to allow before consolidating.
 206  };
 207  
 208  enum class DatabaseStatus {
 209      SUCCESS,
 210      FAILED_BAD_PATH,
 211      FAILED_BAD_FORMAT,
 212      FAILED_ALREADY_LOADED,
 213      FAILED_ALREADY_EXISTS,
 214      FAILED_NOT_FOUND,
 215      FAILED_CREATE,
 216      FAILED_LOAD,
 217      FAILED_VERIFY,
 218      FAILED_ENCRYPT,
 219      FAILED_INVALID_BACKUP_FILE,
 220  };
 221  
 222  /** Recursively list database paths in directory. */
 223  std::vector<std::pair<fs::path, std::string>> ListDatabases(const fs::path& path);
 224  
 225  void ReadDatabaseArgs(const ArgsManager& args, DatabaseOptions& options);
 226  std::unique_ptr<WalletDatabase> MakeDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
 227  
 228  fs::path BDBDataFile(const fs::path& path);
 229  fs::path SQLiteDataFile(const fs::path& path);
 230  bool IsBDBFile(const fs::path& path);
 231  bool IsSQLiteFile(const fs::path& path);
 232  } // namespace wallet
 233  
 234  #endif // LIMENKA_WALLET_DB_H
 235