sqlite.h raw

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