summaryrefslogtreecommitdiffstats
path: root/common/storage_unqlite.cpp
diff options
context:
space:
mode:
authorAaron Seigo <aseigo@kde.org>2014-12-14 12:00:05 +0100
committerAaron Seigo <aseigo@kde.org>2014-12-14 12:00:05 +0100
commit7cc25005b8c46d1fa783d33def2c6923e8ef8469 (patch)
tree64fa59d17af29838396cf37b912b3babd885e5dd /common/storage_unqlite.cpp
parentbfc32f265e8ad72823db960fed371d72596003b7 (diff)
parenta6ed70495f9f3ecb21c26860dda16aadcdc91c3a (diff)
downloadsink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.tar.gz
sink-7cc25005b8c46d1fa783d33def2c6923e8ef8469.zip
Merge branch 'unqlite'
Diffstat (limited to 'common/storage_unqlite.cpp')
-rw-r--r--common/storage_unqlite.cpp287
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
14class Storage::Private
15{
16public:
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
32Storage::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
58Storage::Private::~Private()
59{
60 unqlite_close(db);
61}
62
63void 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
78void 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
97Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode)
98 : d(new Private(storageRoot, name, mode))
99{
100}
101
102Storage::~Storage()
103{
104 if (d->inTransaction) {
105 abortTransaction();
106 }
107
108 delete d;
109}
110
111bool Storage::isInTransaction() const
112{
113 return d->inTransaction;
114}
115
116bool 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
135bool 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
155void Storage::abortTransaction()
156{
157 if (!d->db || !d->inTransaction) {
158 return;
159 }
160
161 unqlite_rollback(d->db);
162 d->inTransaction = false;
163}
164
165bool 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
170bool 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
185void 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
200void 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
209void 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
235void 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
277qint64 Storage::diskUsage() const
278{
279 QFileInfo info(d->storageRoot + '/' + d->name);
280 return info.size();
281}
282
283void Storage::removeFromDisk() const
284{
285 QFile::remove(d->storageRoot + '/' + d->name);
286}
287