/bitcoin/src/wallet/sqlite.h
Line | Count | Source |
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 | | explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range) |
33 | 210k | : m_prefix_range_start(std::move(start_range)), |
34 | 210k | m_prefix_range_end(std::move(end_range)) |
35 | 210k | {} |
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 | 181k | 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 | 181k | ~SQLiteBatch() override { Close(); } |
87 | | |
88 | 0 | 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 | 11.0k | 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 |