diff options
-rw-r--r-- | common/storage_lmdb.cpp | 124 |
1 files changed, 67 insertions, 57 deletions
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index c3240f6..f7999d1 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -716,75 +716,85 @@ public: | |||
716 | 716 | ||
717 | MDB_env *env; | 717 | MDB_env *env; |
718 | AccessMode mode; | 718 | AccessMode mode; |
719 | Sink::Log::Context logCtx; | ||
720 | |||
721 | void initEnvironment(const QString &fullPath, const DbLayout &layout) | ||
722 | { | ||
723 | // Ensure the environment is only created once, and that we only have one environment per process | ||
724 | if (!(env = sEnvironments.value(fullPath))) { | ||
725 | QMutexLocker locker(&sMutex); | ||
726 | if (!(env = sEnvironments.value(fullPath))) { | ||
727 | int rc = 0; | ||
728 | if ((rc = mdb_env_create(&env))) { | ||
729 | SinkWarningCtx(logCtx) << "mdb_env_create: " << rc << " " << mdb_strerror(rc); | ||
730 | qCritical() << "mdb_env_create: " << rc << " " << mdb_strerror(rc); | ||
731 | } else { | ||
732 | //Limit large enough to accomodate all our named dbs. This only starts to matter if the number gets large, otherwise it's just a bunch of extra entries in the main table. | ||
733 | mdb_env_set_maxdbs(env, 50); | ||
734 | const bool readOnly = (mode == ReadOnly); | ||
735 | unsigned int flags = MDB_NOTLS; | ||
736 | if (readOnly) { | ||
737 | flags |= MDB_RDONLY; | ||
738 | } | ||
739 | if ((rc = mdb_env_open(env, fullPath.toStdString().data(), flags, 0664))) { | ||
740 | SinkWarningCtx(logCtx) << "mdb_env_open: " << rc << ":" << mdb_strerror(rc); | ||
741 | mdb_env_close(env); | ||
742 | env = 0; | ||
743 | } else { | ||
744 | if (RUNNING_ON_VALGRIND) { | ||
745 | // In order to run valgrind this size must be smaller than half your available RAM | ||
746 | // https://github.com/BVLC/caffe/issues/2404 | ||
747 | mdb_env_set_mapsize(env, (size_t)10485760 * (size_t)1000); // 1MB * 1000 | ||
748 | } else { | ||
749 | //This is the maximum size of the db (but will not be used directly), so we make it large enough that we hopefully never run into the limit. | ||
750 | mdb_env_set_mapsize(env, (size_t)10485760 * (size_t)100000); // 1MB * 1000 | ||
751 | } | ||
752 | Q_ASSERT(env); | ||
753 | sEnvironments.insert(fullPath, env); | ||
754 | //Open all available dbi's | ||
755 | bool noLock = true; | ||
756 | auto t = Transaction(new Transaction::Private(readOnly, nullptr, name, env, noLock)); | ||
757 | if (!layout.tables.isEmpty()) { | ||
758 | |||
759 | //TODO upgrade db if the layout has changed: | ||
760 | //* read existing layout | ||
761 | //* if layout is not the same create new layout | ||
762 | //If the db is read only, abort if the db is not yet existing. | ||
763 | //If the db is not read-only but is not existing, ensure we have a layout and create all tables. | ||
764 | |||
765 | for (auto it = layout.tables.constBegin(); it != layout.tables.constEnd(); it++) { | ||
766 | bool allowDuplicates = it.value(); | ||
767 | t.openDatabase(it.key(), {}, allowDuplicates); | ||
768 | } | ||
769 | } else { | ||
770 | for (const auto &db : t.getDatabaseNames()) { | ||
771 | //Get dbi to store for future use. | ||
772 | t.openDatabase(db); | ||
773 | } | ||
774 | } | ||
775 | //To persist the dbis (this is also necessary for read-only transactions) | ||
776 | t.commit(); | ||
777 | } | ||
778 | } | ||
779 | } | ||
780 | } | ||
781 | } | ||
782 | |||
719 | }; | 783 | }; |
720 | 784 | ||
721 | DataStore::Private::Private(const QString &s, const QString &n, AccessMode m, const DbLayout &layout) : storageRoot(s), name(n), env(0), mode(m) | 785 | DataStore::Private::Private(const QString &s, const QString &n, AccessMode m, const DbLayout &layout) : storageRoot(s), name(n), env(0), mode(m), logCtx(n.toLatin1()) |
722 | { | 786 | { |
787 | |||
723 | const QString fullPath(storageRoot + '/' + name); | 788 | const QString fullPath(storageRoot + '/' + name); |
724 | QFileInfo dirInfo(fullPath); | 789 | QFileInfo dirInfo(fullPath); |
725 | if (!dirInfo.exists() && mode == ReadWrite) { | 790 | if (!dirInfo.exists() && mode == ReadWrite) { |
726 | QDir().mkpath(fullPath); | 791 | QDir().mkpath(fullPath); |
727 | dirInfo.refresh(); | 792 | dirInfo.refresh(); |
728 | } | 793 | } |
729 | Sink::Log::Context logCtx{n.toLatin1()}; | ||
730 | if (mode == ReadWrite && !dirInfo.permission(QFile::WriteOwner)) { | 794 | if (mode == ReadWrite && !dirInfo.permission(QFile::WriteOwner)) { |
731 | qCritical() << fullPath << "does not have write permissions. Aborting"; | 795 | qCritical() << fullPath << "does not have write permissions. Aborting"; |
732 | } else if (dirInfo.exists()) { | 796 | } else if (dirInfo.exists()) { |
733 | // Ensure the environment is only created once | 797 | initEnvironment(fullPath, layout); |
734 | QMutexLocker locker(&sMutex); | ||
735 | |||
736 | /* | ||
737 | * It seems we can only ever have one environment open in the process. | ||
738 | * Otherwise multi-threading breaks. | ||
739 | */ | ||
740 | env = sEnvironments.value(fullPath); | ||
741 | if (!env) { | ||
742 | int rc = 0; | ||
743 | if ((rc = mdb_env_create(&env))) { | ||
744 | // TODO: handle error | ||
745 | SinkWarningCtx(logCtx) << "mdb_env_create: " << rc << " " << mdb_strerror(rc); | ||
746 | } else { | ||
747 | mdb_env_set_maxdbs(env, 50); | ||
748 | unsigned int flags = MDB_NOTLS; | ||
749 | if (mode == ReadOnly) { | ||
750 | flags |= MDB_RDONLY; | ||
751 | } | ||
752 | if ((rc = mdb_env_open(env, fullPath.toStdString().data(), flags, 0664))) { | ||
753 | SinkWarningCtx(logCtx) << "mdb_env_open: " << rc << ":" << mdb_strerror(rc); | ||
754 | mdb_env_close(env); | ||
755 | env = 0; | ||
756 | } else { | ||
757 | if (RUNNING_ON_VALGRIND) { | ||
758 | // In order to run valgrind this size must be smaller than half your available RAM | ||
759 | // https://github.com/BVLC/caffe/issues/2404 | ||
760 | const size_t dbSize = (size_t)10485760 * (size_t)1000; // 1MB * 1000 | ||
761 | mdb_env_set_mapsize(env, dbSize); | ||
762 | } else { | ||
763 | // FIXME: dynamic resize | ||
764 | const size_t dbSize = (size_t)10485760 * (size_t)8000; // 1MB * 8000 | ||
765 | mdb_env_set_mapsize(env, dbSize); | ||
766 | } | ||
767 | sEnvironments.insert(fullPath, env); | ||
768 | //Open all available dbi's | ||
769 | bool noLock = true; | ||
770 | bool requestedRead = m == ReadOnly; | ||
771 | auto t = Transaction(new Transaction::Private(requestedRead, nullptr, name, env, noLock)); | ||
772 | if (!layout.tables.isEmpty()) { | ||
773 | for (auto it = layout.tables.constBegin(); it != layout.tables.constEnd(); it++) { | ||
774 | bool allowDuplicates = it.value(); | ||
775 | t.openDatabase(it.key(), {}, allowDuplicates); | ||
776 | } | ||
777 | } else { | ||
778 | for (const auto &db : t.getDatabaseNames()) { | ||
779 | //Get dbi to store for future use. | ||
780 | t.openDatabase(db); | ||
781 | } | ||
782 | } | ||
783 | //To persist the dbis (this is also necessary for read-only transactions) | ||
784 | t.commit(); | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | } | 798 | } |
789 | } | 799 | } |
790 | 800 | ||