summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Seigo <aseigo@kde.org>2014-12-14 11:59:39 +0100
committerAaron Seigo <aseigo@kde.org>2014-12-14 11:59:39 +0100
commita6ed70495f9f3ecb21c26860dda16aadcdc91c3a (patch)
tree5304b9fdd7fea14dcc49faea77c0ecc848a7525f
parent8969c46cf96884c7304a01b8b7822c1936ab215e (diff)
downloadsink-a6ed70495f9f3ecb21c26860dda16aadcdc91c3a.tar.gz
sink-a6ed70495f9f3ecb21c26860dda16aadcdc91c3a.zip
and now unqlite storage works
-rw-r--r--common/CMakeLists.txt8
-rw-r--r--common/storage_unqlite.cpp252
2 files changed, 164 insertions, 96 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index 8e8af1f..a2fd57a 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -4,11 +4,12 @@ generate_flatbuffers(commands/handshake
4 4
5if (STORAGE_unqlite) 5if (STORAGE_unqlite)
6 add_definitions(-DUNQLITE_ENABLE_THREADS) 6 add_definitions(-DUNQLITE_ENABLE_THREADS)
7 set(storage_SRCS storage_unqlite.cpp unqlite/*c) 7 file(GLOB storage_SRCS unqlite/*c)
8else (STORAGE_KYOTO) 8 set(storage_SRCS ${storage_SRCS} storage_unqlite.cpp)
9else (STORAGE_unqlite)
9 set(storage_SRCS storage_lmdb.cpp) 10 set(storage_SRCS storage_lmdb.cpp)
10 set(storage_LIBS lmdb) 11 set(storage_LIBS lmdb)
11endif (STORAGE_KYOTO) 12endif (STORAGE_unqlite)
12 13
13set(command_SRCS 14set(command_SRCS
14 commands.cpp 15 commands.cpp
@@ -16,6 +17,7 @@ set(command_SRCS
16 storage_common.cpp 17 storage_common.cpp
17 ${storage_SRCS}) 18 ${storage_SRCS})
18 19
20message("We have: ${storage_SRCS}")
19add_library(${PROJECT_NAME} ${command_SRCS}) 21add_library(${PROJECT_NAME} ${command_SRCS})
20SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX) 22SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
21qt5_use_modules(${PROJECT_NAME} Widgets) 23qt5_use_modules(${PROJECT_NAME} Widgets)
diff --git a/common/storage_unqlite.cpp b/common/storage_unqlite.cpp
index d0eaa38..5c5ef09 100644
--- a/common/storage_unqlite.cpp
+++ b/common/storage_unqlite.cpp
@@ -5,51 +5,93 @@
5#include <QAtomicInt> 5#include <QAtomicInt>
6#include <QDebug> 6#include <QDebug>
7#include <QDir> 7#include <QDir>
8#include <QFileInfo>
9#include <QReadWriteLock> 8#include <QReadWriteLock>
10#include <QString> 9#include <QString>
11#include <QTime> 10#include <QTime>
12 11
13#include <unqlite/unqlite.h> 12#include "unqlite/unqlite.h"
14 13
15class Storage::Private 14class Storage::Private
16{ 15{
17public: 16public:
18 Private(const QString &storageRoot, const QString &name, AccessMode m); 17 Private(const QString &s, const QString &name, AccessMode m);
19 ~Private(); 18 ~Private();
20 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;
21 QString name; 25 QString name;
22 kyotocabinet::TreeDB db;
23 AccessMode mode; 26 AccessMode mode;
24 bool dbOpen; 27
28 unqlite *db;
25 bool inTransaction; 29 bool inTransaction;
26}; 30};
27 31
28Storage::Private::Private(const QString &storageRoot, const QString &n, AccessMode m) 32Storage::Private::Private(const QString &s, const QString &n, AccessMode m)
29 : name(n), 33 : storageRoot(s),
34 name(n),
30 mode(m), 35 mode(m),
31 dbOpen(false), 36 db(0),
32 inTransaction(false) 37 inTransaction(false)
33{ 38{
39 const QString fullPath(storageRoot + '/' + name);
34 QDir dir; 40 QDir dir;
35 dir.mkdir(storageRoot); 41 dir.mkdir(storageRoot);
36 42
37 //create file 43 //create file
38 uint32_t openMode = kyotocabinet::BasicDB::OCREATE | 44 int openFlags = UNQLITE_OPEN_CREATE;
39 (mode == ReadOnly ? kyotocabinet::BasicDB::OREADER 45 if (mode == ReadOnly) {
40 : kyotocabinet::BasicDB::OWRITER); 46 openFlags |= UNQLITE_OPEN_READONLY | UNQLITE_OPEN_MMAP;
41 dbOpen = db.open((storageRoot + "/" + name + ".kch").toStdString(), openMode); 47 } else {
42 if (!dbOpen) { 48 openFlags |= UNQLITE_OPEN_READWRITE;
43 std::cerr << "Could not open database: " << db.error().codename(db.error().code()) << " " << db.error().message() << std::endl; 49 }
44 // TODO: handle error 50
51 int rc = unqlite_open(&db, fullPath.toStdString().data(), openFlags);
52
53 if (rc != UNQLITE_OK) {
54 reportDbError("unqlite_open");
45 } 55 }
46} 56}
47 57
48Storage::Private::~Private() 58Storage::Private::~Private()
49{ 59{
50 if (dbOpen && inTransaction) { 60 unqlite_close(db);
51 db.end_transaction(false); 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 }
52 } 91 }
92
93 Error error(name.toStdString(), errorCode, functionName);
94 errorHandler(error);
53} 95}
54 96
55Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode) 97Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode)
@@ -59,6 +101,10 @@ Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mod
59 101
60Storage::~Storage() 102Storage::~Storage()
61{ 103{
104 if (d->inTransaction) {
105 abortTransaction();
106 }
107
62 delete d; 108 delete d;
63} 109}
64 110
@@ -69,11 +115,7 @@ bool Storage::isInTransaction() const
69 115
70bool Storage::startTransaction(AccessMode type) 116bool Storage::startTransaction(AccessMode type)
71{ 117{
72 if (!d->dbOpen) { 118 if (!d->db) {
73 return false;
74 }
75
76 if (type == ReadWrite && d->mode != ReadWrite) {
77 return false; 119 return false;
78 } 120 }
79 121
@@ -81,141 +123,165 @@ bool Storage::startTransaction(AccessMode type)
81 return true; 123 return true;
82 } 124 }
83 125
84 //TODO handle errors 126 d->inTransaction = unqlite_begin(d->db) == UNQLITE_OK;
85 d->inTransaction = d->db.begin_transaction(); 127
128 if (!d->inTransaction) {
129 d->reportDbError("unqlite_begin");
130 }
131
86 return d->inTransaction; 132 return d->inTransaction;
87} 133}
88 134
89bool Storage::commitTransaction() 135bool Storage::commitTransaction()
90{ 136{
91 if (!d->dbOpen) { 137 if (!d->db) {
92 return false; 138 return false;
93 } 139 }
94 140
95 if (!d->inTransaction) { 141 if (!d->inTransaction) {
96 return false; 142 return true;
97 } 143 }
98 144
99 bool success = d->db.end_transaction(true); 145 int rc = unqlite_commit(d->db);
100 d->inTransaction = false; 146 d->inTransaction = false;
101 return success; 147
148 if (rc != UNQLITE_OK) {
149 d->reportDbError("unqlite_commit");
150 }
151
152 return rc == UNQLITE_OK;
102} 153}
103 154
104void Storage::abortTransaction() 155void Storage::abortTransaction()
105{ 156{
106 if (!d->dbOpen || !d->inTransaction) { 157 if (!d->db || !d->inTransaction) {
107 return; 158 return;
108 } 159 }
109 160
110 d->db.end_transaction(false); 161 unqlite_rollback(d->db);
111 d->inTransaction = false; 162 d->inTransaction = false;
112} 163}
113 164
114bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize) 165bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize)
115{ 166{
116 if (!d->dbOpen) { 167 return write(std::string(key, keySize), std::string(value, valueSize));
117 return false;
118 }
119
120 bool success = d->db.set(key, keySize, value, valueSize);
121 return success;
122} 168}
123 169
124bool Storage::write(const std::string &sKey, const std::string &sValue) 170bool Storage::write(const std::string &sKey, const std::string &sValue)
125{ 171{
126 if (!d->dbOpen) { 172 if (!d->db) {
127 return false; 173 return false;
128 } 174 }
129 175
130 bool success = d->db.set(sKey, sValue); 176 int rc = unqlite_kv_store(d->db, sKey.data(), -1, sValue.data(), sValue.size());
131 return success; 177
178 if (rc != UNQLITE_OK) {
179 d->reportDbError("unqlite_kv_store");
180 }
181
182 return !rc;
132} 183}
133 184
134void Storage::read(const std::string &sKey, 185void Storage::read(const std::string &sKey,
135 const std::function<bool(const std::string &value)> &resultHandler, 186 const std::function<bool(const std::string &value)> &resultHandler,
136 const std::function<void(const Storage::Error &error)> &errorHandler) 187 const std::function<void(const Storage::Error &error)> &errorHandler)
137{ 188{
138 if (!d->dbOpen) { 189 read(sKey,
139 Error error(d->name.toStdString(), -1, "Not open"); 190 [&](void *ptr, int size) -> bool {
140 errorHandler(error); 191 if (ptr) {
141 return; 192 const std::string resultValue(static_cast<char*>(ptr), size);
142 } 193 return resultHandler(resultValue);
194 }
143 195
144 std::string value; 196 return true;
145 if (sKey.empty()) { 197 }, errorHandler);
146 kyotocabinet::DB::Cursor *cursor = d->db.cursor(); 198}
147 cursor->jump();
148 199
149 std::string key, value; 200void Storage::read(const std::string &sKey,
150 while (cursor->get_value(&value, true) && resultHandler(value)) {} 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}
151 208
152 delete cursor; 209void fetchCursorData(unqlite_kv_cursor *cursor,
153 return; 210 void **keyBuffer, int *keyBufferLength, void **dataBuffer, unqlite_int64 *dataBufferLength,
154 } else { 211 const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler)
155 if (d->db.get(sKey, &value)) { 212{
156 resultHandler(value); 213 int keyLength = 0;
157 return; 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;
158 } 221 }
159 }
160 222
161 Error error(d->name.toStdString(), d->db.error().code(), d->db.error().message()); 223 if (dataLength > *dataBufferLength) {
162 errorHandler(error); 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 }
163} 233}
164 234
165void Storage::read(const std::string &sKey, 235void Storage::scan(const char *keyData, uint keySize,
166 const std::function<bool(void *ptr, int size)> &resultHandler, 236 const std::function<bool(void *keyPtr, int keySize, void *valuePtr, int valueSize)> &resultHandler,
167 const std::function<void(const Storage::Error &error)> &errorHandler) 237 const std::function<void(const Storage::Error &error)> &errorHandler)
168{ 238{
169 if (!d->dbOpen) { 239 if (!d->db) {
170 Error error(d->name.toStdString(), -1, "Not open"); 240 Error error(d->name.toStdString(), -1, "Not open");
171 errorHandler(error); 241 errorHandler(error);
172 return; 242 return;
173 } 243 }
174 244
175 size_t valueSize; 245 unqlite_kv_cursor *cursor;
176 char *valueBuffer;
177 if (sKey.empty()) {
178 kyotocabinet::DB::Cursor *cursor = d->db.cursor();
179 cursor->jump();
180 246
181 while ((valueBuffer = cursor->get_value(&valueSize, true))) { 247 int rc = unqlite_kv_cursor_init(d->db, &cursor);
182 bool ok = resultHandler(valueBuffer, valueSize); 248 if (rc != UNQLITE_OK) {
183 delete[] valueBuffer; 249 d->reportDbError("unqlite_kv_cursor_init", rc, errorHandler);
184 if (!ok) { 250 return;
185 break; 251 }
186 }
187 }
188 252
189 delete cursor; 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 }
190 } else { 262 } else {
191 valueBuffer = d->db.get(sKey.data(), sKey.size(), &valueSize); 263 rc = unqlite_kv_cursor_seek(cursor, keyData, keySize, UNQLITE_CURSOR_MATCH_EXACT);
192 if (valueBuffer) { 264 if (rc == UNQLITE_OK) {
193 resultHandler(valueBuffer, valueSize); 265 fetchCursorData(cursor, &keyBuffer, &keyBufferLength, &dataBuffer, &dataBufferLength, resultHandler);
194 } else { 266 } else {
195 Error error(d->name.toStdString(), d->db.error().code(), d->db.error().message()); 267 std::cout << "couldn't find value " << std::string(keyData, keySize) << std::endl;
196 errorHandler(error);
197 } 268 }
198 delete[] valueBuffer; 269
199 } 270 }
271
272 free(keyBuffer);
273 free(dataBuffer);
274 unqlite_kv_cursor_release(d->db, cursor);
200} 275}
201 276
202qint64 Storage::diskUsage() const 277qint64 Storage::diskUsage() const
203{ 278{
204 if (!d->dbOpen) { 279 QFileInfo info(d->storageRoot + '/' + d->name);
205 return 0;
206 }
207
208 QFileInfo info(QString::fromStdString(d->db.path()));
209 return info.size(); 280 return info.size();
210} 281}
211 282
212void Storage::removeFromDisk() const 283void Storage::removeFromDisk() const
213{ 284{
214 if (!d->dbOpen) { 285 QFile::remove(d->storageRoot + '/' + d->name);
215 return;
216 }
217
218 QFileInfo info(QString::fromStdString(d->db.path()));
219 QDir dir = info.dir();
220 dir.remove(info.fileName());
221} 286}
287