summaryrefslogtreecommitdiffstats
path: root/common/storage_lmdb.cpp
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-10-16 14:55:20 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-10-21 09:02:21 +0200
commit237b9ae4113e7a9f489632296941becb71afdb45 (patch)
tree01cde58f495944f01cad9d282391d4efd2897141 /common/storage_lmdb.cpp
parent95d11bf0be98a4e3c08502fe23417b800233ce14 (diff)
downloadsink-237b9ae4113e7a9f489632296941becb71afdb45.tar.gz
sink-237b9ae4113e7a9f489632296941becb71afdb45.zip
Refactor how the storage is used.
This is the initial refactoring to improve how we deal with the storage. It does a couple of things: * Rename Sink::Storage to Sink::Storage::DataStore to free up the Sink::Storage namespace * Introduce a Sink::ResourceContext to have a single object that can be passed around containing everything that is necessary to operate on a resource. This is a lot better than the multiple separate parameters that we used to pass around all over the place, while still allowing for dependency injection for tests. * Tie storage access together using the new EntityStore that directly works with ApplicationDomainTypes. This gives us a central place where main storage, indexes and buffer adaptors are tied together, which will also give us a place to implement external indexes, such as a fulltextindex using xapian. * Use ApplicationDomainTypes as the default way to pass around entities. Instead of using various ways to pass around entities (buffers, buffer adaptors, ApplicationDomainTypes), only use a single way. The old approach was confusing, and was only done as: * optimization; really shouldn't be necessary and otherwise I'm sure we can find better ways to optimize ApplicationDomainType itself. * a way to account for entities that have multiple buffers, a concept that I no longer deem relevant. While this commit does the bulk of the work to get there, the following commits will refactor more stuff to get things back to normal.
Diffstat (limited to 'common/storage_lmdb.cpp')
-rw-r--r--common/storage_lmdb.cpp100
1 files changed, 51 insertions, 49 deletions
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp
index 6f11af3..e418472 100644
--- a/common/storage_lmdb.cpp
+++ b/common/storage_lmdb.cpp
@@ -39,6 +39,7 @@ SINK_DEBUG_AREA("storage")
39// SINK_DEBUG_COMPONENT(d->storageRoot.toLatin1() + '/' + d->name.toLatin1()) 39// SINK_DEBUG_COMPONENT(d->storageRoot.toLatin1() + '/' + d->name.toLatin1())
40 40
41namespace Sink { 41namespace Sink {
42namespace Storage {
42 43
43QMutex sMutex; 44QMutex sMutex;
44QHash<QString, MDB_env *> sEnvironments; 45QHash<QString, MDB_env *> sEnvironments;
@@ -47,17 +48,17 @@ int getErrorCode(int e)
47{ 48{
48 switch (e) { 49 switch (e) {
49 case MDB_NOTFOUND: 50 case MDB_NOTFOUND:
50 return Storage::ErrorCodes::NotFound; 51 return DataStore::ErrorCodes::NotFound;
51 default: 52 default:
52 break; 53 break;
53 } 54 }
54 return -1; 55 return -1;
55} 56}
56 57
57class Storage::NamedDatabase::Private 58class DataStore::NamedDatabase::Private
58{ 59{
59public: 60public:
60 Private(const QByteArray &_db, bool _allowDuplicates, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_txn *_txn) 61 Private(const QByteArray &_db, bool _allowDuplicates, const std::function<void(const DataStore::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_txn *_txn)
61 : db(_db), transaction(_txn), allowDuplicates(_allowDuplicates), defaultErrorHandler(_defaultErrorHandler), name(_name) 62 : db(_db), transaction(_txn), allowDuplicates(_allowDuplicates), defaultErrorHandler(_defaultErrorHandler), name(_name)
62 { 63 {
63 } 64 }
@@ -70,10 +71,10 @@ public:
70 MDB_txn *transaction; 71 MDB_txn *transaction;
71 MDB_dbi dbi; 72 MDB_dbi dbi;
72 bool allowDuplicates; 73 bool allowDuplicates;
73 std::function<void(const Storage::Error &error)> defaultErrorHandler; 74 std::function<void(const DataStore::Error &error)> defaultErrorHandler;
74 QString name; 75 QString name;
75 76
76 bool openDatabase(bool readOnly, std::function<void(const Storage::Error &error)> errorHandler) 77 bool openDatabase(bool readOnly, std::function<void(const DataStore::Error &error)> errorHandler)
77 { 78 {
78 unsigned int flags = 0; 79 unsigned int flags = 0;
79 if (!readOnly) { 80 if (!readOnly) {
@@ -97,20 +98,20 @@ public:
97 } 98 }
98}; 99};
99 100
100Storage::NamedDatabase::NamedDatabase() : d(nullptr) 101DataStore::NamedDatabase::NamedDatabase() : d(nullptr)
101{ 102{
102} 103}
103 104
104Storage::NamedDatabase::NamedDatabase(NamedDatabase::Private *prv) : d(prv) 105DataStore::NamedDatabase::NamedDatabase(NamedDatabase::Private *prv) : d(prv)
105{ 106{
106} 107}
107 108
108Storage::NamedDatabase::NamedDatabase(NamedDatabase &&other) : d(nullptr) 109DataStore::NamedDatabase::NamedDatabase(NamedDatabase &&other) : d(nullptr)
109{ 110{
110 *this = std::move(other); 111 *this = std::move(other);
111} 112}
112 113
113Storage::NamedDatabase &Storage::NamedDatabase::operator=(Storage::NamedDatabase &&other) 114DataStore::NamedDatabase &DataStore::NamedDatabase::operator=(DataStore::NamedDatabase &&other)
114{ 115{
115 if (&other != this) { 116 if (&other != this) {
116 delete d; 117 delete d;
@@ -120,12 +121,12 @@ Storage::NamedDatabase &Storage::NamedDatabase::operator=(Storage::NamedDatabase
120 return *this; 121 return *this;
121} 122}
122 123
123Storage::NamedDatabase::~NamedDatabase() 124DataStore::NamedDatabase::~NamedDatabase()
124{ 125{
125 delete d; 126 delete d;
126} 127}
127 128
128bool Storage::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sValue, const std::function<void(const Storage::Error &error)> &errorHandler) 129bool DataStore::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sValue, const std::function<void(const DataStore::Error &error)> &errorHandler)
129{ 130{
130 if (!d || !d->transaction) { 131 if (!d || !d->transaction) {
131 Error error("", ErrorCodes::GenericError, "Not open"); 132 Error error("", ErrorCodes::GenericError, "Not open");
@@ -161,12 +162,12 @@ bool Storage::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sVa
161 return !rc; 162 return !rc;
162} 163}
163 164
164void Storage::NamedDatabase::remove(const QByteArray &k, const std::function<void(const Storage::Error &error)> &errorHandler) 165void DataStore::NamedDatabase::remove(const QByteArray &k, const std::function<void(const DataStore::Error &error)> &errorHandler)
165{ 166{
166 remove(k, QByteArray(), errorHandler); 167 remove(k, QByteArray(), errorHandler);
167} 168}
168 169
169void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, const std::function<void(const Storage::Error &error)> &errorHandler) 170void DataStore::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, const std::function<void(const DataStore::Error &error)> &errorHandler)
170{ 171{
171 if (!d || !d->transaction) { 172 if (!d || !d->transaction) {
172 if (d) { 173 if (d) {
@@ -195,8 +196,8 @@ void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value
195 } 196 }
196} 197}
197 198
198int Storage::NamedDatabase::scan(const QByteArray &k, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler, 199int DataStore::NamedDatabase::scan(const QByteArray &k, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler,
199 const std::function<void(const Storage::Error &error)> &errorHandler, bool findSubstringKeys, bool skipInternalKeys) const 200 const std::function<void(const DataStore::Error &error)> &errorHandler, bool findSubstringKeys, bool skipInternalKeys) const
200{ 201{
201 if (!d || !d->transaction) { 202 if (!d || !d->transaction) {
202 // Not an error. We rely on this to read nothing from non-existing databases. 203 // Not an error. We rely on this to read nothing from non-existing databases.
@@ -278,8 +279,8 @@ int Storage::NamedDatabase::scan(const QByteArray &k, const std::function<bool(c
278 return numberOfRetrievedValues; 279 return numberOfRetrievedValues;
279} 280}
280 281
281void Storage::NamedDatabase::findLatest(const QByteArray &k, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 282void DataStore::NamedDatabase::findLatest(const QByteArray &k, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler,
282 const std::function<void(const Storage::Error &error)> &errorHandler) const 283 const std::function<void(const DataStore::Error &error)> &errorHandler) const
283{ 284{
284 if (!d || !d->transaction) { 285 if (!d || !d->transaction) {
285 // Not an error. We rely on this to read nothing from non-existing databases. 286 // Not an error. We rely on this to read nothing from non-existing databases.
@@ -346,7 +347,7 @@ void Storage::NamedDatabase::findLatest(const QByteArray &k, const std::function
346 return; 347 return;
347} 348}
348 349
349qint64 Storage::NamedDatabase::getSize() 350qint64 DataStore::NamedDatabase::getSize()
350{ 351{
351 if (!d || !d->transaction) { 352 if (!d || !d->transaction) {
352 return -1; 353 return -1;
@@ -368,10 +369,10 @@ qint64 Storage::NamedDatabase::getSize()
368} 369}
369 370
370 371
371class Storage::Transaction::Private 372class DataStore::Transaction::Private
372{ 373{
373public: 374public:
374 Private(bool _requestRead, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_env *_env) 375 Private(bool _requestRead, const std::function<void(const DataStore::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_env *_env)
375 : env(_env), transaction(nullptr), requestedRead(_requestRead), defaultErrorHandler(_defaultErrorHandler), name(_name), implicitCommit(false), error(false), modificationCounter(0) 376 : env(_env), transaction(nullptr), requestedRead(_requestRead), defaultErrorHandler(_defaultErrorHandler), name(_name), implicitCommit(false), error(false), modificationCounter(0)
376 { 377 {
377 } 378 }
@@ -383,7 +384,7 @@ public:
383 MDB_txn *transaction; 384 MDB_txn *transaction;
384 MDB_dbi dbi; 385 MDB_dbi dbi;
385 bool requestedRead; 386 bool requestedRead;
386 std::function<void(const Storage::Error &error)> defaultErrorHandler; 387 std::function<void(const DataStore::Error &error)> defaultErrorHandler;
387 QString name; 388 QString name;
388 bool implicitCommit; 389 bool implicitCommit;
389 bool error; 390 bool error;
@@ -406,21 +407,21 @@ public:
406 } 407 }
407}; 408};
408 409
409Storage::Transaction::Transaction() : d(nullptr) 410DataStore::Transaction::Transaction() : d(nullptr)
410{ 411{
411} 412}
412 413
413Storage::Transaction::Transaction(Transaction::Private *prv) : d(prv) 414DataStore::Transaction::Transaction(Transaction::Private *prv) : d(prv)
414{ 415{
415 d->startTransaction(); 416 d->startTransaction();
416} 417}
417 418
418Storage::Transaction::Transaction(Transaction &&other) : d(nullptr) 419DataStore::Transaction::Transaction(Transaction &&other) : d(nullptr)
419{ 420{
420 *this = std::move(other); 421 *this = std::move(other);
421} 422}
422 423
423Storage::Transaction &Storage::Transaction::operator=(Storage::Transaction &&other) 424DataStore::Transaction &DataStore::Transaction::operator=(DataStore::Transaction &&other)
424{ 425{
425 if (&other != this) { 426 if (&other != this) {
426 delete d; 427 delete d;
@@ -430,7 +431,7 @@ Storage::Transaction &Storage::Transaction::operator=(Storage::Transaction &&oth
430 return *this; 431 return *this;
431} 432}
432 433
433Storage::Transaction::~Transaction() 434DataStore::Transaction::~Transaction()
434{ 435{
435 if (d && d->transaction) { 436 if (d && d->transaction) {
436 if (d->implicitCommit && !d->error) { 437 if (d->implicitCommit && !d->error) {
@@ -443,12 +444,12 @@ Storage::Transaction::~Transaction()
443 delete d; 444 delete d;
444} 445}
445 446
446Storage::Transaction::operator bool() const 447DataStore::Transaction::operator bool() const
447{ 448{
448 return (d && d->transaction); 449 return (d && d->transaction);
449} 450}
450 451
451bool Storage::Transaction::commit(const std::function<void(const Storage::Error &error)> &errorHandler) 452bool DataStore::Transaction::commit(const std::function<void(const DataStore::Error &error)> &errorHandler)
452{ 453{
453 if (!d || !d->transaction) { 454 if (!d || !d->transaction) {
454 return false; 455 return false;
@@ -467,7 +468,7 @@ bool Storage::Transaction::commit(const std::function<void(const Storage::Error
467 return !rc; 468 return !rc;
468} 469}
469 470
470void Storage::Transaction::abort() 471void DataStore::Transaction::abort()
471{ 472{
472 if (!d || !d->transaction) { 473 if (!d || !d->transaction) {
473 return; 474 return;
@@ -481,7 +482,7 @@ void Storage::Transaction::abort()
481 482
482//Ensure that we opened the correct database by comparing the expected identifier with the one 483//Ensure that we opened the correct database by comparing the expected identifier with the one
483//we write to the database on first open. 484//we write to the database on first open.
484static bool ensureCorrectDb(Storage::NamedDatabase &database, const QByteArray &db, bool readOnly) 485static bool ensureCorrectDb(DataStore::NamedDatabase &database, const QByteArray &db, bool readOnly)
485{ 486{
486 bool openedTheWrongDatabase = false; 487 bool openedTheWrongDatabase = false;
487 auto count = database.scan("__internal_dbname", [db, &openedTheWrongDatabase](const QByteArray &key, const QByteArray &value) ->bool { 488 auto count = database.scan("__internal_dbname", [db, &openedTheWrongDatabase](const QByteArray &key, const QByteArray &value) ->bool {
@@ -491,7 +492,7 @@ static bool ensureCorrectDb(Storage::NamedDatabase &database, const QByteArray &
491 } 492 }
492 return false; 493 return false;
493 }, 494 },
494 [](const Storage::Error &error) -> bool{ 495 [](const DataStore::Error &error) -> bool{
495 return false; 496 return false;
496 }, false); 497 }, false);
497 //This is the first time we open this database in a write transaction, write the db name 498 //This is the first time we open this database in a write transaction, write the db name
@@ -503,7 +504,7 @@ static bool ensureCorrectDb(Storage::NamedDatabase &database, const QByteArray &
503 return !openedTheWrongDatabase; 504 return !openedTheWrongDatabase;
504} 505}
505 506
506bool Storage::Transaction::validateNamedDatabases() 507bool DataStore::Transaction::validateNamedDatabases()
507{ 508{
508 auto databases = getDatabaseNames(); 509 auto databases = getDatabaseNames();
509 for (const auto &dbName : databases) { 510 for (const auto &dbName : databases) {
@@ -516,28 +517,28 @@ bool Storage::Transaction::validateNamedDatabases()
516 return true; 517 return true;
517} 518}
518 519
519Storage::NamedDatabase Storage::Transaction::openDatabase(const QByteArray &db, const std::function<void(const Storage::Error &error)> &errorHandler, bool allowDuplicates) const 520DataStore::NamedDatabase DataStore::Transaction::openDatabase(const QByteArray &db, const std::function<void(const DataStore::Error &error)> &errorHandler, bool allowDuplicates) const
520{ 521{
521 if (!d) { 522 if (!d) {
522 return Storage::NamedDatabase(); 523 return DataStore::NamedDatabase();
523 } 524 }
524 Q_ASSERT(d->transaction); 525 Q_ASSERT(d->transaction);
525 // We don't now if anything changed 526 // We don't now if anything changed
526 d->implicitCommit = true; 527 d->implicitCommit = true;
527 auto p = new Storage::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction); 528 auto p = new DataStore::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction);
528 if (!p->openDatabase(d->requestedRead, errorHandler)) { 529 if (!p->openDatabase(d->requestedRead, errorHandler)) {
529 delete p; 530 delete p;
530 return Storage::NamedDatabase(); 531 return DataStore::NamedDatabase();
531 } 532 }
532 auto database = Storage::NamedDatabase(p); 533 auto database = DataStore::NamedDatabase(p);
533 if (!ensureCorrectDb(database, db, d->requestedRead)) { 534 if (!ensureCorrectDb(database, db, d->requestedRead)) {
534 SinkWarning() << "Failed to open the database" << db; 535 SinkWarning() << "Failed to open the database" << db;
535 return Storage::NamedDatabase(); 536 return DataStore::NamedDatabase();
536 } 537 }
537 return database; 538 return database;
538} 539}
539 540
540QList<QByteArray> Storage::Transaction::getDatabaseNames() const 541QList<QByteArray> DataStore::Transaction::getDatabaseNames() const
541{ 542{
542 if (!d) { 543 if (!d) {
543 SinkWarning() << "Invalid transaction"; 544 SinkWarning() << "Invalid transaction";
@@ -574,7 +575,7 @@ QList<QByteArray> Storage::Transaction::getDatabaseNames() const
574} 575}
575 576
576 577
577class Storage::Private 578class DataStore::Private
578{ 579{
579public: 580public:
580 Private(const QString &s, const QString &n, AccessMode m); 581 Private(const QString &s, const QString &n, AccessMode m);
@@ -587,7 +588,7 @@ public:
587 AccessMode mode; 588 AccessMode mode;
588}; 589};
589 590
590Storage::Private::Private(const QString &s, const QString &n, AccessMode m) : storageRoot(s), name(n), env(0), mode(m) 591DataStore::Private::Private(const QString &s, const QString &n, AccessMode m) : storageRoot(s), name(n), env(0), mode(m)
591{ 592{
592 const QString fullPath(storageRoot + '/' + name); 593 const QString fullPath(storageRoot + '/' + name);
593 QFileInfo dirInfo(fullPath); 594 QFileInfo dirInfo(fullPath);
@@ -639,27 +640,27 @@ Storage::Private::Private(const QString &s, const QString &n, AccessMode m) : st
639 } 640 }
640} 641}
641 642
642Storage::Private::~Private() 643DataStore::Private::~Private()
643{ 644{
644 //We never close the environment (unless we remove the db), since we should only open the environment once per process (as per lmdb docs) 645 //We never close the environment (unless we remove the db), since we should only open the environment once per process (as per lmdb docs)
645 //and create storage instance from all over the place. Thus, we're not closing it here on purpose. 646 //and create storage instance from all over the place. Thus, we're not closing it here on purpose.
646} 647}
647 648
648Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode) : d(new Private(storageRoot, name, mode)) 649DataStore::DataStore(const QString &storageRoot, const QString &name, AccessMode mode) : d(new Private(storageRoot, name, mode))
649{ 650{
650} 651}
651 652
652Storage::~Storage() 653DataStore::~DataStore()
653{ 654{
654 delete d; 655 delete d;
655} 656}
656 657
657bool Storage::exists() const 658bool DataStore::exists() const
658{ 659{
659 return (d->env != 0); 660 return (d->env != 0);
660} 661}
661 662
662Storage::Transaction Storage::createTransaction(AccessMode type, const std::function<void(const Storage::Error &error)> &errorHandlerArg) 663DataStore::Transaction DataStore::createTransaction(AccessMode type, const std::function<void(const DataStore::Error &error)> &errorHandlerArg)
663{ 664{
664 auto errorHandler = errorHandlerArg ? errorHandlerArg : defaultErrorHandler(); 665 auto errorHandler = errorHandlerArg ? errorHandlerArg : defaultErrorHandler();
665 if (!d->env) { 666 if (!d->env) {
@@ -677,7 +678,7 @@ Storage::Transaction Storage::createTransaction(AccessMode type, const std::func
677 return Transaction(new Transaction::Private(requestedRead, defaultErrorHandler(), d->name, d->env)); 678 return Transaction(new Transaction::Private(requestedRead, defaultErrorHandler(), d->name, d->env));
678} 679}
679 680
680qint64 Storage::diskUsage() const 681qint64 DataStore::diskUsage() const
681{ 682{
682 QFileInfo info(d->storageRoot + '/' + d->name + "/data.mdb"); 683 QFileInfo info(d->storageRoot + '/' + d->name + "/data.mdb");
683 if (!info.exists()) { 684 if (!info.exists()) {
@@ -686,7 +687,7 @@ qint64 Storage::diskUsage() const
686 return info.size(); 687 return info.size();
687} 688}
688 689
689void Storage::removeFromDisk() const 690void DataStore::removeFromDisk() const
690{ 691{
691 const QString fullPath(d->storageRoot + '/' + d->name); 692 const QString fullPath(d->storageRoot + '/' + d->name);
692 QMutexLocker locker(&sMutex); 693 QMutexLocker locker(&sMutex);
@@ -701,7 +702,7 @@ void Storage::removeFromDisk() const
701 } 702 }
702} 703}
703 704
704void Storage::clearEnv() 705void DataStore::clearEnv()
705{ 706{
706 for (auto env : sEnvironments) { 707 for (auto env : sEnvironments) {
707 mdb_env_close(env); 708 mdb_env_close(env);
@@ -709,4 +710,5 @@ void Storage::clearEnv()
709 sEnvironments.clear(); 710 sEnvironments.clear();
710} 711}
711 712
713}
712} // namespace Sink 714} // namespace Sink