diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2015-10-06 16:19:51 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2015-10-10 10:40:01 +0200 |
commit | f689ad1021a7805f6f8b6a81f534b4cb9ca91f51 (patch) | |
tree | c18d746b775279f143c8d8052924bb4d83fbb91f | |
parent | c3f6e72c2d46906a4699127b558ca248729ce577 (diff) | |
download | sink-f689ad1021a7805f6f8b6a81f534b4cb9ca91f51.tar.gz sink-f689ad1021a7805f6f8b6a81f534b4cb9ca91f51.zip |
Change replay
So far only includes modifications and additions,
removals are not yet stored as separate revisions.
-rw-r--r-- | common/entitystorage.cpp | 75 | ||||
-rw-r--r-- | common/entitystorage.h | 38 | ||||
-rw-r--r-- | common/facade.h | 4 | ||||
-rw-r--r-- | common/genericresource.cpp | 3 | ||||
-rw-r--r-- | common/pipeline.cpp | 3 | ||||
-rw-r--r-- | common/resourceaccess.h | 2 | ||||
-rw-r--r-- | common/resultset.h | 12 | ||||
-rw-r--r-- | common/storage_common.cpp | 19 | ||||
-rw-r--r-- | examples/client/main.cpp | 4 | ||||
-rw-r--r-- | tests/dummyresourcetest.cpp | 4 | ||||
-rw-r--r-- | tests/genericfacadetest.cpp | 5 | ||||
-rw-r--r-- | tests/storagetest.cpp | 9 |
12 files changed, 131 insertions, 47 deletions
diff --git a/common/entitystorage.cpp b/common/entitystorage.cpp index 0eb2763..60d58ad 100644 --- a/common/entitystorage.cpp +++ b/common/entitystorage.cpp | |||
@@ -44,18 +44,21 @@ static void scan(const Akonadi2::Storage::Transaction &transaction, const QByteA | |||
44 | }); | 44 | }); |
45 | } | 45 | } |
46 | 46 | ||
47 | void EntityStorageBase::readValue(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)> &resultCallback) | 47 | void EntityStorageBase::readEntity(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)> &resultCallback) |
48 | { | 48 | { |
49 | //This only works for a 1:1 mapping of resource to domain types. | ||
50 | //Not i.e. for tags that are stored as flags in each entity of an imap store. | ||
51 | //additional properties that don't have a 1:1 mapping (such as separately stored tags), | ||
52 | //could be added to the adaptor. | ||
53 | //TODO: resource implementations should be able to customize the retrieval function for non 1:1 entity-buffer mapping cases | ||
49 | scan(transaction, key, [=](const QByteArray &key, const Akonadi2::Entity &entity) { | 54 | scan(transaction, key, [=](const QByteArray &key, const Akonadi2::Entity &entity) { |
50 | const auto metadataBuffer = Akonadi2::EntityBuffer::readBuffer<Akonadi2::Metadata>(entity.metadata()); | 55 | const auto metadataBuffer = Akonadi2::EntityBuffer::readBuffer<Akonadi2::Metadata>(entity.metadata()); |
56 | Q_ASSERT(metadataBuffer); | ||
51 | qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; | 57 | qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; |
52 | //This only works for a 1:1 mapping of resource to domain types. | 58 | auto operation = metadataBuffer->operation(); |
53 | //Not i.e. for tags that are stored as flags in each entity of an imap store. | ||
54 | //additional properties that don't have a 1:1 mapping (such as separately stored tags), | ||
55 | //could be added to the adaptor. | ||
56 | 59 | ||
57 | auto domainObject = create(key, revision, mDomainTypeAdaptorFactory->createAdaptor(entity)); | 60 | auto domainObject = create(key, revision, mDomainTypeAdaptorFactory->createAdaptor(entity)); |
58 | resultCallback(domainObject); | 61 | resultCallback(domainObject, operation); |
59 | return false; | 62 | return false; |
60 | }, mBufferType); | 63 | }, mBufferType); |
61 | } | 64 | } |
@@ -80,16 +83,22 @@ static ResultSet fullScan(const Akonadi2::Storage::Transaction &transaction, con | |||
80 | return ResultSet(keys); | 83 | return ResultSet(keys); |
81 | } | 84 | } |
82 | 85 | ||
83 | ResultSet EntityStorageBase::filteredSet(const ResultSet &resultSet, const std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision) | 86 | ResultSet EntityStorageBase::filteredSet(const ResultSet &resultSet, const std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Akonadi2::Storage::Transaction &transaction, bool initialQuery) |
84 | { | 87 | { |
85 | auto resultSetPtr = QSharedPointer<ResultSet>::create(resultSet); | 88 | auto resultSetPtr = QSharedPointer<ResultSet>::create(resultSet); |
86 | 89 | ||
87 | //Read through the source values and return whatever matches the filter | 90 | //Read through the source values and return whatever matches the filter |
88 | std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)>)> generator = [this, resultSetPtr, &transaction, filter](std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)> callback) -> bool { | 91 | std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)>)> generator = [this, resultSetPtr, &transaction, filter, initialQuery](std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)> callback) -> bool { |
89 | while (resultSetPtr->next()) { | 92 | while (resultSetPtr->next()) { |
90 | readValue(transaction, resultSetPtr->id(), [this, filter, callback](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) { | 93 | //TODO. every read value is actually a revision that contains one of three operations. Reflect that so the result set can be updated appropriately. |
94 | //TODO while getting the initial set everything is adding | ||
95 | readEntity(transaction, resultSetPtr->id(), [this, filter, callback, initialQuery](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Akonadi2::Operation operation) { | ||
91 | if (filter(domainObject)) { | 96 | if (filter(domainObject)) { |
92 | callback(domainObject); | 97 | if (initialQuery) { |
98 | callback(domainObject, Akonadi2::Operation_Creation); | ||
99 | } else { | ||
100 | callback(domainObject, operation); | ||
101 | } | ||
93 | } | 102 | } |
94 | }); | 103 | }); |
95 | } | 104 | } |
@@ -98,15 +107,51 @@ ResultSet EntityStorageBase::filteredSet(const ResultSet &resultSet, const std:: | |||
98 | return ResultSet(generator); | 107 | return ResultSet(generator); |
99 | } | 108 | } |
100 | 109 | ||
101 | ResultSet EntityStorageBase::getResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision) | 110 | ResultSet EntityStorageBase::loadInitialResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters) |
102 | { | 111 | { |
103 | QSet<QByteArray> appliedFilters; | 112 | QSet<QByteArray> appliedFilters; |
104 | ResultSet resultSet = queryIndexes(query, mResourceInstanceIdentifier, appliedFilters, transaction); | 113 | auto resultSet = queryIndexes(query, mResourceInstanceIdentifier, appliedFilters, transaction); |
105 | const auto remainingFilters = query.propertyFilter.keys().toSet() - appliedFilters; | 114 | remainingFilters = query.propertyFilter.keys().toSet() - appliedFilters; |
106 | 115 | ||
107 | //We do a full scan if there were no indexes available to create the initial set. | 116 | //We do a full scan if there were no indexes available to create the initial set. |
108 | if (appliedFilters.isEmpty()) { | 117 | if (appliedFilters.isEmpty()) { |
109 | resultSet = fullScan(transaction, mBufferType); | 118 | //TODO this should be replaced by an index lookup as well |
119 | return fullScan(transaction, mBufferType); | ||
120 | } | ||
121 | return resultSet; | ||
122 | } | ||
123 | |||
124 | ResultSet EntityStorageBase::getResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision) | ||
125 | { | ||
126 | QSet<QByteArray> remainingFilters = query.propertyFilter.keys().toSet(); | ||
127 | ResultSet resultSet; | ||
128 | const bool initialQuery = (baseRevision == 0); | ||
129 | if (initialQuery) { | ||
130 | Trace() << "Initial result set update"; | ||
131 | resultSet = loadInitialResultSet(query, transaction, remainingFilters); | ||
132 | } else { | ||
133 | //TODO fallback in case the old revision is no longer available to clear + redo complete initial scan | ||
134 | Trace() << "Incremental result set update" << baseRevision << topRevision; | ||
135 | auto revisionCounter = QSharedPointer<qint64>::create(baseRevision); | ||
136 | resultSet = ResultSet([revisionCounter, topRevision, &transaction, this]() -> QByteArray { | ||
137 | //Spit out the revision keys one by one. | ||
138 | while (*revisionCounter <= topRevision) { | ||
139 | const auto uid = Akonadi2::Storage::getUidFromRevision(transaction, *revisionCounter); | ||
140 | const auto type = Akonadi2::Storage::getTypeFromRevision(transaction, *revisionCounter); | ||
141 | Trace() << "Revision" << *revisionCounter << type << uid; | ||
142 | if (type != mBufferType) { | ||
143 | //Skip revision | ||
144 | *revisionCounter += 1; | ||
145 | continue; | ||
146 | } | ||
147 | const auto key = Akonadi2::Storage::assembleKey(uid, *revisionCounter); | ||
148 | *revisionCounter += 1; | ||
149 | return key; | ||
150 | } | ||
151 | //We're done | ||
152 | //FIXME make sure result set understands that this means we're done | ||
153 | return QByteArray(); | ||
154 | }); | ||
110 | } | 155 | } |
111 | 156 | ||
112 | auto filter = [remainingFilters, query, baseRevision, topRevision](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool { | 157 | auto filter = [remainingFilters, query, baseRevision, topRevision](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool { |
@@ -125,5 +170,5 @@ ResultSet EntityStorageBase::getResultSet(const Akonadi2::Query &query, Akonadi2 | |||
125 | return true; | 170 | return true; |
126 | }; | 171 | }; |
127 | 172 | ||
128 | return filteredSet(resultSet, filter, transaction, baseRevision, topRevision); | 173 | return filteredSet(resultSet, filter, transaction, initialQuery); |
129 | } | 174 | } |
diff --git a/common/entitystorage.h b/common/entitystorage.h index 9d928b8..f1d7f84 100644 --- a/common/entitystorage.h +++ b/common/entitystorage.h | |||
@@ -31,6 +31,8 @@ | |||
31 | 31 | ||
32 | /** | 32 | /** |
33 | * Wraps storage, entity adaptor factory and indexes into one. | 33 | * Wraps storage, entity adaptor factory and indexes into one. |
34 | * | ||
35 | * TODO: customize with readEntity instead of adaptor factory | ||
34 | */ | 36 | */ |
35 | class EntityStorageBase | 37 | class EntityStorageBase |
36 | { | 38 | { |
@@ -46,14 +48,26 @@ protected: | |||
46 | virtual Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr copy(const Akonadi2::ApplicationDomain::ApplicationDomainType &) = 0; | 48 | virtual Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr copy(const Akonadi2::ApplicationDomain::ApplicationDomainType &) = 0; |
47 | virtual ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) = 0; | 49 | virtual ResultSet queryIndexes(const Akonadi2::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, Akonadi2::Storage::Transaction &transaction) = 0; |
48 | 50 | ||
49 | void readValue(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)> &resultCallback); | 51 | /** |
50 | ResultSet filteredSet(const ResultSet &resultSet, const std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision); | 52 | * Loads a single entity by uid from storage. |
53 | * | ||
54 | * TODO: Resources should be able to customize this for cases where an entity is not the same as a single buffer. | ||
55 | */ | ||
56 | void readEntity(const Akonadi2::Storage::Transaction &transaction, const QByteArray &key, const std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)> &resultCallback); | ||
51 | ResultSet getResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision); | 57 | ResultSet getResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, qint64 baseRevision, qint64 topRevision); |
52 | 58 | ||
53 | protected: | 59 | protected: |
54 | QByteArray mResourceInstanceIdentifier; | 60 | QByteArray mResourceInstanceIdentifier; |
55 | QByteArray mBufferType; | 61 | QByteArray mBufferType; |
56 | DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory; | 62 | DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory; |
63 | private: | ||
64 | /** | ||
65 | * Returns the initial result set that still needs to be filtered. | ||
66 | * | ||
67 | * To make this efficient indexes should be chosen that are as selective as possible. | ||
68 | */ | ||
69 | ResultSet loadInitialResultSet(const Akonadi2::Query &query, Akonadi2::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters); | ||
70 | ResultSet filteredSet(const ResultSet &resultSet, const std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Akonadi2::Storage::Transaction &transaction, bool isInitialQuery); | ||
57 | }; | 71 | }; |
58 | 72 | ||
59 | template<typename DomainType> | 73 | template<typename DomainType> |
@@ -95,13 +109,25 @@ public: | |||
95 | auto transaction = storage.createTransaction(Akonadi2::Storage::ReadOnly); | 109 | auto transaction = storage.createTransaction(Akonadi2::Storage::ReadOnly); |
96 | 110 | ||
97 | Log() << "Querying" << revisionRange.first << revisionRange.second; | 111 | Log() << "Querying" << revisionRange.first << revisionRange.second; |
112 | //TODO fallback in case the old revision is no longer available to clear + redo complete initial scan | ||
113 | // | ||
98 | auto resultSet = getResultSet(query, transaction, revisionRange.first, revisionRange.second); | 114 | auto resultSet = getResultSet(query, transaction, revisionRange.first, revisionRange.second); |
99 | while(resultSet.next([this, resultProvider](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &value) -> bool { | 115 | while(resultSet.next([this, resultProvider](const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &value, Akonadi2::Operation operation) -> bool { |
100 | auto cloned = copy(*value); | 116 | switch (operation) { |
101 | resultProvider->add(cloned.template staticCast<DomainType>()); | 117 | case Akonadi2::Operation_Creation: |
118 | Trace() << "Got creation"; | ||
119 | resultProvider->add(copy(*value).template staticCast<DomainType>()); | ||
120 | break; | ||
121 | case Akonadi2::Operation_Modification: | ||
122 | Trace() << "Got modification"; | ||
123 | resultProvider->add(copy(*value).template staticCast<DomainType>()); | ||
124 | break; | ||
125 | case Akonadi2::Operation_Removal: | ||
126 | Trace() << "Got removal"; | ||
127 | break; | ||
128 | } | ||
102 | return true; | 129 | return true; |
103 | })){}; | 130 | })){}; |
104 | //TODO replay removals and modifications | ||
105 | } | 131 | } |
106 | 132 | ||
107 | }; | 133 | }; |
diff --git a/common/facade.h b/common/facade.h index d53ec4a..dab1578 100644 --- a/common/facade.h +++ b/common/facade.h | |||
@@ -56,8 +56,8 @@ public: | |||
56 | if (mLatestRevision == newRevision && mLatestRevision > 0) { | 56 | if (mLatestRevision == newRevision && mLatestRevision > 0) { |
57 | return KAsync::null<void>(); | 57 | return KAsync::null<void>(); |
58 | } | 58 | } |
59 | return queryFunction(mLatestRevision + 1, newRevision).then<void, qint64>([this](qint64 revision) { | 59 | return queryFunction(mLatestRevision, newRevision).then<void, qint64>([this](qint64 revision) { |
60 | mLatestRevision = revision; | 60 | mLatestRevision = revision + 1; |
61 | }).then<void>([](){}); | 61 | }).then<void>([](){}); |
62 | } | 62 | } |
63 | 63 | ||
diff --git a/common/genericresource.cpp b/common/genericresource.cpp index 4abcecd..acf84c4 100644 --- a/common/genericresource.cpp +++ b/common/genericresource.cpp | |||
@@ -204,10 +204,11 @@ void GenericResource::enqueueCommand(MessageQueue &mq, int commandId, const QByt | |||
204 | void GenericResource::processCommand(int commandId, const QByteArray &data) | 204 | void GenericResource::processCommand(int commandId, const QByteArray &data) |
205 | { | 205 | { |
206 | static int modifications = 0; | 206 | static int modifications = 0; |
207 | const int batchSize = 100; | ||
207 | mUserQueue.startTransaction(); | 208 | mUserQueue.startTransaction(); |
208 | enqueueCommand(mUserQueue, commandId, data); | 209 | enqueueCommand(mUserQueue, commandId, data); |
209 | modifications++; | 210 | modifications++; |
210 | if (modifications >= 100) { | 211 | if (modifications >= batchSize) { |
211 | mUserQueue.commit(); | 212 | mUserQueue.commit(); |
212 | modifications = 0; | 213 | modifications = 0; |
213 | mCommitQueueTimer.stop(); | 214 | mCommitQueueTimer.stop(); |
diff --git a/common/pipeline.cpp b/common/pipeline.cpp index c108540..6c75bde 100644 --- a/common/pipeline.cpp +++ b/common/pipeline.cpp | |||
@@ -220,6 +220,7 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size) | |||
220 | } | 220 | } |
221 | } | 221 | } |
222 | 222 | ||
223 | //TODO use only readPropertyMapper and writePropertyMapper | ||
223 | auto adaptorFactory = d->adaptorFactory.value(bufferType); | 224 | auto adaptorFactory = d->adaptorFactory.value(bufferType); |
224 | if (!adaptorFactory) { | 225 | if (!adaptorFactory) { |
225 | Warning() << "no adaptor factory for type " << bufferType; | 226 | Warning() << "no adaptor factory for type " << bufferType; |
@@ -255,6 +256,7 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size) | |||
255 | 256 | ||
256 | //Apply diff | 257 | //Apply diff |
257 | //FIXME only apply the properties that are available in the buffer | 258 | //FIXME only apply the properties that are available in the buffer |
259 | Trace() << "Applying changed properties: " << diff->availableProperties(); | ||
258 | for (const auto &property : diff->availableProperties()) { | 260 | for (const auto &property : diff->availableProperties()) { |
259 | newObject->setProperty(property, diff->getProperty(property)); | 261 | newObject->setProperty(property, diff->getProperty(property)); |
260 | } | 262 | } |
@@ -277,7 +279,6 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size) | |||
277 | flatbuffers::FlatBufferBuilder fbb; | 279 | flatbuffers::FlatBufferBuilder fbb; |
278 | adaptorFactory->createBuffer(*newObject, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); | 280 | adaptorFactory->createBuffer(*newObject, fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); |
279 | 281 | ||
280 | //TODO don't overwrite the old entry, but instead store a new revision | ||
281 | d->transaction.openDatabase(bufferType + ".main").write(Akonadi2::Storage::assembleKey(key, newRevision), QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); | 282 | d->transaction.openDatabase(bufferType + ".main").write(Akonadi2::Storage::assembleKey(key, newRevision), QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize())); |
282 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); | 283 | Akonadi2::Storage::setMaxRevision(d->transaction, newRevision); |
283 | Akonadi2::Storage::recordRevision(d->transaction, newRevision, key, bufferType); | 284 | Akonadi2::Storage::recordRevision(d->transaction, newRevision, key, bufferType); |
diff --git a/common/resourceaccess.h b/common/resourceaccess.h index e6b9d91..1ff9ca6 100644 --- a/common/resourceaccess.h +++ b/common/resourceaccess.h | |||
@@ -49,7 +49,7 @@ public: | |||
49 | 49 | ||
50 | Q_SIGNALS: | 50 | Q_SIGNALS: |
51 | void ready(bool isReady); | 51 | void ready(bool isReady); |
52 | void revisionChanged(unsigned long long revision); | 52 | void revisionChanged(qint64 revision); |
53 | 53 | ||
54 | public Q_SLOTS: | 54 | public Q_SLOTS: |
55 | virtual void open() = 0; | 55 | virtual void open() = 0; |
diff --git a/common/resultset.h b/common/resultset.h index 1a19100..a888177 100644 --- a/common/resultset.h +++ b/common/resultset.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <QVector> | 21 | #include <QVector> |
22 | #include <functional> | 22 | #include <functional> |
23 | #include "domain/applicationdomaintype.h" | 23 | #include "domain/applicationdomaintype.h" |
24 | #include "metadata_generated.h" | ||
24 | 25 | ||
25 | /* | 26 | /* |
26 | * An iterator to a result set. | 27 | * An iterator to a result set. |
@@ -30,8 +31,13 @@ | |||
30 | class ResultSet { | 31 | class ResultSet { |
31 | public: | 32 | public: |
32 | 33 | ||
34 | ResultSet() | ||
35 | : mIt(nullptr) | ||
36 | { | ||
37 | |||
38 | } | ||
33 | 39 | ||
34 | ResultSet(const std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)>)> &generator) | 40 | ResultSet(const std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)>)> &generator) |
35 | : mIt(nullptr), | 41 | : mIt(nullptr), |
36 | mValueGenerator(generator) | 42 | mValueGenerator(generator) |
37 | { | 43 | { |
@@ -67,7 +73,7 @@ class ResultSet { | |||
67 | return false; | 73 | return false; |
68 | } | 74 | } |
69 | 75 | ||
70 | bool next(std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &value)> callback) | 76 | bool next(std::function<bool(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &value, Akonadi2::Operation)> callback) |
71 | { | 77 | { |
72 | Q_ASSERT(mValueGenerator); | 78 | Q_ASSERT(mValueGenerator); |
73 | return mValueGenerator(callback); | 79 | return mValueGenerator(callback); |
@@ -107,6 +113,6 @@ class ResultSet { | |||
107 | QVector<QByteArray>::ConstIterator mIt; | 113 | QVector<QByteArray>::ConstIterator mIt; |
108 | QByteArray mCurrentValue; | 114 | QByteArray mCurrentValue; |
109 | std::function<QByteArray()> mGenerator; | 115 | std::function<QByteArray()> mGenerator; |
110 | std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &)>)> mValueGenerator; | 116 | std::function<bool(std::function<void(const Akonadi2::ApplicationDomain::ApplicationDomainType::Ptr &, Akonadi2::Operation)>)> mValueGenerator; |
111 | }; | 117 | }; |
112 | 118 | ||
diff --git a/common/storage_common.cpp b/common/storage_common.cpp index dc02aec..512a13f 100644 --- a/common/storage_common.cpp +++ b/common/storage_common.cpp | |||
@@ -66,10 +66,7 @@ qint64 Storage::maxRevision(const Akonadi2::Storage::Transaction &transaction) | |||
66 | r = revision.toLongLong(); | 66 | r = revision.toLongLong(); |
67 | return false; | 67 | return false; |
68 | }, [](const Error &error){ | 68 | }, [](const Error &error){ |
69 | if (error.code != ErrorCodes::NotFound) { | 69 | std::cout << "Coultn'd find uid for revision "; |
70 | //FIXME | ||
71 | // defaultErrorHandler()(error); | ||
72 | } | ||
73 | }); | 70 | }); |
74 | return r; | 71 | return r; |
75 | } | 72 | } |
@@ -80,11 +77,8 @@ QByteArray Storage::getUidFromRevision(const Akonadi2::Storage::Transaction &tra | |||
80 | transaction.openDatabase("revisions").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { | 77 | transaction.openDatabase("revisions").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { |
81 | uid = value; | 78 | uid = value; |
82 | return false; | 79 | return false; |
83 | }, [](const Error &error){ | 80 | }, [revision](const Error &error){ |
84 | if (error.code != ErrorCodes::NotFound) { | 81 | std::cout << "Coultn'd find uid for revision " << revision; |
85 | //FIXME | ||
86 | // defaultErrorHandler()(error); | ||
87 | } | ||
88 | }); | 82 | }); |
89 | return uid; | 83 | return uid; |
90 | } | 84 | } |
@@ -95,11 +89,8 @@ QByteArray Storage::getTypeFromRevision(const Akonadi2::Storage::Transaction &tr | |||
95 | transaction.openDatabase("revisionType").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { | 89 | transaction.openDatabase("revisionType").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { |
96 | type = value; | 90 | type = value; |
97 | return false; | 91 | return false; |
98 | }, [](const Error &error){ | 92 | }, [revision](const Error &error){ |
99 | if (error.code != ErrorCodes::NotFound) { | 93 | std::cout << "Coultn'd find type for revision " << revision; |
100 | //FIXME | ||
101 | // defaultErrorHandler()(error); | ||
102 | } | ||
103 | }); | 94 | }); |
104 | return type; | 95 | return type; |
105 | } | 96 | } |
diff --git a/examples/client/main.cpp b/examples/client/main.cpp index a0ca51b..ead9dd6 100644 --- a/examples/client/main.cpp +++ b/examples/client/main.cpp | |||
@@ -128,6 +128,7 @@ int main(int argc, char *argv[]) | |||
128 | cliOptions.addPositionalArgument(QObject::tr("[resource]"), | 128 | cliOptions.addPositionalArgument(QObject::tr("[resource]"), |
129 | QObject::tr("A resource to connect to")); | 129 | QObject::tr("A resource to connect to")); |
130 | cliOptions.addOption(QCommandLineOption("clear")); | 130 | cliOptions.addOption(QCommandLineOption("clear")); |
131 | cliOptions.addOption(QCommandLineOption("debuglevel")); | ||
131 | cliOptions.addHelpOption(); | 132 | cliOptions.addHelpOption(); |
132 | cliOptions.process(app); | 133 | cliOptions.process(app); |
133 | QStringList resources = cliOptions.positionalArguments(); | 134 | QStringList resources = cliOptions.positionalArguments(); |
@@ -143,6 +144,9 @@ int main(int argc, char *argv[]) | |||
143 | } | 144 | } |
144 | return 0; | 145 | return 0; |
145 | } | 146 | } |
147 | if (cliOptions.isSet("debuglevel")) { | ||
148 | Akonadi2::Log::setDebugOutputLevel(static_cast<Akonadi2::Log::DebugLevel>(cliOptions.value("debuglevel").toInt())); | ||
149 | } | ||
146 | 150 | ||
147 | //Ensure resource is ready | 151 | //Ensure resource is ready |
148 | for (const auto &resource : resources) { | 152 | for (const auto &resource : resources) { |
diff --git a/tests/dummyresourcetest.cpp b/tests/dummyresourcetest.cpp index a28e071..caf808a 100644 --- a/tests/dummyresourcetest.cpp +++ b/tests/dummyresourcetest.cpp | |||
@@ -2,10 +2,6 @@ | |||
2 | 2 | ||
3 | #include <QString> | 3 | #include <QString> |
4 | 4 | ||
5 | #include "event_generated.h" | ||
6 | #include "entity_generated.h" | ||
7 | #include "metadata_generated.h" | ||
8 | #include "createentity_generated.h" | ||
9 | #include "dummyresource/resourcefactory.h" | 5 | #include "dummyresource/resourcefactory.h" |
10 | #include "clientapi.h" | 6 | #include "clientapi.h" |
11 | #include "synclistresult.h" | 7 | #include "synclistresult.h" |
diff --git a/tests/genericfacadetest.cpp b/tests/genericfacadetest.cpp index 45ca54d..4c58b91 100644 --- a/tests/genericfacadetest.cpp +++ b/tests/genericfacadetest.cpp | |||
@@ -68,6 +68,11 @@ class GenericFacadeTest : public QObject | |||
68 | Q_OBJECT | 68 | Q_OBJECT |
69 | private Q_SLOTS: | 69 | private Q_SLOTS: |
70 | 70 | ||
71 | void init() | ||
72 | { | ||
73 | Akonadi2::Log::setDebugOutputLevel(Akonadi2::Log::Trace); | ||
74 | } | ||
75 | |||
71 | void testLoad() | 76 | void testLoad() |
72 | { | 77 | { |
73 | Akonadi2::Query query; | 78 | Akonadi2::Query query; |
diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp index 8d5ee00..8e841cb 100644 --- a/tests/storagetest.cpp +++ b/tests/storagetest.cpp | |||
@@ -381,6 +381,15 @@ private Q_SLOTS: | |||
381 | 381 | ||
382 | QCOMPARE(result, QByteArray("value2")); | 382 | QCOMPARE(result, QByteArray("value2")); |
383 | } | 383 | } |
384 | |||
385 | void testRecordRevision() | ||
386 | { | ||
387 | Akonadi2::Storage store(testDataPath, dbName, Akonadi2::Storage::ReadWrite); | ||
388 | auto transaction = store.createTransaction(Akonadi2::Storage::ReadWrite); | ||
389 | Akonadi2::Storage::recordRevision(transaction, 1, "uid", "type"); | ||
390 | QCOMPARE(Akonadi2::Storage::getTypeFromRevision(transaction, 1), QByteArray("type")); | ||
391 | QCOMPARE(Akonadi2::Storage::getUidFromRevision(transaction, 1), QByteArray("uid")); | ||
392 | } | ||
384 | }; | 393 | }; |
385 | 394 | ||
386 | QTEST_MAIN(StorageTest) | 395 | QTEST_MAIN(StorageTest) |