Line data Source code
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 0 : explicit SQLiteCursor() = default;
32 0 : explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range)
33 0 : : m_prefix_range_start(std::move(start_range)),
34 0 : m_prefix_range_end(std::move(end_range))
35 0 : {}
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 0 : class SQliteExecHandler
44 : {
45 : public:
46 0 : 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 : bool ReadKey(DataStream&& key, DataStream& value) override;
79 : bool WriteKey(DataStream&& key, DataStream&& value, bool overwrite = true) override;
80 : bool EraseKey(DataStream&& key) override;
81 : bool HasKey(DataStream&& key) override;
82 : bool ErasePrefix(std::span<const std::byte> prefix) override;
83 :
84 : public:
85 : explicit SQLiteBatch(SQLiteDatabase& database);
86 0 : ~SQLiteBatch() override { Close(); }
87 :
88 : void SetExecHandler(std::unique_ptr<SQliteExecHandler>&& handler) { m_exec_handler = std::move(handler); }
89 :
90 : void Close() override;
91 :
92 : std::unique_ptr<DatabaseCursor> GetNewCursor() override;
93 : std::unique_ptr<DatabaseCursor> GetNewPrefixCursor(std::span<const std::byte> prefix) override;
94 : bool TxnBegin() override;
95 : bool TxnCommit() override;
96 : bool TxnAbort() override;
97 0 : bool HasActiveTxn() override { return m_txn; }
98 : };
99 :
100 : /** An instance of this class represents one SQLite3 database.
101 : **/
102 : class SQLiteDatabase : public WalletDatabase
103 : {
104 : private:
105 : const bool m_mock{false};
106 :
107 : const std::string m_dir_path;
108 :
109 : const std::string m_file_path;
110 :
111 : /**
112 : * This mutex protects SQLite initialization and shutdown.
113 : * sqlite3_config() and sqlite3_shutdown() are not thread-safe (sqlite3_initialize() is).
114 : * Concurrent threads that execute SQLiteDatabase::SQLiteDatabase() should have just one
115 : * of them do the init and the rest wait for it to complete before all can proceed.
116 : */
117 : static Mutex g_sqlite_mutex;
118 : static int g_sqlite_count GUARDED_BY(g_sqlite_mutex);
119 :
120 : void Cleanup() noexcept EXCLUSIVE_LOCKS_REQUIRED(!g_sqlite_mutex);
121 :
122 : public:
123 : SQLiteDatabase() = delete;
124 :
125 : /** Create DB handle to real database */
126 : SQLiteDatabase(const fs::path& dir_path, const fs::path& file_path, const DatabaseOptions& options, bool mock = false);
127 :
128 : ~SQLiteDatabase();
129 :
130 : // Batches must acquire this semaphore on writing, and release when done writing.
131 : // This ensures that only one batch is modifying the database at a time.
132 : std::binary_semaphore m_write_semaphore;
133 :
134 : bool Verify(bilingual_str& error);
135 :
136 : /** Open the database if it is not already opened */
137 : void Open() override;
138 :
139 : /** Close the database */
140 : void Close() override;
141 :
142 : /** Rewrite the entire database on disk */
143 : bool Rewrite(const char* skip = nullptr) override;
144 :
145 : /** Back up the entire database to a file.
146 : */
147 : bool Backup(const std::string& dest) const override;
148 :
149 0 : std::string Filename() override { return m_file_path; }
150 0 : std::string Format() override { return "sqlite"; }
151 :
152 : /** Make a SQLiteBatch connected to this database */
153 : std::unique_ptr<DatabaseBatch> MakeBatch() override;
154 :
155 : /** Return true if there is an on-going txn in this connection */
156 : bool HasActiveTxn();
157 :
158 : sqlite3* m_db{nullptr};
159 : bool m_use_unsafe_sync;
160 : };
161 :
162 : std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
163 :
164 : std::string SQLiteDatabaseVersion();
165 : } // namespace wallet
166 :
167 : #endif // BITCOIN_WALLET_SQLITE_H
|