/root/bitcoin/src/wallet/sqlite.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2020-2021 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 | | 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 | 0 | explicit SQLiteCursor() = default; |
30 | | explicit SQLiteCursor(std::vector<std::byte> start_range, std::vector<std::byte> end_range) |
31 | 0 | : m_prefix_range_start(std::move(start_range)), |
32 | 0 | m_prefix_range_end(std::move(end_range)) |
33 | 0 | {} |
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 | 0 | 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 | 0 | ~SQLiteBatch() override { Close(); } |
85 | | |
86 | 0 | void SetExecHandler(std::unique_ptr<SQliteExecHandler>&& handler) { m_exec_handler = std::move(handler); } |
87 | | |
88 | | /* No-op. See comment on SQLiteDatabase::Flush */ |
89 | 0 | 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 | 0 | 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 std::string 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 | 0 | void AddRef() override { assert(false); } |
145 | 0 | 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 | 0 | void Flush() override {} |
163 | 0 | bool PeriodicFlush() override { return false; } |
164 | 0 | void ReloadDbEnv() override {} |
165 | | |
166 | 0 | void IncrementUpdateCounter() override { ++nUpdateCounter; } |
167 | | |
168 | 0 | std::string Filename() override { return m_file_path; } |
169 | 0 | std::string Format() override { return "sqlite"; } |
170 | | |
171 | | /** Make a SQLiteBatch connected to this database */ |
172 | | std::unique_ptr<DatabaseBatch> MakeBatch(bool flush_on_close = true) override; |
173 | | |
174 | | /** Return true if there is an on-going txn in this connection */ |
175 | | bool HasActiveTxn(); |
176 | | |
177 | | sqlite3* m_db{nullptr}; |
178 | | bool m_use_unsafe_sync; |
179 | | }; |
180 | | |
181 | | std::unique_ptr<SQLiteDatabase> MakeSQLiteDatabase(const fs::path& path, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error); |
182 | | |
183 | | std::string SQLiteDatabaseVersion(); |
184 | | } // namespace wallet |
185 | | |
186 | | #endif // BITCOIN_WALLET_SQLITE_H |