diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | common/changereplay.cpp | 14 | ||||
-rw-r--r-- | common/storage.h | 6 | ||||
-rw-r--r-- | common/storage/entitystore.cpp | 73 | ||||
-rw-r--r-- | common/storage/entitystore.h | 1 | ||||
-rw-r--r-- | common/storage/key.cpp | 156 | ||||
-rw-r--r-- | common/storage/key.h | 100 | ||||
-rw-r--r-- | common/storage_common.cpp | 17 | ||||
-rw-r--r-- | common/synchronizer.cpp | 3 | ||||
-rw-r--r-- | common/typeindex.cpp | 9 | ||||
-rw-r--r-- | common/utils.h | 13 |
11 files changed, 333 insertions, 60 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 970990f..7c4630b 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt | |||
@@ -73,6 +73,7 @@ add_library(${PROJECT_NAME} SHARED | |||
73 | specialpurposepreprocessor.cpp | 73 | specialpurposepreprocessor.cpp |
74 | datastorequery.cpp | 74 | datastorequery.cpp |
75 | storage/entitystore.cpp | 75 | storage/entitystore.cpp |
76 | storage/key.cpp | ||
76 | indexer.cpp | 77 | indexer.cpp |
77 | mail/threadindexer.cpp | 78 | mail/threadindexer.cpp |
78 | mail/fulltextindexer.cpp | 79 | mail/fulltextindexer.cpp |
diff --git a/common/changereplay.cpp b/common/changereplay.cpp index 0adbd78..d7f46dc 100644 --- a/common/changereplay.cpp +++ b/common/changereplay.cpp | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "log.h" | 23 | #include "log.h" |
24 | #include "definitions.h" | 24 | #include "definitions.h" |
25 | #include "bufferutils.h" | 25 | #include "bufferutils.h" |
26 | #include "storage/key.h" | ||
26 | 27 | ||
27 | #include <QTimer> | 28 | #include <QTimer> |
28 | 29 | ||
@@ -113,10 +114,13 @@ KAsync::Job<void> ChangeReplay::replayNextRevision() | |||
113 | if (uid.isEmpty() || type.isEmpty()) { | 114 | if (uid.isEmpty() || type.isEmpty()) { |
114 | SinkErrorCtx(mLogCtx) << "Failed to read uid or type for revison: " << revision << uid << type; | 115 | SinkErrorCtx(mLogCtx) << "Failed to read uid or type for revison: " << revision << uid << type; |
115 | } else { | 116 | } else { |
116 | const auto key = DataStore::assembleKey(uid, revision); | 117 | // TODO: should not use internal representations |
118 | const auto key = Storage::Key(Storage::Identifier::fromDisplayByteArray(uid), revision); | ||
119 | const auto internalKey = key.toInternalByteArray(); | ||
120 | const auto displayKey = key.toDisplayByteArray(); | ||
117 | QByteArray entityBuffer; | 121 | QByteArray entityBuffer; |
118 | DataStore::mainDatabase(mMainStoreTransaction, type) | 122 | DataStore::mainDatabase(mMainStoreTransaction, type) |
119 | .scan(key, | 123 | .scan(internalKey, |
120 | [&entityBuffer](const QByteArray &key, const QByteArray &value) -> bool { | 124 | [&entityBuffer](const QByteArray &key, const QByteArray &value) -> bool { |
121 | entityBuffer = value; | 125 | entityBuffer = value; |
122 | return false; | 126 | return false; |
@@ -126,9 +130,9 @@ KAsync::Job<void> ChangeReplay::replayNextRevision() | |||
126 | if (entityBuffer.isEmpty()) { | 130 | if (entityBuffer.isEmpty()) { |
127 | SinkErrorCtx(mLogCtx) << "Failed to replay change " << key; | 131 | SinkErrorCtx(mLogCtx) << "Failed to replay change " << key; |
128 | } else { | 132 | } else { |
129 | if (canReplay(type, key, entityBuffer)) { | 133 | if (canReplay(type, displayKey, entityBuffer)) { |
130 | SinkTraceCtx(mLogCtx) << "Replaying " << key; | 134 | SinkTraceCtx(mLogCtx) << "Replaying " << displayKey; |
131 | replayJob = replay(type, key, entityBuffer); | 135 | replayJob = replay(type, displayKey, entityBuffer); |
132 | //Set the last revision we tried to replay | 136 | //Set the last revision we tried to replay |
133 | *lastReplayedRevision = revision; | 137 | *lastReplayedRevision = revision; |
134 | //Execute replay job and commit | 138 | //Execute replay job and commit |
diff --git a/common/storage.h b/common/storage.h index a8c486c..8904148 100644 --- a/common/storage.h +++ b/common/storage.h | |||
@@ -22,8 +22,10 @@ | |||
22 | #pragma once | 22 | #pragma once |
23 | 23 | ||
24 | #include "sink_export.h" | 24 | #include "sink_export.h" |
25 | #include "utils.h" | ||
25 | #include <string> | 26 | #include <string> |
26 | #include <functional> | 27 | #include <functional> |
28 | #include <QUuid> | ||
27 | #include <QString> | 29 | #include <QString> |
28 | #include <QMap> | 30 | #include <QMap> |
29 | 31 | ||
@@ -237,10 +239,6 @@ public: | |||
237 | static bool isInternalKey(void *key, int keySize); | 239 | static bool isInternalKey(void *key, int keySize); |
238 | static bool isInternalKey(const QByteArray &key); | 240 | static bool isInternalKey(const QByteArray &key); |
239 | 241 | ||
240 | static QByteArray assembleKey(const QByteArray &key, qint64 revision); | ||
241 | static QByteArray uidFromKey(const QByteArray &key); | ||
242 | static qint64 revisionFromKey(const QByteArray &key); | ||
243 | |||
244 | static NamedDatabase mainDatabase(const Transaction &, const QByteArray &type); | 242 | static NamedDatabase mainDatabase(const Transaction &, const QByteArray &type); |
245 | 243 | ||
246 | static QByteArray generateUid(); | 244 | static QByteArray generateUid(); |
diff --git a/common/storage/entitystore.cpp b/common/storage/entitystore.cpp index dd6bbf0..3addf94 100644 --- a/common/storage/entitystore.cpp +++ b/common/storage/entitystore.cpp | |||
@@ -237,8 +237,10 @@ bool EntityStore::add(const QByteArray &type, ApplicationDomainType entity, bool | |||
237 | flatbuffers::FlatBufferBuilder fbb; | 237 | flatbuffers::FlatBufferBuilder fbb; |
238 | d->resourceContext.adaptorFactory(type).createBuffer(entity, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); | 238 | d->resourceContext.adaptorFactory(type).createBuffer(entity, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); |
239 | 239 | ||
240 | const auto key = Key(Identifier::fromDisplayByteArray(entity.identifier()), newRevision); | ||
241 | |||
240 | DataStore::mainDatabase(d->transaction, type) | 242 | DataStore::mainDatabase(d->transaction, type) |
241 | .write(DataStore::assembleKey(entity.identifier(), newRevision), BufferUtils::extractBuffer(fbb), | 243 | .write(key.toInternalByteArray(), BufferUtils::extractBuffer(fbb), |
242 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << entity.identifier() << newRevision; }); | 244 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << entity.identifier() << newRevision; }); |
243 | DataStore::setMaxRevision(d->transaction, newRevision); | 245 | DataStore::setMaxRevision(d->transaction, newRevision); |
244 | DataStore::recordRevision(d->transaction, newRevision, entity.identifier(), type); | 246 | DataStore::recordRevision(d->transaction, newRevision, entity.identifier(), type); |
@@ -311,8 +313,10 @@ bool EntityStore::modify(const QByteArray &type, const ApplicationDomainType &cu | |||
311 | flatbuffers::FlatBufferBuilder fbb; | 313 | flatbuffers::FlatBufferBuilder fbb; |
312 | d->resourceContext.adaptorFactory(type).createBuffer(newEntity, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); | 314 | d->resourceContext.adaptorFactory(type).createBuffer(newEntity, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); |
313 | 315 | ||
316 | const auto key = Key(Identifier::fromDisplayByteArray(newEntity.identifier()), newRevision); | ||
317 | |||
314 | DataStore::mainDatabase(d->transaction, type) | 318 | DataStore::mainDatabase(d->transaction, type) |
315 | .write(DataStore::assembleKey(newEntity.identifier(), newRevision), BufferUtils::extractBuffer(fbb), | 319 | .write(key.toInternalByteArray(), BufferUtils::extractBuffer(fbb), |
316 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << newEntity.identifier() << newRevision; }); | 320 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << newEntity.identifier() << newRevision; }); |
317 | DataStore::setMaxRevision(d->transaction, newRevision); | 321 | DataStore::setMaxRevision(d->transaction, newRevision); |
318 | DataStore::recordRevision(d->transaction, newRevision, newEntity.identifier(), type); | 322 | DataStore::recordRevision(d->transaction, newRevision, newEntity.identifier(), type); |
@@ -346,8 +350,10 @@ bool EntityStore::remove(const QByteArray &type, const ApplicationDomainType &cu | |||
346 | flatbuffers::FlatBufferBuilder fbb; | 350 | flatbuffers::FlatBufferBuilder fbb; |
347 | EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), 0, 0, 0, 0); | 351 | EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), 0, 0, 0, 0); |
348 | 352 | ||
353 | const auto key = Key(Identifier::fromDisplayByteArray(uid), newRevision); | ||
354 | |||
349 | DataStore::mainDatabase(d->transaction, type) | 355 | DataStore::mainDatabase(d->transaction, type) |
350 | .write(DataStore::assembleKey(uid, newRevision), BufferUtils::extractBuffer(fbb), | 356 | .write(key.toInternalByteArray(), BufferUtils::extractBuffer(fbb), |
351 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << uid << newRevision; }); | 357 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to write entity" << uid << newRevision; }); |
352 | DataStore::setMaxRevision(d->transaction, newRevision); | 358 | DataStore::setMaxRevision(d->transaction, newRevision); |
353 | DataStore::recordRevision(d->transaction, newRevision, uid, type); | 359 | DataStore::recordRevision(d->transaction, newRevision, uid, type); |
@@ -365,8 +371,9 @@ void EntityStore::cleanupEntityRevisionsUntil(qint64 revision) | |||
365 | return; | 371 | return; |
366 | } | 372 | } |
367 | SinkTraceCtx(d->logCtx) << "Cleaning up revision " << revision << uid << bufferType; | 373 | SinkTraceCtx(d->logCtx) << "Cleaning up revision " << revision << uid << bufferType; |
374 | const auto internalUid = Identifier::fromDisplayByteArray(uid).toInternalByteArray(); | ||
368 | DataStore::mainDatabase(d->transaction, bufferType) | 375 | DataStore::mainDatabase(d->transaction, bufferType) |
369 | .scan(uid, | 376 | .scan(internalUid, |
370 | [&](const QByteArray &key, const QByteArray &data) -> bool { | 377 | [&](const QByteArray &key, const QByteArray &data) -> bool { |
371 | EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); | 378 | EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); |
372 | if (!buffer.isValid()) { | 379 | if (!buffer.isValid()) { |
@@ -428,7 +435,7 @@ QVector<QByteArray> EntityStore::fullScan(const QByteArray &type) | |||
428 | DataStore::mainDatabase(d->getTransaction(), type) | 435 | DataStore::mainDatabase(d->getTransaction(), type) |
429 | .scan(QByteArray(), | 436 | .scan(QByteArray(), |
430 | [&](const QByteArray &key, const QByteArray &value) -> bool { | 437 | [&](const QByteArray &key, const QByteArray &value) -> bool { |
431 | const auto uid = DataStore::uidFromKey(key); | 438 | const auto uid = Sink::Storage::Key::fromInternalByteArray(key).identifier().toDisplayByteArray(); |
432 | if (keys.contains(uid)) { | 439 | if (keys.contains(uid)) { |
433 | //Not something that should persist if the replay works, so we keep a message for now. | 440 | //Not something that should persist if the replay works, so we keep a message for now. |
434 | SinkTraceCtx(d->logCtx) << "Multiple revisions for key: " << key; | 441 | SinkTraceCtx(d->logCtx) << "Multiple revisions for key: " << key; |
@@ -479,16 +486,26 @@ void EntityStore::indexLookup(const QByteArray &type, const QByteArray &property | |||
479 | /* }); */ | 486 | /* }); */ |
480 | } | 487 | } |
481 | 488 | ||
482 | void EntityStore::readLatest(const QByteArray &type, const QByteArray &uid, const std::function<void(const QByteArray &uid, const EntityBuffer &entity)> callback) | 489 | void EntityStore::readLatest(const QByteArray &type, const QByteArray &key, const std::function<void(const QByteArray &uid, const EntityBuffer &entity)> callback) |
483 | { | 490 | { |
484 | Q_ASSERT(d); | 491 | Q_ASSERT(d); |
485 | Q_ASSERT(!uid.isEmpty()); | 492 | Q_ASSERT(!key.isEmpty()); |
493 | // TODO: we shouldn't pass whole keys to this function | ||
494 | // check the testSingle test from querytest | ||
495 | const auto internalKey = [&key]() { | ||
496 | if(key.size() == Identifier::DISPLAY_REPR_SIZE) { | ||
497 | return Identifier::fromDisplayByteArray(key).toInternalByteArray(); | ||
498 | } else { | ||
499 | return Key::fromDisplayByteArray(key).toInternalByteArray(); | ||
500 | } | ||
501 | }(); | ||
486 | auto db = DataStore::mainDatabase(d->getTransaction(), type); | 502 | auto db = DataStore::mainDatabase(d->getTransaction(), type); |
487 | db.findLatest(uid, | 503 | db.findLatest(internalKey, |
488 | [=](const QByteArray &key, const QByteArray &value) { | 504 | [=](const QByteArray &key, const QByteArray &value) { |
489 | callback(DataStore::uidFromKey(key), Sink::EntityBuffer(value.data(), value.size())); | 505 | const auto uid = Sink::Storage::Key::fromInternalByteArray(key).identifier().toDisplayByteArray(); |
506 | callback(uid, Sink::EntityBuffer(value.data(), value.size())); | ||
490 | }, | 507 | }, |
491 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during readLatest query: " << error.message << uid; }); | 508 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during readLatest query: " << error.message << key; }); |
492 | } | 509 | } |
493 | 510 | ||
494 | void EntityStore::readLatest(const QByteArray &type, const QByteArray &uid, const std::function<void(const ApplicationDomainType &)> callback) | 511 | void EntityStore::readLatest(const QByteArray &type, const QByteArray &uid, const std::function<void(const ApplicationDomainType &)> callback) |
@@ -516,12 +533,14 @@ ApplicationDomain::ApplicationDomainType EntityStore::readLatest(const QByteArra | |||
516 | return dt; | 533 | return dt; |
517 | } | 534 | } |
518 | 535 | ||
519 | void EntityStore::readEntity(const QByteArray &type, const QByteArray &key, const std::function<void(const QByteArray &uid, const EntityBuffer &entity)> callback) | 536 | void EntityStore::readEntity(const QByteArray &type, const QByteArray &displayKey, const std::function<void(const QByteArray &uid, const EntityBuffer &entity)> callback) |
520 | { | 537 | { |
538 | const auto key = Key::fromDisplayByteArray(displayKey); | ||
521 | auto db = DataStore::mainDatabase(d->getTransaction(), type); | 539 | auto db = DataStore::mainDatabase(d->getTransaction(), type); |
522 | db.scan(key, | 540 | db.scan(key.toInternalByteArray(), |
523 | [=](const QByteArray &key, const QByteArray &value) -> bool { | 541 | [=](const QByteArray &key, const QByteArray &value) -> bool { |
524 | callback(DataStore::uidFromKey(key), Sink::EntityBuffer(value.data(), value.size())); | 542 | const auto uid = Sink::Storage::Key::fromInternalByteArray(key).identifier().toDisplayByteArray(); |
543 | callback(uid, Sink::EntityBuffer(value.data(), value.size())); | ||
525 | return false; | 544 | return false; |
526 | }, | 545 | }, |
527 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during readEntity query: " << error.message << key; }); | 546 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Error during readEntity query: " << error.message << key; }); |
@@ -567,9 +586,10 @@ void EntityStore::readRevisions(qint64 baseRevision, const QByteArray &expectedT | |||
567 | revisionCounter++; | 586 | revisionCounter++; |
568 | continue; | 587 | continue; |
569 | } | 588 | } |
570 | const auto key = DataStore::assembleKey(uid, revisionCounter); | 589 | const auto key = Key(Identifier::fromDisplayByteArray(uid), revisionCounter); |
590 | |||
571 | revisionCounter++; | 591 | revisionCounter++; |
572 | callback(key); | 592 | callback(key.toDisplayByteArray()); |
573 | } | 593 | } |
574 | } | 594 | } |
575 | 595 | ||
@@ -577,16 +597,18 @@ void EntityStore::readPrevious(const QByteArray &type, const QByteArray &uid, qi | |||
577 | { | 597 | { |
578 | auto db = DataStore::mainDatabase(d->getTransaction(), type); | 598 | auto db = DataStore::mainDatabase(d->getTransaction(), type); |
579 | qint64 latestRevision = 0; | 599 | qint64 latestRevision = 0; |
580 | db.scan(uid, | 600 | const auto internalUid = Identifier::fromDisplayByteArray(uid).toInternalByteArray(); |
601 | db.scan(internalUid, | ||
581 | [&latestRevision, revision](const QByteArray &key, const QByteArray &) -> bool { | 602 | [&latestRevision, revision](const QByteArray &key, const QByteArray &) -> bool { |
582 | const auto foundRevision = DataStore::revisionFromKey(key); | 603 | const auto foundRevision = Key::fromInternalByteArray(key).revision().toQint64(); |
583 | if (foundRevision < revision && foundRevision > latestRevision) { | 604 | if (foundRevision < revision && foundRevision > latestRevision) { |
584 | latestRevision = foundRevision; | 605 | latestRevision = foundRevision; |
585 | } | 606 | } |
586 | return true; | 607 | return true; |
587 | }, | 608 | }, |
588 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to read current value from storage: " << error.message; }, true); | 609 | [&](const DataStore::Error &error) { SinkWarningCtx(d->logCtx) << "Failed to read current value from storage: " << error.message; }, true); |
589 | readEntity(type, DataStore::assembleKey(uid, latestRevision), callback); | 610 | const auto key = Key(Identifier::fromDisplayByteArray(uid), latestRevision); |
611 | readEntity(type, key.toDisplayByteArray(), callback); | ||
590 | } | 612 | } |
591 | 613 | ||
592 | void EntityStore::readPrevious(const QByteArray &type, const QByteArray &uid, qint64 revision, const std::function<void(const ApplicationDomainType &)> callback) | 614 | void EntityStore::readPrevious(const QByteArray &type, const QByteArray &uid, qint64 revision, const std::function<void(const ApplicationDomainType &)> callback) |
@@ -612,15 +634,18 @@ void EntityStore::readAllUids(const QByteArray &type, const std::function<void(c | |||
612 | 634 | ||
613 | bool EntityStore::contains(const QByteArray &type, const QByteArray &uid) | 635 | bool EntityStore::contains(const QByteArray &type, const QByteArray &uid) |
614 | { | 636 | { |
615 | return DataStore::mainDatabase(d->getTransaction(), type).contains(uid); | 637 | Q_ASSERT(!uid.isEmpty()); |
638 | const auto internalUid = Identifier::fromDisplayByteArray(uid).toInternalByteArray(); | ||
639 | return DataStore::mainDatabase(d->getTransaction(), type).contains(internalUid); | ||
616 | } | 640 | } |
617 | 641 | ||
618 | bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) | 642 | bool EntityStore::exists(const QByteArray &type, const QByteArray &uid) |
619 | { | 643 | { |
620 | bool found = false; | 644 | bool found = false; |
621 | bool alreadyRemoved = false; | 645 | bool alreadyRemoved = false; |
646 | const auto internalUid = Identifier::fromDisplayByteArray(uid).toInternalByteArray(); | ||
622 | DataStore::mainDatabase(d->transaction, type) | 647 | DataStore::mainDatabase(d->transaction, type) |
623 | .findLatest(uid, | 648 | .findLatest(internalUid, |
624 | [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) { | 649 | [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) { |
625 | auto entity = GetEntity(data.data()); | 650 | auto entity = GetEntity(data.data()); |
626 | if (entity && entity->metadata()) { | 651 | if (entity && entity->metadata()) { |
@@ -647,12 +672,14 @@ void EntityStore::readRevisions(const QByteArray &type, const QByteArray &uid, q | |||
647 | { | 672 | { |
648 | Q_ASSERT(d); | 673 | Q_ASSERT(d); |
649 | Q_ASSERT(!uid.isEmpty()); | 674 | Q_ASSERT(!uid.isEmpty()); |
675 | const auto internalUid = Identifier::fromDisplayByteArray(uid).toInternalByteArray(); | ||
650 | DataStore::mainDatabase(d->transaction, type) | 676 | DataStore::mainDatabase(d->transaction, type) |
651 | .scan(uid, | 677 | .scan(internalUid, |
652 | [&](const QByteArray &key, const QByteArray &value) -> bool { | 678 | [&](const QByteArray &key, const QByteArray &value) -> bool { |
653 | const auto revision = DataStore::revisionFromKey(key); | 679 | const auto parsedKey = Key::fromInternalByteArray(key); |
680 | const auto revision = parsedKey.revision().toQint64(); | ||
654 | if (revision >= startingRevision) { | 681 | if (revision >= startingRevision) { |
655 | callback(DataStore::uidFromKey(key), revision, Sink::EntityBuffer(value.data(), value.size())); | 682 | callback(parsedKey.identifier().toDisplayByteArray(), revision, Sink::EntityBuffer(value.data(), value.size())); |
656 | } | 683 | } |
657 | return true; | 684 | return true; |
658 | }, | 685 | }, |
diff --git a/common/storage/entitystore.h b/common/storage/entitystore.h index 69de76c..1dcd285 100644 --- a/common/storage/entitystore.h +++ b/common/storage/entitystore.h | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "domaintypeadaptorfactoryinterface.h" | 25 | #include "domaintypeadaptorfactoryinterface.h" |
26 | #include "query.h" | 26 | #include "query.h" |
27 | #include "storage.h" | 27 | #include "storage.h" |
28 | #include "key.h" | ||
28 | #include "resourcecontext.h" | 29 | #include "resourcecontext.h" |
29 | #include "metadata_generated.h" | 30 | #include "metadata_generated.h" |
30 | 31 | ||
diff --git a/common/storage/key.cpp b/common/storage/key.cpp new file mode 100644 index 0000000..01a3e3a --- /dev/null +++ b/common/storage/key.cpp | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * Copyright (C) 2018 Rémi Nicole <minijackson@riseup.net> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) version 3, or any | ||
9 | * later version accepted by the membership of KDE e.V. (or its | ||
10 | * successor approved by the membership of KDE e.V.), which shall | ||
11 | * act as a proxy defined in Section 6 of version 3 of the license. | ||
12 | * | ||
13 | * This library is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include "key.h" | ||
23 | #include "utils.h" | ||
24 | |||
25 | using Sink::Storage::Identifier; | ||
26 | using Sink::Storage::Key; | ||
27 | using Sink::Storage::Revision; | ||
28 | |||
29 | QDebug &operator<<(QDebug &dbg, const Identifier &id) | ||
30 | { | ||
31 | dbg << id.toDisplayString(); | ||
32 | return dbg; | ||
33 | } | ||
34 | |||
35 | QDebug &operator<<(QDebug &dbg, const Revision &rev) | ||
36 | { | ||
37 | dbg << rev.toDisplayString(); | ||
38 | return dbg; | ||
39 | } | ||
40 | |||
41 | QDebug &operator<<(QDebug &dbg, const Key &key) | ||
42 | { | ||
43 | dbg << key.toDisplayString(); | ||
44 | return dbg; | ||
45 | } | ||
46 | |||
47 | // Identifier | ||
48 | |||
49 | QByteArray Identifier::toInternalByteArray() const | ||
50 | { | ||
51 | return uid.toRfc4122(); | ||
52 | } | ||
53 | |||
54 | Identifier Identifier::fromInternalByteArray(const QByteArray &bytes) | ||
55 | { | ||
56 | Q_ASSERT(bytes.size() == INTERNAL_REPR_SIZE); | ||
57 | return Identifier(QUuid::fromRfc4122(bytes)); | ||
58 | } | ||
59 | |||
60 | QString Identifier::toDisplayString() const | ||
61 | { | ||
62 | return uid.toString(); | ||
63 | } | ||
64 | |||
65 | QByteArray Identifier::toDisplayByteArray() const | ||
66 | { | ||
67 | return uid.toByteArray(); | ||
68 | } | ||
69 | |||
70 | Identifier Identifier::fromDisplayByteArray(const QByteArray &bytes) | ||
71 | { | ||
72 | Q_ASSERT(bytes.size() == DISPLAY_REPR_SIZE); | ||
73 | return Identifier(QUuid(bytes)); | ||
74 | } | ||
75 | |||
76 | // Revision | ||
77 | |||
78 | QByteArray Revision::toInternalByteArray() const | ||
79 | { | ||
80 | return padNumber(rev); | ||
81 | } | ||
82 | |||
83 | Revision Revision::fromInternalByteArray(const QByteArray &bytes) | ||
84 | { | ||
85 | Q_ASSERT(bytes.size() == INTERNAL_REPR_SIZE); | ||
86 | return Revision(bytes.toLongLong()); | ||
87 | } | ||
88 | |||
89 | QString Revision::toDisplayString() const | ||
90 | { | ||
91 | return QString::fromUtf8(toInternalByteArray()); | ||
92 | } | ||
93 | |||
94 | QByteArray Revision::toDisplayByteArray() const | ||
95 | { | ||
96 | return toInternalByteArray(); | ||
97 | } | ||
98 | |||
99 | Revision Revision::fromDisplayByteArray(const QByteArray &bytes) | ||
100 | { | ||
101 | Q_ASSERT(bytes.size() == DISPLAY_REPR_SIZE); | ||
102 | return fromInternalByteArray(bytes); | ||
103 | } | ||
104 | |||
105 | qint64 Revision::toQint64() const | ||
106 | { | ||
107 | return rev; | ||
108 | } | ||
109 | |||
110 | // Key | ||
111 | |||
112 | QByteArray Key::toInternalByteArray() const | ||
113 | { | ||
114 | return id.toInternalByteArray() + rev.toInternalByteArray(); | ||
115 | } | ||
116 | |||
117 | Key Key::fromInternalByteArray(const QByteArray &bytes) | ||
118 | { | ||
119 | Q_ASSERT(bytes.size() == INTERNAL_REPR_SIZE); | ||
120 | auto idBytes = bytes.mid(0, Identifier::INTERNAL_REPR_SIZE); | ||
121 | auto revBytes = bytes.mid(Identifier::INTERNAL_REPR_SIZE); | ||
122 | return Key(Identifier::fromInternalByteArray(idBytes), Revision::fromInternalByteArray(revBytes)); | ||
123 | } | ||
124 | |||
125 | QString Key::toDisplayString() const | ||
126 | { | ||
127 | return id.toDisplayString() + rev.toDisplayString(); | ||
128 | } | ||
129 | |||
130 | QByteArray Key::toDisplayByteArray() const | ||
131 | { | ||
132 | return id.toDisplayByteArray() + rev.toDisplayByteArray(); | ||
133 | } | ||
134 | |||
135 | Key Key::fromDisplayByteArray(const QByteArray &bytes) | ||
136 | { | ||
137 | Q_ASSERT(bytes.size() == DISPLAY_REPR_SIZE); | ||
138 | auto idBytes = bytes.mid(0, Identifier::DISPLAY_REPR_SIZE); | ||
139 | auto revBytes = bytes.mid(Identifier::DISPLAY_REPR_SIZE); | ||
140 | return Key(Identifier::fromDisplayByteArray(idBytes), Revision::fromDisplayByteArray(revBytes)); | ||
141 | } | ||
142 | |||
143 | const Identifier &Key::identifier() const | ||
144 | { | ||
145 | return id; | ||
146 | } | ||
147 | |||
148 | const Revision &Key::revision() const | ||
149 | { | ||
150 | return rev; | ||
151 | } | ||
152 | |||
153 | void Key::setRevision(const Revision &newRev) | ||
154 | { | ||
155 | rev = newRev; | ||
156 | } | ||
diff --git a/common/storage/key.h b/common/storage/key.h new file mode 100644 index 0000000..76dbd13 --- /dev/null +++ b/common/storage/key.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm> | ||
3 | * Copyright (C) 2018 Rémi Nicole <minijackson@riseup.net> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2.1 of the License, or (at your option) version 3, or any | ||
9 | * later version accepted by the membership of KDE e.V. (or its | ||
10 | * successor approved by the membership of KDE e.V.), which shall | ||
11 | * act as a proxy defined in Section 6 of version 3 of the license. | ||
12 | * | ||
13 | * This library is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * Lesser General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU Lesser General Public | ||
19 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #pragma once | ||
23 | |||
24 | #include "sink_export.h" | ||
25 | |||
26 | #include <QByteArray> | ||
27 | #include <QDebug> | ||
28 | #include <QUuid> | ||
29 | |||
30 | namespace Sink { | ||
31 | namespace Storage { | ||
32 | |||
33 | class Identifier | ||
34 | { | ||
35 | public: | ||
36 | // RFC 4122 Section 4.1.2 says 128 bits -> 16 bytes | ||
37 | static const constexpr size_t INTERNAL_REPR_SIZE = 16; | ||
38 | static const constexpr size_t DISPLAY_REPR_SIZE = 38; | ||
39 | |||
40 | Identifier() : uid(QUuid::createUuid()){}; | ||
41 | |||
42 | QByteArray toInternalByteArray() const; | ||
43 | static Identifier fromInternalByteArray(const QByteArray &bytes); | ||
44 | QString toDisplayString() const; | ||
45 | QByteArray toDisplayByteArray() const; | ||
46 | static Identifier fromDisplayByteArray(const QByteArray &bytes); | ||
47 | |||
48 | private: | ||
49 | explicit Identifier(const QUuid &uid) : uid(uid) {} | ||
50 | QUuid uid; | ||
51 | }; | ||
52 | |||
53 | class Revision | ||
54 | { | ||
55 | public: | ||
56 | // qint64 has a 19 digit decimal representation | ||
57 | static const constexpr size_t INTERNAL_REPR_SIZE = 19; | ||
58 | static const constexpr size_t DISPLAY_REPR_SIZE = 19; | ||
59 | |||
60 | Revision(qint64 rev) : rev(rev) {} | ||
61 | |||
62 | QByteArray toInternalByteArray() const; | ||
63 | static Revision fromInternalByteArray(const QByteArray &bytes); | ||
64 | QString toDisplayString() const; | ||
65 | QByteArray toDisplayByteArray() const; | ||
66 | static Revision fromDisplayByteArray(const QByteArray &bytes); | ||
67 | qint64 toQint64() const; | ||
68 | |||
69 | private: | ||
70 | qint64 rev; | ||
71 | }; | ||
72 | |||
73 | class Key | ||
74 | { | ||
75 | public: | ||
76 | static const constexpr size_t INTERNAL_REPR_SIZE = Identifier::INTERNAL_REPR_SIZE + Revision::INTERNAL_REPR_SIZE; | ||
77 | static const constexpr size_t DISPLAY_REPR_SIZE = Identifier::DISPLAY_REPR_SIZE + Revision::DISPLAY_REPR_SIZE; | ||
78 | |||
79 | Key(const Identifier &id, const Revision &rev) : id(id), rev(rev) {} | ||
80 | |||
81 | QByteArray toInternalByteArray() const; | ||
82 | static Key fromInternalByteArray(const QByteArray &bytes); | ||
83 | QString toDisplayString() const; | ||
84 | QByteArray toDisplayByteArray() const; | ||
85 | static Key fromDisplayByteArray(const QByteArray &bytes); | ||
86 | const Identifier &identifier() const; | ||
87 | const Revision &revision() const; | ||
88 | void setRevision(const Revision &newRev); | ||
89 | |||
90 | private: | ||
91 | Identifier id; | ||
92 | Revision rev; | ||
93 | }; | ||
94 | |||
95 | } // namespace Storage | ||
96 | } // namespace Sink | ||
97 | |||
98 | SINK_EXPORT QDebug& operator<<(QDebug &dbg, const Sink::Storage::Identifier &); | ||
99 | SINK_EXPORT QDebug& operator<<(QDebug &dbg, const Sink::Storage::Revision &); | ||
100 | SINK_EXPORT QDebug& operator<<(QDebug &dbg, const Sink::Storage::Key &); | ||
diff --git a/common/storage_common.cpp b/common/storage_common.cpp index 057dce4..f96097a 100644 --- a/common/storage_common.cpp +++ b/common/storage_common.cpp | |||
@@ -194,23 +194,6 @@ bool DataStore::isInternalKey(const QByteArray &key) | |||
194 | return key.startsWith(s_internalPrefix); | 194 | return key.startsWith(s_internalPrefix); |
195 | } | 195 | } |
196 | 196 | ||
197 | QByteArray DataStore::assembleKey(const QByteArray &key, qint64 revision) | ||
198 | { | ||
199 | Q_ASSERT(revision <= 9223372036854775807); | ||
200 | Q_ASSERT(key.size() == s_lengthOfUid); | ||
201 | return key + QByteArray::number(revision).rightJustified(19, '0', false); | ||
202 | } | ||
203 | |||
204 | QByteArray DataStore::uidFromKey(const QByteArray &key) | ||
205 | { | ||
206 | return key.mid(0, s_lengthOfUid); | ||
207 | } | ||
208 | |||
209 | qint64 DataStore::revisionFromKey(const QByteArray &key) | ||
210 | { | ||
211 | return key.mid(s_lengthOfUid + 1).toLongLong(); | ||
212 | } | ||
213 | |||
214 | QByteArray DataStore::generateUid() | 197 | QByteArray DataStore::generateUid() |
215 | { | 198 | { |
216 | return createUuid(); | 199 | return createUuid(); |
diff --git a/common/synchronizer.cpp b/common/synchronizer.cpp index 71091a6..a43ec06 100644 --- a/common/synchronizer.cpp +++ b/common/synchronizer.cpp | |||
@@ -616,7 +616,8 @@ KAsync::Job<void> Synchronizer::replay(const QByteArray &type, const QByteArray | |||
616 | Q_ASSERT(mEntityStore->hasTransaction()); | 616 | Q_ASSERT(mEntityStore->hasTransaction()); |
617 | 617 | ||
618 | const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation; | 618 | const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation; |
619 | const auto uid = Sink::Storage::DataStore::uidFromKey(key); | 619 | // TODO: should not use internal representations |
620 | const auto uid = Sink::Storage::Key::fromDisplayByteArray(key).identifier().toDisplayByteArray(); | ||
620 | const auto modifiedProperties = metadataBuffer->modifiedProperties() ? BufferUtils::fromVector(*metadataBuffer->modifiedProperties()) : QByteArrayList(); | 621 | const auto modifiedProperties = metadataBuffer->modifiedProperties() ? BufferUtils::fromVector(*metadataBuffer->modifiedProperties()) : QByteArrayList(); |
621 | QByteArray oldRemoteId; | 622 | QByteArray oldRemoteId; |
622 | 623 | ||
diff --git a/common/typeindex.cpp b/common/typeindex.cpp index b18791f..0b78d59 100644 --- a/common/typeindex.cpp +++ b/common/typeindex.cpp | |||
@@ -25,8 +25,6 @@ | |||
25 | #include <QDateTime> | 25 | #include <QDateTime> |
26 | #include <QDataStream> | 26 | #include <QDataStream> |
27 | 27 | ||
28 | #include <cmath> | ||
29 | |||
30 | using namespace Sink; | 28 | using namespace Sink; |
31 | 29 | ||
32 | static QByteArray getByteArray(const QVariant &value) | 30 | static QByteArray getByteArray(const QVariant &value) |
@@ -53,13 +51,6 @@ static QByteArray getByteArray(const QVariant &value) | |||
53 | return "toplevel"; | 51 | return "toplevel"; |
54 | } | 52 | } |
55 | 53 | ||
56 | template <typename T> | ||
57 | static QByteArray padNumber(T number) | ||
58 | { | ||
59 | static T uint_num_digits = (T)std::log10(std::numeric_limits<T>::max()) + 1; | ||
60 | return QByteArray::number(number).rightJustified(uint_num_digits, '0'); | ||
61 | } | ||
62 | |||
63 | static QByteArray toSortableByteArrayImpl(const QDateTime &date) | 54 | static QByteArray toSortableByteArrayImpl(const QDateTime &date) |
64 | { | 55 | { |
65 | // Sort invalid last | 56 | // Sort invalid last |
diff --git a/common/utils.h b/common/utils.h index 253de61..7066d79 100644 --- a/common/utils.h +++ b/common/utils.h | |||
@@ -20,6 +20,17 @@ | |||
20 | 20 | ||
21 | #include <QByteArray> | 21 | #include <QByteArray> |
22 | 22 | ||
23 | #include <cmath> | ||
24 | |||
23 | namespace Sink { | 25 | namespace Sink { |
24 | QByteArray createUuid(); | 26 | |
27 | QByteArray createUuid(); | ||
28 | |||
29 | template <typename T> | ||
30 | static QByteArray padNumber(T number) | ||
31 | { | ||
32 | static T uint_num_digits = (T)std::log10(std::numeric_limits<T>::max()) + 1; | ||
33 | return QByteArray::number(number).rightJustified(uint_num_digits, '0'); | ||
25 | } | 34 | } |
35 | |||
36 | } // namespace Sink | ||