diff options
author | Rémi Nicole <nicole@kolabsystems.com> | 2018-08-22 14:16:59 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-08-22 14:28:51 +0200 |
commit | 46313049ac01a3007ef60bdc937442945355a38d (patch) | |
tree | 56ce0cd679367a60ba3a706ac4d207bc9cc82230 /common/storage_common.cpp | |
parent | af91a18748b91f4a4fc0d83247561371d376bec5 (diff) | |
download | sink-46313049ac01a3007ef60bdc937442945355a38d.tar.gz sink-46313049ac01a3007ef60bdc937442945355a38d.zip |
Separate UIDs and Revisions in main databases
Summary:
- Change revision type from `qint64` to `size_t` for LMDB in a couple of places (LMDB supports `unsigned int` or `size_t` which are `long unsigned int` on my machine)
- Better support for database flags (duplicate, integer keys, integer values for now but is extensible)
- Main databases' keys are now revisions
- Some databases switched to integer keys databases:
- Main databases
- the revision to uid mapping database
- the revision to entity type mapping database
- Refactor the entity type's `typeDatabases` method (if in the future we need to change the main databases' flags again)
- New uid to revision mapping database (`uidsToRevisions`):
- Stores all revisions (not uid to latest revision) because we need it for cleaning old revisions
- Flags are: duplicates + integer values (so findLatest finds the latest revision for the given uid)
~~Problems to fix before merging:~~
All Fixed!
- ~~Sometimes Sink can't read what has just been written to the database (maybe because of transactions race conditions)~~
- ~~Most of the times, this results in Sink not able to find the uid for a given revision by reading the `revisions` database~~
- ~~`pipelinetest`'s `testModifyWithConflict` fails because the local changes are overridden~~
~~The first problem prevents me from running benchmarks~~
Reviewers: cmollekopf
Tags: #sink
Differential Revision: https://phabricator.kde.org/D14974
Diffstat (limited to 'common/storage_common.cpp')
-rw-r--r-- | common/storage_common.cpp | 105 |
1 files changed, 87 insertions, 18 deletions
diff --git a/common/storage_common.cpp b/common/storage_common.cpp index 264f223..7c794c3 100644 --- a/common/storage_common.cpp +++ b/common/storage_common.cpp | |||
@@ -117,26 +117,69 @@ qint64 DataStore::cleanedUpRevision(const DataStore::Transaction &transaction) | |||
117 | return r; | 117 | return r; |
118 | } | 118 | } |
119 | 119 | ||
120 | QByteArray DataStore::getUidFromRevision(const DataStore::Transaction &transaction, qint64 revision) | 120 | QByteArray DataStore::getUidFromRevision(const DataStore::Transaction &transaction, size_t revision) |
121 | { | 121 | { |
122 | QByteArray uid; | 122 | QByteArray uid; |
123 | transaction.openDatabase("revisions") | 123 | transaction |
124 | .scan(QByteArray::number(revision), | 124 | .openDatabase("revisions", /* errorHandler = */ {}, IntegerKeys) |
125 | [&](const QByteArray &, const QByteArray &value) -> bool { | 125 | .scan(revision, |
126 | uid = QByteArray{value.constData(), value.size()}; | 126 | [&](const size_t, const QByteArray &value) -> bool { |
127 | uid = QByteArray{ value.constData(), value.size() }; | ||
127 | return false; | 128 | return false; |
128 | }, | 129 | }, |
129 | [revision](const Error &error) { SinkWarning() << "Couldn't find uid for revision: " << revision << error.message; }); | 130 | [revision](const Error &error) { |
131 | SinkWarning() << "Couldn't find uid for revision: " << revision << error.message; | ||
132 | }); | ||
130 | Q_ASSERT(!uid.isEmpty()); | 133 | Q_ASSERT(!uid.isEmpty()); |
131 | return uid; | 134 | return uid; |
132 | } | 135 | } |
133 | 136 | ||
134 | QByteArray DataStore::getTypeFromRevision(const DataStore::Transaction &transaction, qint64 revision) | 137 | size_t DataStore::getLatestRevisionFromUid(DataStore::Transaction &t, const QByteArray &uid) |
138 | { | ||
139 | size_t revision; | ||
140 | t.openDatabase("uidsToRevisions", {}, AllowDuplicates | IntegerValues) | ||
141 | .findLatest(uid, [&revision](const QByteArray &key, const QByteArray &value) { | ||
142 | revision = byteArrayToSizeT(value); | ||
143 | }); | ||
144 | |||
145 | return revision; | ||
146 | } | ||
147 | |||
148 | QList<size_t> DataStore::getRevisionsUntilFromUid(DataStore::Transaction &t, const QByteArray &uid, size_t lastRevision) | ||
149 | { | ||
150 | QList<size_t> queriedRevisions; | ||
151 | t.openDatabase("uidsToRevisions", {}, AllowDuplicates | IntegerValues) | ||
152 | .scan(uid, [&queriedRevisions, lastRevision](const QByteArray &, const QByteArray &value) { | ||
153 | size_t currentRevision = byteArrayToSizeT(value); | ||
154 | if (currentRevision < lastRevision) { | ||
155 | queriedRevisions << currentRevision; | ||
156 | return true; | ||
157 | } | ||
158 | |||
159 | return false; | ||
160 | }); | ||
161 | |||
162 | return queriedRevisions; | ||
163 | } | ||
164 | |||
165 | QList<size_t> DataStore::getRevisionsFromUid(DataStore::Transaction &t, const QByteArray &uid) | ||
166 | { | ||
167 | QList<size_t> queriedRevisions; | ||
168 | t.openDatabase("uidsToRevisions", {}, AllowDuplicates | IntegerValues) | ||
169 | .scan(uid, [&queriedRevisions](const QByteArray &, const QByteArray &value) { | ||
170 | queriedRevisions << byteArrayToSizeT(value); | ||
171 | return true; | ||
172 | }); | ||
173 | |||
174 | return queriedRevisions; | ||
175 | } | ||
176 | |||
177 | QByteArray DataStore::getTypeFromRevision(const DataStore::Transaction &transaction, size_t revision) | ||
135 | { | 178 | { |
136 | QByteArray type; | 179 | QByteArray type; |
137 | transaction.openDatabase("revisionType") | 180 | transaction.openDatabase("revisionType", /* errorHandler = */ {}, IntegerKeys) |
138 | .scan(QByteArray::number(revision), | 181 | .scan(revision, |
139 | [&](const QByteArray &, const QByteArray &value) -> bool { | 182 | [&](const size_t, const QByteArray &value) -> bool { |
140 | type = QByteArray{value.constData(), value.size()}; | 183 | type = QByteArray{value.constData(), value.size()}; |
141 | return false; | 184 | return false; |
142 | }, | 185 | }, |
@@ -145,17 +188,31 @@ QByteArray DataStore::getTypeFromRevision(const DataStore::Transaction &transact | |||
145 | return type; | 188 | return type; |
146 | } | 189 | } |
147 | 190 | ||
148 | void DataStore::recordRevision(DataStore::Transaction &transaction, qint64 revision, const QByteArray &uid, const QByteArray &type) | 191 | void DataStore::recordRevision(DataStore::Transaction &transaction, size_t revision, |
192 | const QByteArray &uid, const QByteArray &type) | ||
149 | { | 193 | { |
150 | // TODO use integerkeys | 194 | transaction |
151 | transaction.openDatabase("revisions").write(QByteArray::number(revision), uid); | 195 | .openDatabase("revisions", /* errorHandler = */ {}, IntegerKeys) |
152 | transaction.openDatabase("revisionType").write(QByteArray::number(revision), type); | 196 | .write(revision, uid); |
197 | transaction.openDatabase("uidsToRevisions", /* errorHandler = */ {}, AllowDuplicates | IntegerValues) | ||
198 | .write(uid, sizeTToByteArray(revision)); | ||
199 | transaction | ||
200 | .openDatabase("revisionType", /* errorHandler = */ {}, IntegerKeys) | ||
201 | .write(revision, type); | ||
153 | } | 202 | } |
154 | 203 | ||
155 | void DataStore::removeRevision(DataStore::Transaction &transaction, qint64 revision) | 204 | void DataStore::removeRevision(DataStore::Transaction &transaction, size_t revision) |
156 | { | 205 | { |
157 | transaction.openDatabase("revisions").remove(QByteArray::number(revision)); | 206 | const QByteArray uid = getUidFromRevision(transaction, revision); |
158 | transaction.openDatabase("revisionType").remove(QByteArray::number(revision)); | 207 | |
208 | transaction | ||
209 | .openDatabase("revisions", /* errorHandler = */ {}, IntegerKeys) | ||
210 | .remove(revision); | ||
211 | transaction.openDatabase("uidsToRevisions", /* errorHandler = */ {}, AllowDuplicates | IntegerValues) | ||
212 | .remove(uid, sizeTToByteArray(revision)); | ||
213 | transaction | ||
214 | .openDatabase("revisionType", /* errorHandler = */ {}, IntegerKeys) | ||
215 | .remove(revision); | ||
159 | } | 216 | } |
160 | 217 | ||
161 | void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) | 218 | void DataStore::recordUid(DataStore::Transaction &transaction, const QByteArray &uid, const QByteArray &type) |
@@ -176,6 +233,18 @@ void DataStore::getUids(const QByteArray &type, const Transaction &transaction, | |||
176 | }); | 233 | }); |
177 | } | 234 | } |
178 | 235 | ||
236 | bool DataStore::hasUid(const QByteArray &type, const Transaction &transaction, const QByteArray &uid) | ||
237 | { | ||
238 | bool hasTheUid = false; | ||
239 | transaction.openDatabase(type + "uids").scan(uid, [&](const QByteArray &key, const QByteArray &) { | ||
240 | Q_ASSERT(uid == key); | ||
241 | hasTheUid = true; | ||
242 | return false; | ||
243 | }); | ||
244 | |||
245 | return hasTheUid; | ||
246 | } | ||
247 | |||
179 | bool DataStore::isInternalKey(const char *key) | 248 | bool DataStore::isInternalKey(const char *key) |
180 | { | 249 | { |
181 | return key && strncmp(key, s_internalPrefix, s_internalPrefixSize) == 0; | 250 | return key && strncmp(key, s_internalPrefix, s_internalPrefixSize) == 0; |
@@ -207,7 +276,7 @@ DataStore::NamedDatabase DataStore::mainDatabase(const DataStore::Transaction &t | |||
207 | Q_ASSERT(false); | 276 | Q_ASSERT(false); |
208 | return {}; | 277 | return {}; |
209 | } | 278 | } |
210 | return t.openDatabase(type + ".main"); | 279 | return t.openDatabase(type + ".main", /* errorHandler= */ {}, IntegerKeys); |
211 | } | 280 | } |
212 | 281 | ||
213 | bool DataStore::NamedDatabase::contains(const QByteArray &uid) | 282 | bool DataStore::NamedDatabase::contains(const QByteArray &uid) |