Directory: | cvmfs/ |
---|---|
File: | cvmfs/sql_impl.h |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 220 | 252 | 87.3% |
Branches: | 207 | 451 | 45.9% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM file system. | ||
3 | */ | ||
4 | |||
5 | #ifndef CVMFS_SQL_IMPL_H_ | ||
6 | #define CVMFS_SQL_IMPL_H_ | ||
7 | |||
8 | #include <fcntl.h> | ||
9 | |||
10 | #include <cassert> | ||
11 | #include <cerrno> | ||
12 | #include <string> | ||
13 | |||
14 | #include "sqlitemem.h" | ||
15 | #include "util/logging.h" | ||
16 | #include "util/platform.h" | ||
17 | |||
18 | namespace sqlite { | ||
19 | |||
20 | template <class DerivedT> | ||
21 | 443 | Database<DerivedT>::Database(const std::string &filename, | |
22 | const OpenMode open_mode) | ||
23 | 443 | : database_(filename, this) | |
24 | 443 | , read_write_(kOpenReadWrite == open_mode) | |
25 | 443 | , schema_version_(0.0f) | |
26 |
5/10✓ Branch 2 taken 443 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 443 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 443 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 443 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 443 times.
✗ Branch 15 not taken.
|
886 | , schema_revision_(0) {} |
27 | |||
28 | |||
29 | template <class DerivedT> | ||
30 | 228 | DerivedT* Database<DerivedT>::Create(const std::string &filename) { | |
31 |
3/6✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 228 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 116 times.
✗ Branch 8 not taken.
|
228 | UniquePtr<DerivedT> database(new DerivedT(filename, kOpenReadWrite)); |
32 | |||
33 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 228 times.
|
228 | if (!database.IsValid()) { |
34 | ✗ | LogCvmfs(kLogSql, kLogDebug, "Failed to create new database object"); | |
35 | ✗ | return NULL; | |
36 | } | ||
37 | |||
38 | 228 | database->set_schema_version(DerivedT::kLatestSchema); | |
39 | 228 | database->set_schema_revision(DerivedT::kLatestSchemaRevision); | |
40 | |||
41 | 228 | const int open_flags = SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE | | |
42 | SQLITE_OPEN_CREATE; | ||
43 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
|
228 | if (!database->OpenDatabase(open_flags)) { |
44 | ✗ | LogCvmfs(kLogSql, kLogDebug, "Failed to create new database file"); | |
45 | ✗ | return NULL; | |
46 | } | ||
47 | |||
48 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
|
228 | if (!database->CreatePropertiesTable()) { |
49 | ✗ | database->PrintSqlError("Failed to create common properties table"); | |
50 | ✗ | return NULL; | |
51 | } | ||
52 | |||
53 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
|
228 | if (!database->CreateEmptyDatabase()) { |
54 | ✗ | database->PrintSqlError("Failed to create empty database"); | |
55 | ✗ | return NULL; | |
56 | } | ||
57 | |||
58 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
|
228 | if (!database->PrepareCommonQueries()) { |
59 | ✗ | database->PrintSqlError("Failed to initialize properties queries"); | |
60 | ✗ | return NULL; | |
61 | } | ||
62 | |||
63 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
|
228 | if (!database->StoreSchemaRevision()) { |
64 | ✗ | database->PrintSqlError("Failed to store initial schema revision"); | |
65 | ✗ | return NULL; | |
66 | } | ||
67 | |||
68 | 228 | return database.Release(); | |
69 | 228 | } | |
70 | |||
71 | |||
72 | template <class DerivedT> | ||
73 | 215 | DerivedT* Database<DerivedT>::Open(const std::string &filename, | |
74 | const OpenMode open_mode) { | ||
75 |
3/6✓ Branch 1 taken 215 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 215 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 177 times.
✗ Branch 8 not taken.
|
215 | UniquePtr<DerivedT> database(new DerivedT(filename, open_mode)); |
76 | |||
77 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 215 times.
|
215 | if (!database.IsValid()) { |
78 | ✗ | LogCvmfs(kLogSql, kLogDebug, | |
79 | "Failed to open database file '%s' - errno: %d", | ||
80 | ✗ | filename.c_str(), errno); | |
81 | ✗ | return NULL; | |
82 | } | ||
83 | |||
84 |
3/4✓ Branch 2 taken 215 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 211 times.
|
215 | if (!database->Initialize()) { |
85 | 4 | return NULL; | |
86 | } | ||
87 | |||
88 | 211 | return database.Release(); | |
89 | 215 | } | |
90 | |||
91 | |||
92 | template <class DerivedT> | ||
93 | 215 | bool Database<DerivedT>::Initialize() { | |
94 |
2/2✓ Branch 0 taken 127 times.
✓ Branch 1 taken 88 times.
|
215 | const int flags = (read_write_) ? SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE |
95 | : SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READONLY; | ||
96 | |||
97 |
0/2✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
215 | bool successful = OpenDatabase(flags) && |
98 |
1/2✓ Branch 1 taken 213 times.
✗ Branch 2 not taken.
|
213 | Configure() && |
99 |
3/4✓ Branch 0 taken 213 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 213 times.
✗ Branch 4 not taken.
|
641 | FileReadAhead() && |
100 |
1/2✓ Branch 1 taken 213 times.
✗ Branch 2 not taken.
|
213 | PrepareCommonQueries(); |
101 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 213 times.
|
215 | if (!successful) { |
102 | 2 | LogCvmfs(kLogSql, kLogDebug, "failed to open database file '%s'", | |
103 | 2 | filename().c_str()); | |
104 | 2 | return false; | |
105 | } | ||
106 | |||
107 | 213 | ReadSchemaRevision(); | |
108 | 213 | LogCvmfs(kLogSql, kLogDebug, "opened database with schema version %f " | |
109 | "and revision %u", | ||
110 | 213 | schema_version_, schema_revision_); | |
111 | |||
112 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 212 times.
|
213 | if (!static_cast<DerivedT*>(this)->CheckSchemaCompatibility()) { |
113 | 2 | LogCvmfs(kLogSql, kLogDebug, "schema version %f not supported (%s)", | |
114 | 1 | schema_version_, filename().c_str()); | |
115 | 1 | return false; | |
116 | } | ||
117 | |||
118 |
4/4✓ Branch 0 taken 126 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 211 times.
|
338 | if (read_write_ && |
119 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 125 times.
|
126 | !static_cast<DerivedT*>(this)->LiveSchemaUpgradeIfNecessary()) { |
120 | 1 | LogCvmfs(kLogSql, kLogDebug, "failed tp upgrade schema revision"); | |
121 | 1 | return false; | |
122 | } | ||
123 | |||
124 | 211 | return true; | |
125 | } | ||
126 | |||
127 | |||
128 | template <class DerivedT> | ||
129 | 443 | bool Database<DerivedT>::OpenDatabase(const int flags) { | |
130 | // Open database file (depending on the flags read-only or read-write) | ||
131 | 443 | LogCvmfs(kLogSql, kLogDebug, "opening database file %s", | |
132 | 443 | filename().c_str()); | |
133 | 443 | int retval = sqlite3_open_v2(filename().c_str(), | |
134 | &database_.sqlite_db, | ||
135 | flags | SQLITE_OPEN_EXRESCODE, | ||
136 | NULL); | ||
137 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 441 times.
|
443 | if (retval != SQLITE_OK) { |
138 | 2 | LogCvmfs(kLogSql, kLogDebug, "cannot open database file %s (%d - %d)", | |
139 | 2 | filename().c_str(), retval, errno); | |
140 | 2 | return false; | |
141 | } | ||
142 | |||
143 | 441 | return true; | |
144 | } | ||
145 | |||
146 | |||
147 | template <class DerivedT> | ||
148 | 476 | Database<DerivedT>::DatabaseRaiiWrapper::~DatabaseRaiiWrapper() { | |
149 |
1/2✓ Branch 0 taken 440 times.
✗ Branch 1 not taken.
|
476 | if (NULL != sqlite_db) { |
150 | 476 | const bool close_successful = Close(); | |
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
|
476 | assert(close_successful); |
152 | } | ||
153 | 476 | } | |
154 | |||
155 | |||
156 | template <class DerivedT> | ||
157 | 476 | bool Database<DerivedT>::DatabaseRaiiWrapper::Close() { | |
158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
|
476 | assert(NULL != sqlite_db); |
159 | |||
160 |
2/2✓ Branch 0 taken 103 times.
✓ Branch 1 taken 337 times.
|
952 | LogCvmfs(kLogSql, kLogDebug, "closing SQLite database '%s' (unlink: %s)", |
161 | 476 | filename().c_str(), | |
162 | 476 | (db_file_guard.IsEnabled() ? "yes" : "no")); | |
163 | 476 | const int result = sqlite3_close(sqlite_db); | |
164 | |||
165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 440 times.
|
476 | if (result != SQLITE_OK) { |
166 | ✗ | LogCvmfs(kLogSql, kLogDebug, | |
167 | "failed to close SQLite database '%s' (%d - %s)", | ||
168 | ✗ | filename().c_str(), result, | |
169 | ✗ | delegate_->GetLastErrorMsg().c_str()); | |
170 | ✗ | return false; | |
171 | } | ||
172 | |||
173 | 476 | sqlite_db = NULL; | |
174 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 406 times.
|
476 | if (lookaside_buffer != NULL) { |
175 | 34 | SqliteMemoryManager::GetInstance()->ReleaseLookasideBuffer( | |
176 | lookaside_buffer); | ||
177 | 34 | lookaside_buffer = NULL; | |
178 | } | ||
179 | 476 | return true; | |
180 | } | ||
181 | |||
182 | |||
183 | template <class DerivedT> | ||
184 | 213 | bool Database<DerivedT>::Configure() { | |
185 | // Read-only databases should store temporary files in memory. This avoids | ||
186 | // unexpected open read-write file descriptors in the cache directory like | ||
187 | // etilqs_<number>. They also use the optimized memory manager, if it is | ||
188 | // available. | ||
189 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 127 times.
|
213 | if (!read_write_) { |
190 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 52 times.
|
86 | if (SqliteMemoryManager::HasInstance()) { |
191 | 34 | database_.lookaside_buffer = | |
192 | 34 | SqliteMemoryManager::GetInstance()->AssignLookasideBuffer(sqlite_db()); | |
193 | } | ||
194 | |||
195 |
7/22✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 86 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 86 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 86 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 86 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 86 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 86 times.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
|
258 | return Sql(sqlite_db() , "PRAGMA temp_store=2;").Execute() && |
196 |
9/24✓ Branch 2 taken 86 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 86 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 86 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 86 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 86 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 86 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 86 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 86 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 86 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
|
172 | Sql(sqlite_db() , "PRAGMA locking_mode=EXCLUSIVE;").Execute(); |
197 | } | ||
198 | 127 | return true; | |
199 | } | ||
200 | |||
201 | |||
202 | template <class DerivedT> | ||
203 | 213 | bool Database<DerivedT>::FileReadAhead() { | |
204 | // Read-ahead into file system buffers | ||
205 | // TODO(jblomer): mmap, re-readahead | ||
206 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 213 times.
|
213 | assert(filename().length() > 1); |
207 | int fd_readahead; | ||
208 |
2/2✓ Branch 2 taken 179 times.
✓ Branch 3 taken 34 times.
|
213 | if (filename()[0] != '@') { |
209 | 179 | fd_readahead = open(filename().c_str(), O_RDONLY); | |
210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 179 times.
|
179 | if (fd_readahead < 0) { |
211 | ✗ | LogCvmfs(kLogSql, kLogDebug, "failed to open %s for read-ahead (%d)", | |
212 | ✗ | filename().c_str(), errno); | |
213 | ✗ | return false; | |
214 | } | ||
215 | 179 | const ssize_t retval = platform_readahead(fd_readahead); | |
216 | 179 | close(fd_readahead); | |
217 | |||
218 | // Read-ahead is known to fail on tmpfs with EINVAL | ||
219 | // EINVAL = "readahead() cannot be applied to that a file type" | ||
220 | // Don't consider it a fatal error. | ||
221 |
2/4✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 179 times.
|
179 | if (retval != 0 && errno != EINVAL) { |
222 | ✗ | LogCvmfs(kLogSql, kLogDebug | kLogSyslogWarn, | |
223 | "failed to read-ahead %s: invalid file descrp. or not open for reading", | ||
224 | ✗ | filename().c_str()); | |
225 | ✗ | return false; | |
226 | } | ||
227 | } | ||
228 | |||
229 | 213 | return true; | |
230 | } | ||
231 | |||
232 | |||
233 | template <class DerivedT> | ||
234 | 441 | bool Database<DerivedT>::PrepareCommonQueries() { | |
235 | 441 | sqlite3 *db = sqlite_db(); | |
236 |
4/8✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 441 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 441 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 441 times.
✗ Branch 12 not taken.
|
441 | begin_transaction_ = new Sql(db, "BEGIN;"); |
237 |
4/8✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 441 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 441 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 441 times.
✗ Branch 12 not taken.
|
441 | commit_transaction_ = new Sql(db, "COMMIT;"); |
238 |
4/8✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 441 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 441 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 441 times.
✗ Branch 12 not taken.
|
441 | has_property_ = new Sql(db, "SELECT count(*) FROM properties " |
239 | "WHERE key = :key;"); | ||
240 |
4/8✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 441 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 441 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 441 times.
✗ Branch 12 not taken.
|
441 | get_property_ = new Sql(db, "SELECT value FROM properties " |
241 | "WHERE key = :key;"); | ||
242 |
4/8✓ Branch 2 taken 441 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 441 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 441 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 441 times.
✗ Branch 12 not taken.
|
441 | set_property_ = new Sql(db, "INSERT OR REPLACE INTO properties " |
243 | "(key, value) VALUES (:key, :value);"); | ||
244 |
1/2✓ Branch 1 taken 441 times.
✗ Branch 2 not taken.
|
882 | return (begin_transaction_.IsValid() && |
245 |
1/2✓ Branch 1 taken 441 times.
✗ Branch 2 not taken.
|
882 | commit_transaction_.IsValid() && |
246 |
1/2✓ Branch 1 taken 441 times.
✗ Branch 2 not taken.
|
882 | has_property_.IsValid() && |
247 |
2/4✓ Branch 0 taken 441 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 441 times.
✗ Branch 4 not taken.
|
1323 | get_property_.IsValid() && |
248 | 882 | set_property_.IsValid()); | |
249 | } | ||
250 | |||
251 | |||
252 | template <class DerivedT> | ||
253 | 213 | void Database<DerivedT>::ReadSchemaRevision() { | |
254 |
2/4✓ Branch 2 taken 213 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 213 times.
✗ Branch 6 not taken.
|
426 | schema_version_ = (this->HasProperty(kSchemaVersionKey)) |
255 |
5/15✓ Branch 0 taken 213 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 213 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 213 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 213 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 213 times.
✗ Branch 13 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
213 | ? this->GetProperty<double>(kSchemaVersionKey) |
256 | : 1.0; | ||
257 |
2/4✓ Branch 2 taken 213 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 213 times.
✗ Branch 6 not taken.
|
426 | schema_revision_ = (this->HasProperty(kSchemaRevisionKey)) |
258 |
8/15✓ Branch 0 taken 208 times.
✓ Branch 1 taken 5 times.
✓ Branch 4 taken 208 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 208 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 208 times.
✓ Branch 10 taken 5 times.
✓ Branch 12 taken 208 times.
✓ Branch 13 taken 5 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
|
213 | ? this->GetProperty<int>(kSchemaRevisionKey) |
259 | : 0; | ||
260 | 213 | } | |
261 | |||
262 | |||
263 | template <class DerivedT> | ||
264 | 250 | bool Database<DerivedT>::StoreSchemaRevision() { | |
265 |
4/14✓ Branch 2 taken 250 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 250 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 250 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 250 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
750 | return this->SetProperty(kSchemaVersionKey, schema_version_) && |
266 |
6/17✓ Branch 2 taken 250 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 250 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 250 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 250 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 250 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 250 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
|
750 | this->SetProperty(kSchemaRevisionKey, schema_revision_); |
267 | } | ||
268 | |||
269 | |||
270 | template <class DerivedT> | ||
271 | 206 | bool Database<DerivedT>::BeginTransaction() const { | |
272 |
2/4✓ Branch 2 taken 203 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
409 | return begin_transaction_->Execute() && |
273 |
1/2✓ Branch 2 taken 203 times.
✗ Branch 3 not taken.
|
409 | begin_transaction_->Reset(); |
274 | } | ||
275 | |||
276 | |||
277 | template <class DerivedT> | ||
278 | 195 | bool Database<DerivedT>::CommitTransaction() const { | |
279 |
1/4✓ Branch 2 taken 195 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
390 | return commit_transaction_->Execute() && |
280 |
1/2✓ Branch 2 taken 195 times.
✗ Branch 3 not taken.
|
390 | commit_transaction_->Reset(); |
281 | } | ||
282 | |||
283 | |||
284 | template <class DerivedT> | ||
285 | 228 | bool Database<DerivedT>::CreatePropertiesTable() { | |
286 |
3/6✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 228 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 228 times.
✗ Branch 9 not taken.
|
456 | return Sql(sqlite_db(), |
287 | "CREATE TABLE properties (key TEXT, value TEXT, " | ||
288 |
1/2✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
|
456 | "CONSTRAINT pk_properties PRIMARY KEY (key));").Execute(); |
289 | } | ||
290 | |||
291 | |||
292 | template <class DerivedT> | ||
293 | 1050 | bool Database<DerivedT>::HasProperty(const std::string &key) const { | |
294 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1050 times.
|
1050 | assert(has_property_.IsValid()); |
295 |
1/4✓ Branch 2 taken 1050 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
2100 | const bool retval = has_property_->BindText(1, key) && |
296 |
1/2✓ Branch 2 taken 1050 times.
✗ Branch 3 not taken.
|
1050 | has_property_->FetchRow(); |
297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1050 times.
|
1050 | assert(retval); |
298 | 1050 | const bool result = has_property_->RetrieveInt64(0) > 0; | |
299 | 1050 | has_property_->Reset(); | |
300 | 1050 | return result; | |
301 | } | ||
302 | |||
303 | template <class DerivedT> | ||
304 | template <typename T> | ||
305 | 1500 | T Database<DerivedT>::GetProperty(const std::string &key) const { | |
306 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 750 times.
|
1500 | assert(get_property_.IsValid()); |
307 |
1/4✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3000 | const bool retval = get_property_->BindText(1, key) && |
308 |
1/2✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
|
1500 | get_property_->FetchRow(); |
309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 750 times.
|
1500 | assert(retval); |
310 | 1500 | const T result = get_property_->Retrieve<T>(0); | |
311 |
1/2✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
|
1500 | get_property_->Reset(); |
312 | 1500 | return result; | |
313 | } | ||
314 | |||
315 | template <class DerivedT> | ||
316 | template <typename T> | ||
317 | 614 | T Database<DerivedT>::GetPropertyDefault(const std::string &key, | |
318 | const T default_value) const { | ||
319 |
2/2✓ Branch 1 taken 133 times.
✓ Branch 2 taken 169 times.
|
614 | return (HasProperty(key)) ? GetProperty<T>(key) |
320 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
614 | : default_value; |
321 | } | ||
322 | |||
323 | template <class DerivedT> | ||
324 | template <typename T> | ||
325 | 2278 | bool Database<DerivedT>::SetProperty(const std::string &key, | |
326 | const T value) { | ||
327 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1153 times.
|
2278 | assert(set_property_.IsValid()); |
328 |
0/2✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2278 | return set_property_->BindText(1, key) && |
329 |
1/2✓ Branch 2 taken 1153 times.
✗ Branch 3 not taken.
|
2278 | set_property_->Bind(2, value) && |
330 |
2/4✓ Branch 0 taken 1153 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1153 times.
✗ Branch 5 not taken.
|
6834 | set_property_->Execute() && |
331 |
1/2✓ Branch 2 taken 1153 times.
✗ Branch 3 not taken.
|
4556 | set_property_->Reset(); |
332 | } | ||
333 | |||
334 | template <class DerivedT> | ||
335 | ✗ | std::string Database<DerivedT>::GetLastErrorMsg() const { | |
336 | ✗ | std::string msg = sqlite3_errmsg(sqlite_db()); | |
337 | ✗ | return msg; | |
338 | } | ||
339 | |||
340 | |||
341 | template <class DerivedT> | ||
342 | 107 | void Database<DerivedT>::TakeFileOwnership() { | |
343 | 107 | database_.TakeFileOwnership(); | |
344 | 107 | LogCvmfs(kLogSql, kLogDebug, "Database object took ownership of '%s'", | |
345 | 107 | database_.filename().c_str()); | |
346 | 107 | } | |
347 | |||
348 | |||
349 | template <class DerivedT> | ||
350 | 4 | void Database<DerivedT>::DropFileOwnership() { | |
351 | 4 | database_.DropFileOwnership(); | |
352 | 4 | LogCvmfs(kLogSql, kLogDebug, "Database object dropped ownership of '%s'", | |
353 | 4 | database_.filename().c_str()); | |
354 | 4 | } | |
355 | |||
356 | |||
357 | template <class DerivedT> | ||
358 | 11 | unsigned Database<DerivedT>::GetModifiedRowCount() const { | |
359 | 11 | const int modified_rows = sqlite3_total_changes(sqlite_db()); | |
360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | assert(modified_rows >= 0); |
361 | 11 | return static_cast<unsigned>(modified_rows); | |
362 | } | ||
363 | |||
364 | /** | ||
365 | * Ask SQlite for per-connection memory statistics | ||
366 | */ | ||
367 | template <class DerivedT> | ||
368 | 1 | void Database<DerivedT>::GetMemStatistics(MemStatistics *stats) const { | |
369 | 1 | const int reset = 0; | |
370 | int current; | ||
371 | int highwater; | ||
372 | 1 | int retval = SQLITE_OK; | |
373 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_USED, |
374 | ¤t, &highwater, reset); | ||
375 | 1 | stats->lookaside_slots_used = current; | |
376 | 1 | stats->lookaside_slots_max = highwater; | |
377 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_HIT, |
378 | ¤t, &highwater, reset); | ||
379 | 1 | stats->lookaside_hit = highwater; | |
380 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, |
381 | ¤t, &highwater, reset); | ||
382 | 1 | stats->lookaside_miss_size = highwater; | |
383 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, |
384 | ¤t, &highwater, reset); | ||
385 | 1 | stats->lookaside_miss_full = highwater; | |
386 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_USED, |
387 | ¤t, &highwater, reset); | ||
388 | 1 | stats->page_cache_used = current; | |
389 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_HIT, |
390 | ¤t, &highwater, reset); | ||
391 | 1 | stats->page_cache_hit = current; | |
392 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_CACHE_MISS, |
393 | ¤t, &highwater, reset); | ||
394 | 1 | stats->page_cache_miss = current; | |
395 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_SCHEMA_USED, |
396 | ¤t, &highwater, reset); | ||
397 | 1 | stats->schema_used = current; | |
398 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | retval |= sqlite3_db_status(sqlite_db(), SQLITE_DBSTATUS_STMT_USED, |
399 | ¤t, &highwater, reset); | ||
400 | 1 | stats->stmt_used = current; | |
401 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(retval == SQLITE_OK); |
402 | 1 | } | |
403 | |||
404 | |||
405 | template <class DerivedT> | ||
406 | 58 | double Database<DerivedT>::GetFreePageRatio() const { | |
407 |
3/6✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 58 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 58 times.
✗ Branch 9 not taken.
|
116 | Sql free_page_count_query(this->sqlite_db(), "PRAGMA freelist_count;"); |
408 |
3/6✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 58 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 58 times.
✗ Branch 9 not taken.
|
116 | Sql page_count_query(this->sqlite_db(), "PRAGMA page_count;"); |
409 | |||
410 |
2/4✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
|
116 | const bool retval = page_count_query.FetchRow() && |
411 |
2/4✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
|
58 | free_page_count_query.FetchRow(); |
412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | assert(retval); |
413 | |||
414 |
1/2✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
|
58 | int64_t pages = page_count_query.RetrieveInt64(0); |
415 |
1/2✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
|
58 | int64_t free_pages = free_page_count_query.RetrieveInt64(0); |
416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
|
58 | assert(pages > 0); |
417 | |||
418 | 58 | return (static_cast<double>(free_pages) / static_cast<double>(pages)); | |
419 | 58 | } | |
420 | |||
421 | |||
422 | template <class DerivedT> | ||
423 | 18 | bool Database<DerivedT>::Vacuum() const { | |
424 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | assert(read_write_); |
425 |
3/4✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
|
35 | return static_cast<const DerivedT*>(this)->CompactDatabase() && |
426 |
11/22✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 17 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 17 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 17 times.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 17 times.
✓ Branch 19 taken 1 times.
✓ Branch 21 taken 17 times.
✓ Branch 22 taken 1 times.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
|
35 | Sql(this->sqlite_db(), "VACUUM;").Execute(); |
427 | } | ||
428 | |||
429 | |||
430 | template <class DerivedT> | ||
431 | ✗ | void Database<DerivedT>::PrintSqlError(const std::string &error_msg) { | |
432 | ✗ | LogCvmfs(kLogSql, kLogStderr, "%s\nSQLite said: '%s'", | |
433 | error_msg.c_str(), this->GetLastErrorMsg().c_str()); | ||
434 | } | ||
435 | |||
436 | template <class DerivedT> | ||
437 | const float Database<DerivedT>::kSchemaEpsilon = 0.0005; | ||
438 | template <class DerivedT> | ||
439 | const char *Database<DerivedT>::kSchemaVersionKey = "schema"; | ||
440 | template <class DerivedT> | ||
441 | const char *Database<DerivedT>::kSchemaRevisionKey = "schema_revision"; | ||
442 | |||
443 | |||
444 | // | ||
445 | // # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | ||
446 | // | ||
447 | |||
448 | |||
449 | template <> | ||
450 | 101 | inline bool Sql::Bind(const int index, const int &value) { | |
451 | 101 | return this->BindInt64(index, value); | |
452 | } | ||
453 | |||
454 | template <> | ||
455 | 270 | inline bool Sql::Bind(const int index, const unsigned int &value) { | |
456 | 270 | return this->BindInt64(index, static_cast<int>(value)); | |
457 | } | ||
458 | |||
459 | template <> | ||
460 | 283 | inline bool Sql::Bind(const int index, const uint64_t &value) { | |
461 | 283 | return this->BindInt64(index, static_cast<int64_t>(value)); | |
462 | } | ||
463 | |||
464 | template <> | ||
465 | inline bool Sql::Bind(const int index, const sqlite3_int64 &value) { | ||
466 | return this->BindInt64(index, value); | ||
467 | } | ||
468 | |||
469 | template <> | ||
470 | 245 | inline bool Sql::Bind(const int index, const std::string &value) { | |
471 | 245 | return this->BindTextTransient(index, value); | |
472 | } | ||
473 | |||
474 | template <> | ||
475 | 250 | inline bool Sql::Bind(const int index, const float &value) { | |
476 | 250 | return this->BindDouble(index, value); | |
477 | } | ||
478 | |||
479 | template <> | ||
480 | 4 | inline bool Sql::Bind(const int index, const double &value) { | |
481 | 4 | return this->BindDouble(index, value); | |
482 | } | ||
483 | |||
484 | |||
485 | template <> | ||
486 | 275 | inline int Sql::Retrieve(const int index) { | |
487 | 275 | return static_cast<int>(this->RetrieveInt64(index)); | |
488 | } | ||
489 | |||
490 | template <> | ||
491 | ✗ | inline bool Sql::Retrieve(const int index) { | |
492 | ✗ | return static_cast<bool>(this->RetrieveInt(index)); | |
493 | } | ||
494 | |||
495 | template <> | ||
496 | inline sqlite3_int64 Sql::Retrieve(const int index) { | ||
497 | return this->RetrieveInt64(index); | ||
498 | } | ||
499 | |||
500 | template <> | ||
501 | 129 | inline uint64_t Sql::Retrieve(const int index) { | |
502 | 129 | return static_cast<uint64_t>(this->RetrieveInt64(index)); | |
503 | } | ||
504 | |||
505 | template <> | ||
506 | 156 | inline std::string Sql::Retrieve(const int index) { | |
507 | 156 | return RetrieveString(index); | |
508 | } | ||
509 | |||
510 | template <> | ||
511 | 4 | inline float Sql::Retrieve(const int index) { | |
512 | 4 | return static_cast<float>(this->RetrieveDouble(index)); | |
513 | } | ||
514 | |||
515 | template <> | ||
516 | 217 | inline double Sql::Retrieve(const int index) { | |
517 | 217 | return this->RetrieveDouble(index); | |
518 | } | ||
519 | |||
520 | } // namespace sqlite | ||
521 | |||
522 | #endif // CVMFS_SQL_IMPL_H_ | ||
523 |