summaryrefslogtreecommitdiffstats
path: root/common/storage_lmdb.cpp
diff options
context:
space:
mode:
authorMinijackson <minijackson@riseup.net>2018-08-21 12:03:40 +0200
committerMinijackson <minijackson@riseup.net>2018-08-21 14:04:56 +0200
commit23e13c91e44e9d1fcbe2215f16d10117de4d0e84 (patch)
tree6e341ca4bcb94499a9b9631b7b3499a691d30b79 /common/storage_lmdb.cpp
parent40fbc56ba745322ed75ac12c5551ce6b9bcb1cc4 (diff)
downloadsink-23e13c91e44e9d1fcbe2215f16d10117de4d0e84.tar.gz
sink-23e13c91e44e9d1fcbe2215f16d10117de4d0e84.zip
Separate UIDs and revisions
Diffstat (limited to 'common/storage_lmdb.cpp')
-rw-r--r--common/storage_lmdb.cpp99
1 files changed, 77 insertions, 22 deletions
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp
index a007405..e3377b2 100644
--- a/common/storage_lmdb.cpp
+++ b/common/storage_lmdb.cpp
@@ -48,6 +48,10 @@ static QMutex sCreateDbiLock;
48static QHash<QString, MDB_env *> sEnvironments; 48static QHash<QString, MDB_env *> sEnvironments;
49static QHash<QString, MDB_dbi> sDbis; 49static QHash<QString, MDB_dbi> sDbis;
50 50
51int AllowDuplicates = MDB_DUPSORT;
52int IntegerKeys = MDB_INTEGERKEY;
53int IntegerValues = MDB_INTEGERDUP;
54
51int getErrorCode(int e) 55int getErrorCode(int e)
52{ 56{
53 switch (e) { 57 switch (e) {
@@ -101,14 +105,8 @@ static QList<QByteArray> getDatabaseNames(MDB_txn *transaction)
101 * and we always need to commit the transaction ASAP 105 * and we always need to commit the transaction ASAP
102 * We can only ever enter from one point per process. 106 * We can only ever enter from one point per process.
103 */ 107 */
104static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly, bool allowDuplicates, MDB_dbi &dbi) 108static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly, int flags, MDB_dbi &dbi)
105{ 109{
106
107 unsigned int flags = 0;
108 if (allowDuplicates) {
109 flags |= MDB_DUPSORT;
110 }
111
112 MDB_dbi flagtableDbi; 110 MDB_dbi flagtableDbi;
113 if (const int rc = mdb_dbi_open(transaction, "__flagtable", readOnly ? 0 : MDB_CREATE, &flagtableDbi)) { 111 if (const int rc = mdb_dbi_open(transaction, "__flagtable", readOnly ? 0 : MDB_CREATE, &flagtableDbi)) {
114 if (!readOnly) { 112 if (!readOnly) {
@@ -130,6 +128,10 @@ static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly,
130 } 128 }
131 } 129 }
132 130
131 if (flags & IntegerValues && !(flags & AllowDuplicates)) {
132 SinkWarning() << "Opening a database with integer values, but not duplicate keys";
133 }
134
133 if (const int rc = mdb_dbi_open(transaction, db.constData(), flags, &dbi)) { 135 if (const int rc = mdb_dbi_open(transaction, db.constData(), flags, &dbi)) {
134 //Create the db if it is not existing already 136 //Create the db if it is not existing already
135 if (rc == MDB_NOTFOUND && !readOnly) { 137 if (rc == MDB_NOTFOUND && !readOnly) {
@@ -165,7 +167,7 @@ static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly,
165 //Store the flags without the create option 167 //Store the flags without the create option
166 const auto ba = QByteArray::number(flags); 168 const auto ba = QByteArray::number(flags);
167 value.mv_data = const_cast<void*>(static_cast<const void*>(ba.constData())); 169 value.mv_data = const_cast<void*>(static_cast<const void*>(ba.constData()));
168 value.mv_size = db.size(); 170 value.mv_size = ba.size();
169 if (const int rc = mdb_put(transaction, flagtableDbi, &key, &value, MDB_NOOVERWRITE)) { 171 if (const int rc = mdb_put(transaction, flagtableDbi, &key, &value, MDB_NOOVERWRITE)) {
170 //We expect this to fail if we're only creating the dbi but not the db 172 //We expect this to fail if we're only creating the dbi but not the db
171 if (rc != MDB_KEYEXIST) { 173 if (rc != MDB_KEYEXIST) {
@@ -175,7 +177,7 @@ static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly,
175 } else { 177 } else {
176 //It's not an error if we only want to read 178 //It's not an error if we only want to read
177 if (!readOnly) { 179 if (!readOnly) {
178 SinkWarning() << "Failed to open db " << QByteArray(mdb_strerror(rc)); 180 SinkWarning() << "Failed to open db " << db << "error:" << QByteArray(mdb_strerror(rc));
179 return true; 181 return true;
180 } 182 }
181 return false; 183 return false;
@@ -187,8 +189,14 @@ static bool createDbi(MDB_txn *transaction, const QByteArray &db, bool readOnly,
187class DataStore::NamedDatabase::Private 189class DataStore::NamedDatabase::Private
188{ 190{
189public: 191public:
190 Private(const QByteArray &_db, bool _allowDuplicates, const std::function<void(const DataStore::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_txn *_txn) 192 Private(const QByteArray &_db, int _flags,
191 : db(_db), transaction(_txn), allowDuplicates(_allowDuplicates), defaultErrorHandler(_defaultErrorHandler), name(_name) 193 const std::function<void(const DataStore::Error &error)> &_defaultErrorHandler,
194 const QString &_name, MDB_txn *_txn)
195 : db(_db),
196 transaction(_txn),
197 flags(_flags),
198 defaultErrorHandler(_defaultErrorHandler),
199 name(_name)
192 { 200 {
193 } 201 }
194 202
@@ -199,7 +207,7 @@ public:
199 QByteArray db; 207 QByteArray db;
200 MDB_txn *transaction; 208 MDB_txn *transaction;
201 MDB_dbi dbi; 209 MDB_dbi dbi;
202 bool allowDuplicates; 210 int flags;
203 std::function<void(const DataStore::Error &error)> defaultErrorHandler; 211 std::function<void(const DataStore::Error &error)> defaultErrorHandler;
204 QString name; 212 QString name;
205 bool createdNewDbi = false; 213 bool createdNewDbi = false;
@@ -313,7 +321,7 @@ public:
313 } else { 321 } else {
314 dbiTransaction = transaction; 322 dbiTransaction = transaction;
315 } 323 }
316 if (createDbi(dbiTransaction, db, readOnly, allowDuplicates, dbi)) { 324 if (createDbi(dbiTransaction, db, readOnly, flags, dbi)) {
317 if (readOnly) { 325 if (readOnly) {
318 mdb_txn_commit(dbiTransaction); 326 mdb_txn_commit(dbiTransaction);
319 Q_ASSERT(!sDbis.contains(dbiName)); 327 Q_ASSERT(!sDbis.contains(dbiName));
@@ -371,6 +379,13 @@ DataStore::NamedDatabase::~NamedDatabase()
371 delete d; 379 delete d;
372} 380}
373 381
382bool DataStore::NamedDatabase::write(const size_t key, const QByteArray &value,
383 const std::function<void(const DataStore::Error &error)> &errorHandler)
384{
385 auto baKey = QByteArray::fromRawData(reinterpret_cast<const char *>(&key), sizeof(key));
386 return write(baKey, value, errorHandler);
387}
388
374bool DataStore::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sValue, const std::function<void(const DataStore::Error &error)> &errorHandler) 389bool DataStore::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sValue, const std::function<void(const DataStore::Error &error)> &errorHandler)
375{ 390{
376 if (!d || !d->transaction) { 391 if (!d || !d->transaction) {
@@ -407,11 +422,25 @@ bool DataStore::NamedDatabase::write(const QByteArray &sKey, const QByteArray &s
407 return !rc; 422 return !rc;
408} 423}
409 424
425void DataStore::NamedDatabase::remove(
426 const size_t key, const std::function<void(const DataStore::Error &error)> &errorHandler)
427{
428 auto baKey = QByteArray::fromRawData(reinterpret_cast<const char *>(&key), sizeof(key));
429 return remove(baKey, errorHandler);
430}
431
410void DataStore::NamedDatabase::remove(const QByteArray &k, const std::function<void(const DataStore::Error &error)> &errorHandler) 432void DataStore::NamedDatabase::remove(const QByteArray &k, const std::function<void(const DataStore::Error &error)> &errorHandler)
411{ 433{
412 remove(k, QByteArray(), errorHandler); 434 remove(k, QByteArray(), errorHandler);
413} 435}
414 436
437void DataStore::NamedDatabase::remove(const size_t key, const QByteArray &value,
438 const std::function<void(const DataStore::Error &error)> &errorHandler)
439{
440 auto baKey = QByteArray::fromRawData(reinterpret_cast<const char *>(&key), sizeof(key));
441 return remove(baKey, value, errorHandler);
442}
443
415void DataStore::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler) 444void DataStore::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler)
416{ 445{
417 if (!d || !d->transaction) { 446 if (!d || !d->transaction) {
@@ -445,6 +474,19 @@ void DataStore::NamedDatabase::remove(const QByteArray &k, const QByteArray &val
445 } 474 }
446} 475}
447 476
477int DataStore::NamedDatabase::scan(const size_t key,
478 const std::function<bool(size_t key, const QByteArray &value)> &resultHandler,
479 const std::function<void(const DataStore::Error &error)> &errorHandler, bool skipInternalKeys) const
480{
481 auto baKey = QByteArray::fromRawData(reinterpret_cast<const char *>(&key), sizeof(key));
482 return scan(baKey,
483 [&resultHandler](const QByteArray &key, const QByteArray &value) {
484 size_t integerKey = *reinterpret_cast<const size_t *>(key.constData());
485 return resultHandler(integerKey, value);
486 },
487 errorHandler, /* findSubstringKeys = */ false, skipInternalKeys);
488}
489
448int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler, 490int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler,
449 const std::function<void(const DataStore::Error &error)> &errorHandler, bool findSubstringKeys, bool skipInternalKeys) const 491 const std::function<void(const DataStore::Error &error)> &errorHandler, bool findSubstringKeys, bool skipInternalKeys) const
450{ 492{
@@ -471,8 +513,10 @@ int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool
471 513
472 int numberOfRetrievedValues = 0; 514 int numberOfRetrievedValues = 0;
473 515
474 if (k.isEmpty() || d->allowDuplicates || findSubstringKeys) { 516 bool allowDuplicates = d->flags & AllowDuplicates;
475 MDB_cursor_op op = d->allowDuplicates ? MDB_SET : MDB_FIRST; 517
518 if (k.isEmpty() || allowDuplicates || findSubstringKeys) {
519 MDB_cursor_op op = allowDuplicates ? MDB_SET : MDB_FIRST;
476 if (findSubstringKeys) { 520 if (findSubstringKeys) {
477 op = MDB_SET_RANGE; 521 op = MDB_SET_RANGE;
478 } 522 }
@@ -490,7 +534,7 @@ int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool
490 key.mv_data = (void *)k.constData(); 534 key.mv_data = (void *)k.constData();
491 key.mv_size = k.size(); 535 key.mv_size = k.size();
492 } 536 }
493 MDB_cursor_op nextOp = (d->allowDuplicates && !findSubstringKeys) ? MDB_NEXT_DUP : MDB_NEXT; 537 MDB_cursor_op nextOp = (allowDuplicates && !findSubstringKeys) ? MDB_NEXT_DUP : MDB_NEXT;
494 while ((rc = mdb_cursor_get(cursor, &key, &data, nextOp)) == 0) { 538 while ((rc = mdb_cursor_get(cursor, &key, &data, nextOp)) == 0) {
495 const auto current = QByteArray::fromRawData((char *)key.mv_data, key.mv_size); 539 const auto current = QByteArray::fromRawData((char *)key.mv_data, key.mv_size);
496 // Every consequitive lookup simply iterates through the list 540 // Every consequitive lookup simply iterates through the list
@@ -602,6 +646,15 @@ void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::functi
602 return; 646 return;
603} 647}
604 648
649int DataStore::NamedDatabase::findAllInRange(const size_t lowerBound, const size_t upperBound,
650 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler,
651 const std::function<void(const DataStore::Error &error)> &errorHandler) const
652{
653 auto baLowerBound = QByteArray::fromRawData(reinterpret_cast<const char *>(&lowerBound), sizeof(size_t));
654 auto baUpperBound = QByteArray::fromRawData(reinterpret_cast<const char *>(&upperBound), sizeof(size_t));
655 return findAllInRange(baLowerBound, baUpperBound, resultHandler, errorHandler);
656}
657
605int DataStore::NamedDatabase::findAllInRange(const QByteArray &lowerBound, const QByteArray &upperBound, 658int DataStore::NamedDatabase::findAllInRange(const QByteArray &lowerBound, const QByteArray &upperBound,
606 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 659 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler,
607 const std::function<void(const DataStore::Error &error)> &errorHandler) const 660 const std::function<void(const DataStore::Error &error)> &errorHandler) const
@@ -862,7 +915,8 @@ static bool ensureCorrectDb(DataStore::NamedDatabase &database, const QByteArray
862 return !openedTheWrongDatabase; 915 return !openedTheWrongDatabase;
863} 916}
864 917
865DataStore::NamedDatabase DataStore::Transaction::openDatabase(const QByteArray &db, const std::function<void(const DataStore::Error &error)> &errorHandler, bool allowDuplicates) const 918DataStore::NamedDatabase DataStore::Transaction::openDatabase(const QByteArray &db,
919 const std::function<void(const DataStore::Error &error)> &errorHandler, int flags) const
866{ 920{
867 if (!d) { 921 if (!d) {
868 SinkError() << "Tried to open database on invalid transaction: " << db; 922 SinkError() << "Tried to open database on invalid transaction: " << db;
@@ -871,7 +925,8 @@ DataStore::NamedDatabase DataStore::Transaction::openDatabase(const QByteArray &
871 Q_ASSERT(d->transaction); 925 Q_ASSERT(d->transaction);
872 // We don't now if anything changed 926 // We don't now if anything changed
873 d->implicitCommit = true; 927 d->implicitCommit = true;
874 auto p = new DataStore::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction); 928 auto p = new DataStore::NamedDatabase::Private(
929 db, flags, d->defaultErrorHandler, d->name, d->transaction);
875 auto ret = p->openDatabase(d->requestedRead, errorHandler); 930 auto ret = p->openDatabase(d->requestedRead, errorHandler);
876 if (!ret) { 931 if (!ret) {
877 delete p; 932 delete p;
@@ -1049,11 +1104,11 @@ public:
1049 1104
1050 //Create dbis from the given layout. 1105 //Create dbis from the given layout.
1051 for (auto it = layout.tables.constBegin(); it != layout.tables.constEnd(); it++) { 1106 for (auto it = layout.tables.constBegin(); it != layout.tables.constEnd(); it++) {
1052 const bool allowDuplicates = it.value(); 1107 const int flags = it.value();
1053 MDB_dbi dbi = 0; 1108 MDB_dbi dbi = 0;
1054 const auto db = it.key(); 1109 const auto db = it.key();
1055 const auto dbiName = name + db; 1110 const auto dbiName = name + db;
1056 if (createDbi(transaction, db, readOnly, allowDuplicates, dbi)) { 1111 if (createDbi(transaction, db, readOnly, flags, dbi)) {
1057 sDbis.insert(dbiName, dbi); 1112 sDbis.insert(dbiName, dbi);
1058 } 1113 }
1059 } 1114 }
@@ -1063,8 +1118,8 @@ public:
1063 MDB_dbi dbi = 0; 1118 MDB_dbi dbi = 0;
1064 const auto dbiName = name + db; 1119 const auto dbiName = name + db;
1065 //We're going to load the flags anyways. 1120 //We're going to load the flags anyways.
1066 bool allowDuplicates = false; 1121 const int flags = 0;
1067 if (createDbi(transaction, db, readOnly, allowDuplicates, dbi)) { 1122 if (createDbi(transaction, db, readOnly, flags, dbi)) {
1068 sDbis.insert(dbiName, dbi); 1123 sDbis.insert(dbiName, dbi);
1069 } 1124 }
1070 } 1125 }