diff options
author | Aaron Seigo <aseigo@kde.org> | 2014-12-14 12:00:05 +0100 |
---|---|---|
committer | Aaron Seigo <aseigo@kde.org> | 2014-12-14 12:00:05 +0100 |
commit | 7cc25005b8c46d1fa783d33def2c6923e8ef8469 (patch) | |
tree | 64fa59d17af29838396cf37b912b3babd885e5dd /common/storage_unqlite.cpp | |
parent | bfc32f265e8ad72823db960fed371d72596003b7 (diff) | |
parent | a6ed70495f9f3ecb21c26860dda16aadcdc91c3a (diff) | |
download | sink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.tar.gz sink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.zip |
Merge branch 'unqlite'
Diffstat (limited to 'common/storage_unqlite.cpp')
-rw-r--r-- | common/storage_unqlite.cpp | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/common/storage_unqlite.cpp b/common/storage_unqlite.cpp new file mode 100644 index 0000000..5c5ef09 --- /dev/null +++ b/common/storage_unqlite.cpp | |||
@@ -0,0 +1,287 @@ | |||
1 | #include "storage.h" | ||
2 | |||
3 | #include <iostream> | ||
4 | |||
5 | #include <QAtomicInt> | ||
6 | #include <QDebug> | ||
7 | #include <QDir> | ||
8 | #include <QReadWriteLock> | ||
9 | #include <QString> | ||
10 | #include <QTime> | ||
11 | |||
12 | #include "unqlite/unqlite.h" | ||
13 | |||
14 | class Storage::Private | ||
15 | { | ||
16 | public: | ||
17 | Private(const QString &s, const QString &name, AccessMode m); | ||
18 | ~Private(); | ||
19 | |||
20 | void reportDbError(const char *functionName); | ||
21 | void reportDbError(const char *functionName, int errorCode, | ||
22 | const std::function<void(const Storage::Error &error)> &errorHandler); | ||
23 | |||
24 | QString storageRoot; | ||
25 | QString name; | ||
26 | AccessMode mode; | ||
27 | |||
28 | unqlite *db; | ||
29 | bool inTransaction; | ||
30 | }; | ||
31 | |||
32 | Storage::Private::Private(const QString &s, const QString &n, AccessMode m) | ||
33 | : storageRoot(s), | ||
34 | name(n), | ||
35 | mode(m), | ||
36 | db(0), | ||
37 | inTransaction(false) | ||
38 | { | ||
39 | const QString fullPath(storageRoot + '/' + name); | ||
40 | QDir dir; | ||
41 | dir.mkdir(storageRoot); | ||
42 | |||
43 | //create file | ||
44 | int openFlags = UNQLITE_OPEN_CREATE; | ||
45 | if (mode == ReadOnly) { | ||
46 | openFlags |= UNQLITE_OPEN_READONLY | UNQLITE_OPEN_MMAP; | ||
47 | } else { | ||
48 | openFlags |= UNQLITE_OPEN_READWRITE; | ||
49 | } | ||
50 | |||
51 | int rc = unqlite_open(&db, fullPath.toStdString().data(), openFlags); | ||
52 | |||
53 | if (rc != UNQLITE_OK) { | ||
54 | reportDbError("unqlite_open"); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | Storage::Private::~Private() | ||
59 | { | ||
60 | unqlite_close(db); | ||
61 | } | ||
62 | |||
63 | void Storage::Private::reportDbError(const char *functionName) | ||
64 | { | ||
65 | std::cerr << "ERROR: " << functionName; | ||
66 | if (db) { | ||
67 | const char *errorMessage; | ||
68 | int length; | ||
69 | /* Something goes wrong, extract database error log */ | ||
70 | unqlite_config(db, UNQLITE_CONFIG_ERR_LOG, &errorMessage, &length); | ||
71 | if (length > 0) { | ||
72 | std::cerr << ": " << errorMessage; | ||
73 | } | ||
74 | } | ||
75 | std::cerr << std::endl; | ||
76 | } | ||
77 | |||
78 | void Storage::Private::reportDbError(const char *functionName, int errorCode, | ||
79 | const std::function<void(const Storage::Error &error)> &errorHandler) | ||
80 | { | ||
81 | if (db) { | ||
82 | const char *errorMessage; | ||
83 | int length; | ||
84 | /* Something goes wrong, extract database error log */ | ||
85 | unqlite_config(db, UNQLITE_CONFIG_ERR_LOG, &errorMessage, &length); | ||
86 | if (length > 0) { | ||
87 | Error error(name.toStdString(), errorCode, errorMessage); | ||
88 | errorHandler(error); | ||
89 | return; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | Error error(name.toStdString(), errorCode, functionName); | ||
94 | errorHandler(error); | ||
95 | } | ||
96 | |||
97 | Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode) | ||
98 | : d(new Private(storageRoot, name, mode)) | ||
99 | { | ||
100 | } | ||
101 | |||
102 | Storage::~Storage() | ||
103 | { | ||
104 | if (d->inTransaction) { | ||
105 | abortTransaction(); | ||
106 | } | ||
107 | |||
108 | delete d; | ||
109 | } | ||
110 | |||
111 | bool Storage::isInTransaction() const | ||
112 | { | ||
113 | return d->inTransaction; | ||
114 | } | ||
115 | |||
116 | bool Storage::startTransaction(AccessMode type) | ||
117 | { | ||
118 | if (!d->db) { | ||
119 | return false; | ||
120 | } | ||
121 | |||
122 | if (d->inTransaction) { | ||
123 | return true; | ||
124 | } | ||
125 | |||
126 | d->inTransaction = unqlite_begin(d->db) == UNQLITE_OK; | ||
127 | |||
128 | if (!d->inTransaction) { | ||
129 | d->reportDbError("unqlite_begin"); | ||
130 | } | ||
131 | |||
132 | return d->inTransaction; | ||
133 | } | ||
134 | |||
135 | bool Storage::commitTransaction() | ||
136 | { | ||
137 | if (!d->db) { | ||
138 | return false; | ||
139 | } | ||
140 | |||
141 | if (!d->inTransaction) { | ||
142 | return true; | ||
143 | } | ||
144 | |||
145 | int rc = unqlite_commit(d->db); | ||
146 | d->inTransaction = false; | ||
147 | |||
148 | if (rc != UNQLITE_OK) { | ||
149 | d->reportDbError("unqlite_commit"); | ||
150 | } | ||
151 | |||
152 | return rc == UNQLITE_OK; | ||
153 | } | ||
154 | |||
155 | void Storage::abortTransaction() | ||
156 | { | ||
157 | if (!d->db || !d->inTransaction) { | ||
158 | return; | ||
159 | } | ||
160 | |||
161 | unqlite_rollback(d->db); | ||
162 | d->inTransaction = false; | ||
163 | } | ||
164 | |||
165 | bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize) | ||
166 | { | ||
167 | return write(std::string(key, keySize), std::string(value, valueSize)); | ||
168 | } | ||
169 | |||
170 | bool Storage::write(const std::string &sKey, const std::string &sValue) | ||
171 | { | ||
172 | if (!d->db) { | ||
173 | return false; | ||
174 | } | ||
175 | |||
176 | int rc = unqlite_kv_store(d->db, sKey.data(), -1, sValue.data(), sValue.size()); | ||
177 | |||
178 | if (rc != UNQLITE_OK) { | ||
179 | d->reportDbError("unqlite_kv_store"); | ||
180 | } | ||
181 | |||
182 | return !rc; | ||
183 | } | ||
184 | |||
185 | void Storage::read(const std::string &sKey, | ||
186 | const std::function<bool(const std::string &value)> &resultHandler, | ||
187 | const std::function<void(const Storage::Error &error)> &errorHandler) | ||
188 | { | ||
189 | read(sKey, | ||
190 | [&](void *ptr, int size) -> bool { | ||
191 | if (ptr) { | ||
192 | const std::string resultValue(static_cast<char*>(ptr), size); | ||
193 | return resultHandler(resultValue); | ||
194 | } | ||
195 | |||
196 | return true; | ||
197 | }, errorHandler); | ||
198 | } | ||
199 | |||
200 | void Storage::read(const std::string &sKey, | ||
201 | const std::function<bool(void *ptr, int size)> &resultHandler, | ||
202 | const std::function<void(const Storage::Error &error)> &errorHandler) | ||
203 | { | ||
204 | scan(sKey.data(), sKey.size(), [resultHandler](void *keyPtr, int keySize, void *valuePtr, int valueSize) { | ||
205 | return resultHandler(valuePtr, valueSize); | ||
206 | }, errorHandler); | ||
207 | } | ||
208 | |||
209 | void fetchCursorData(unqlite_kv_cursor *cursor, | ||
210 | void **keyBuffer, int *keyBufferLength, void **dataBuffer, unqlite_int64 *dataBufferLength, | ||
211 | const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler) | ||
212 | { | ||
213 | int keyLength = 0; | ||
214 | unqlite_int64 dataLength = 0; | ||
215 | // now fetch the data sizes | ||
216 | if (unqlite_kv_cursor_key(cursor, nullptr, &keyLength) == UNQLITE_OK && | ||
217 | unqlite_kv_cursor_data(cursor, nullptr, &dataLength) == UNQLITE_OK) { | ||
218 | if (keyLength > *keyBufferLength) { | ||
219 | *keyBuffer = realloc(*keyBuffer, keyLength); | ||
220 | *keyBufferLength = keyLength; | ||
221 | } | ||
222 | |||
223 | if (dataLength > *dataBufferLength) { | ||
224 | *dataBuffer = realloc(*dataBuffer, dataLength); | ||
225 | *dataBufferLength = dataLength; | ||
226 | } | ||
227 | |||
228 | if (unqlite_kv_cursor_key(cursor, *keyBuffer, &keyLength) == UNQLITE_OK && | ||
229 | unqlite_kv_cursor_data(cursor, *dataBuffer, &dataLength) == UNQLITE_OK) { | ||
230 | resultHandler(*keyBuffer, keyLength, *dataBuffer, dataLength); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | void Storage::scan(const char *keyData, uint keySize, | ||
236 | const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler, | ||
237 | const std::function<void(const Storage::Error &error)> &errorHandler) | ||
238 | { | ||
239 | if (!d->db) { | ||
240 | Error error(d->name.toStdString(), -1, "Not open"); | ||
241 | errorHandler(error); | ||
242 | return; | ||
243 | } | ||
244 | |||
245 | unqlite_kv_cursor *cursor; | ||
246 | |||
247 | int rc = unqlite_kv_cursor_init(d->db, &cursor); | ||
248 | if (rc != UNQLITE_OK) { | ||
249 | d->reportDbError("unqlite_kv_cursor_init", rc, errorHandler); | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | void *keyBuffer = nullptr; | ||
254 | int keyBufferLength = 0; | ||
255 | void *dataBuffer = nullptr; | ||
256 | //FIXME: 64bit ints, but feeding int lenghts to the callbacks. can result in truncation | ||
257 | unqlite_int64 dataBufferLength = 0; | ||
258 | if (!keyData || keySize == 0) { | ||
259 | for (unqlite_kv_cursor_first_entry(cursor); unqlite_kv_cursor_valid_entry(cursor); unqlite_kv_cursor_next_entry(cursor)) { | ||
260 | fetchCursorData(cursor, &keyBuffer, &keyBufferLength, &dataBuffer, &dataBufferLength, resultHandler); | ||
261 | } | ||
262 | } else { | ||
263 | rc = unqlite_kv_cursor_seek(cursor, keyData, keySize, UNQLITE_CURSOR_MATCH_EXACT); | ||
264 | if (rc == UNQLITE_OK) { | ||
265 | fetchCursorData(cursor, &keyBuffer, &keyBufferLength, &dataBuffer, &dataBufferLength, resultHandler); | ||
266 | } else { | ||
267 | std::cout << "couldn't find value " << std::string(keyData, keySize) << std::endl; | ||
268 | } | ||
269 | |||
270 | } | ||
271 | |||
272 | free(keyBuffer); | ||
273 | free(dataBuffer); | ||
274 | unqlite_kv_cursor_release(d->db, cursor); | ||
275 | } | ||
276 | |||
277 | qint64 Storage::diskUsage() const | ||
278 | { | ||
279 | QFileInfo info(d->storageRoot + '/' + d->name); | ||
280 | return info.size(); | ||
281 | } | ||
282 | |||
283 | void Storage::removeFromDisk() const | ||
284 | { | ||
285 | QFile::remove(d->storageRoot + '/' + d->name); | ||
286 | } | ||
287 | |||