sqlite.h raw

   1  // Copyright (c) 2020-present The Bitcoin Core developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef BITCOIN_WALLET_SQLITE_H
   6  #define BITCOIN_WALLET_SQLITE_H
   7  
   8  #include <sync.h>
   9  #include <wallet/db.h>
  10  
  11  #include <semaphore>
  12  
  13  struct bilingual_str;
  14  
  15  struct sqlite3_stmt;
  16  struct sqlite3;
  17  
  18  namespace wallet {
  19  class SQLiteDatabase;
  20  
  21  /** RAII class that provides a database cursor */
  22  class SQLiteCursor : public DatabaseCursor
  23  {
  24  public:
  25      sqlite3_stmt* m_cursor_stmt{nullptr};
  26      // Copies of the prefix things for the prefix cursor.
  27      // Prevents SQLite from accessing temp variables for the prefix things.
  28      std::vector<std::byte> m_prefix_range_start;
  29      std::vector<std::byte> m_prefix_range_end;
  30  
  31      explicit SQLiteCursor() = default;
  32      explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range)
  33          : m_prefix_range_start(std::move(start_range)),
  34          m_prefix_range_end(std::move(end_range))
  35      {}
  36      ~SQLiteCursor() override;
  37  
  38      Status Next(DataStream& key, DataStream& value) override;
  39  };
  40  
  41  /** Class responsible for executing SQL statements in SQLite databases.
  42   *  Methods are virtual so they can be overridden by unit tests testing unusual database conditions. */
  43  class SQliteExecHandler
  44  {
  45  public:
  46      virtual ~SQliteExecHandler() = default;
  47      virtual int Exec(SQLiteDatabase& database, const std::string& statement);
  48  };
  49  
  50  /** RAII class that provides access to a WalletDatabase */
  51  class SQLiteBatch : public DatabaseBatch
  52  {
  53  private:
  54      SQLiteDatabase& m_database;
  55      std::unique_ptr<SQliteExecHandler> m_exec_handler{std::make_unique<SQliteExecHandler>()};
  56  
  57      sqlite3_stmt* m_read_stmt{nullptr};
  58      sqlite3_stmt* m_insert_stmt{nullptr};
  59      sqlite3_stmt* m_overwrite_stmt{nullptr};
  60      sqlite3_stmt* m_delete_stmt{nullptr};
  61      sqlite3_stmt* m_delete_prefix_stmt{nullptr};
  62  
  63      /** Whether this batch has started a database transaction and whether it owns SQLiteDatabase::m_write_semaphore.
  64       * If the batch starts a db tx, it acquires the semaphore and sets this to true, keeping the semaphore
  65       * until the transaction ends to prevent other batch objects from writing to the database.
  66       *
  67       * If this batch did not start a transaction, the semaphore is acquired transiently when writing and m_txn
  68       * is not set.
  69       *
  70       * m_txn is different from HasActiveTxn() as it is only true when this batch has started the transaction,
  71       * not just when any batch has started a transaction.
  72       */
  73      bool m_txn{false};
  74  
  75      void SetupSQLStatements();
  76      bool ExecStatement(sqlite3_stmt* stmt, std::span<const std::byte> blob);
  77  
  78  protected:
  79      bool ReadKey(DataStream&& key, DataStream& value) override;
  80      bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
  81      bool EraseKey(DataStream&& key) override;
  82      bool HasKey(DataStream&& key) override;
  83      bool ErasePrefix(std::span<const std::byte> prefix) override;
  84  
  85  public:
  86      explicit SQLiteBatch(SQLiteDatabase& database);
  87      ~SQLiteBatch() override { Close(); }
  88  
  89      void SetExecHandler(std::unique_ptr<SQliteExecHandler>&& handler) { m_exec_handler = std::move(handler); }
  90  
  91      void Close() override;
  92  
  93      std::unique_ptr<DatabaseCursor> GetNewCursor() override;
  94      std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(std::span<const std::byte> prefix) override;
  95      bool TxnBegin() override;
  96      bool TxnCommit() override;
  97      bool TxnAbort() override;
  98      bool HasActiveTxn() override { return m_txn; }
  99  };
 100  
 101  /** An instance of this class represents one SQLite3 database.
 102   **/
 103  class SQLiteDatabase : public WalletDatabase
 104  {
 105  private:
 106      friend class SQLiteBatch;
 107  
 108      const fs::path m_dir_path;
 109  
 110      const std::string m_file_path;
 111  
 112      const int m_additional_flags;
 113  
 114      /**
 115       * This mutex protects SQLite initialization and shutdown.
 116       * sqlite3_config() and sqlite3_shutdown() are not thread-safe (sqlite3_initialize() is).
 117       * Concurrent threads that execute SQLiteDatabase::SQLiteDatabase() should have just one
 118       * of them do the init and the rest wait for it to complete before all can proceed.
 119       */
 120      static Mutex g_sqlite_mutex;
 121      static int g_sqlite_count GUARDED_BY(g_sqlite_mutex);
 122  
 123      void Cleanup() noexcept EXCLUSIVE_LOCKS_REQUIRED(!g_sqlite_mutex);
 124  
 125      void Open(int additional_flags);
 126  
 127  protected:
 128      SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, int additional_flags);
 129  
 130  public:
 131      SQLiteDatabase() = delete;
 132  
 133      /** Create DB handle to real database */
 134      SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options);
 135  
 136      ~SQLiteDatabase();
 137  
 138      // Batches must acquire this semaphore on writing, and release when done writing.
 139      // This ensures that only one batch is modifying the database at a time.
 140      std::binary_semaphore m_write_semaphore;
 141  
 142      bool Verify(bilingual_str& error);
 143  
 144      /** Open the database if it is not already opened */
 145      void Open() override;
 146  
 147      /** Close the database */
 148      void Close() override;
 149  
 150      /** Rewrite the entire database on disk */
 151      bool Rewrite() override;
 152  
 153      /** Back up the entire database to a file.
 154       */
 155      bool Backup(const std::string& dest) const override;
 156  
 157      std::string Filename() override { return m_file_path; }
 158      /** Return paths to all database created files */
 159      std::vector<fs::path> Files() override
 160      {
 161          std::vector<fs::path> files;
 162          files.emplace_back(m_dir_path / fs::PathFromString(m_file_path));
 163          files.emplace_back(m_dir_path / fs::PathFromString(m_file_path + "-journal"));
 164          return files;
 165      }
 166      std::string Format() override { return "sqlite"; }
 167  
 168      /** Make a SQLiteBatch connected to this database */
 169      std::unique_ptr<DatabaseBatch> MakeBatch() override;
 170  
 171      /** Return true if there is an on-going txn in this connection */
 172      bool HasActiveTxn();
 173  
 174      sqlite3* m_db{nullptr};
 175      bool m_use_unsafe_sync;
 176  };
 177  
 178  /** An in-memory SQLiteDatabase. Used as a temporary build artifact where no
 179   *  on-disk persistence is needed. */
 180  class InMemoryWalletDatabase : public SQLiteDatabase
 181  {
 182  public:
 183      InMemoryWalletDatabase();
 184      std::vector<fs::path> Files() override { return {}; }
 185  };
 186  
 187  std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
 188  
 189  std::unique_ptr<WalletDatabase> MakeInMemoryWalletDatabase();
 190  
 191  std::string SQLiteDatabaseVersion();
 192  } // namespace wallet
 193  
 194  #endif // BITCOIN_WALLET_SQLITE_H
 195