summaryrefslogtreecommitdiffstats
path: root/dummyresource
diff options
context:
space:
mode:
Diffstat (limited to 'dummyresource')
-rw-r--r--dummyresource/domainadaptor.cpp26
-rw-r--r--dummyresource/facade.cpp145
-rw-r--r--dummyresource/facade.h1
-rw-r--r--dummyresource/resourcefactory.cpp26
4 files changed, 138 insertions, 60 deletions
diff --git a/dummyresource/domainadaptor.cpp b/dummyresource/domainadaptor.cpp
index ec5e2be..d902052 100644
--- a/dummyresource/domainadaptor.cpp
+++ b/dummyresource/domainadaptor.cpp
@@ -40,9 +40,10 @@ public:
40 { 40 {
41 if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) { 41 if (mResourceBuffer && mResourceMapper->mReadAccessors.contains(key)) {
42 return mResourceMapper->getProperty(key, mResourceBuffer); 42 return mResourceMapper->getProperty(key, mResourceBuffer);
43 } else if (mLocalBuffer) { 43 } else if (mLocalBuffer && mLocalMapper->mReadAccessors.contains(key)) {
44 return mLocalMapper->getProperty(key, mLocalBuffer); 44 return mLocalMapper->getProperty(key, mLocalBuffer);
45 } 45 }
46 qWarning() << "no mapping available for key " << key;
46 return QVariant(); 47 return QVariant();
47 } 48 }
48 49
@@ -67,14 +68,23 @@ DummyEventAdaptorFactory::DummyEventAdaptorFactory()
67{ 68{
68 mResourceMapper = QSharedPointer<PropertyMapper<DummyEvent> >::create(); 69 mResourceMapper = QSharedPointer<PropertyMapper<DummyEvent> >::create();
69 mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { 70 mResourceMapper->mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant {
70 return QString::fromStdString(buffer->summary()->c_str()); 71 if (buffer->summary()) {
72 return QString::fromStdString(buffer->summary()->c_str());
73 }
74 return QVariant();
71 }); 75 });
72 mLocalMapper = QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> >::create(); 76 mLocalMapper = QSharedPointer<PropertyMapper<Akonadi2::Domain::Buffer::Event> >::create();
73 mLocalMapper->mReadAccessors.insert("summary", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant { 77 mLocalMapper->mReadAccessors.insert("summary", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant {
74 return QString::fromStdString(buffer->summary()->c_str()); 78 if (buffer->summary()) {
79 return QString::fromStdString(buffer->summary()->c_str());
80 }
81 return QVariant();
75 }); 82 });
76 mLocalMapper->mReadAccessors.insert("uid", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant { 83 mLocalMapper->mReadAccessors.insert("uid", [](Akonadi2::Domain::Buffer::Event const *buffer) -> QVariant {
77 return QString::fromStdString(buffer->uid()->c_str()); 84 if (buffer->uid()) {
85 return QString::fromStdString(buffer->uid()->c_str());
86 }
87 return QVariant();
78 }); 88 });
79 89
80} 90}
@@ -94,7 +104,7 @@ QSharedPointer<Akonadi2::Domain::BufferAdaptor> DummyEventAdaptorFactory::create
94 if (auto metadataData = entity.metadata()) { 104 if (auto metadataData = entity.metadata()) {
95 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); 105 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size());
96 if (Akonadi2::VerifyMetadataBuffer(verifyer)) { 106 if (Akonadi2::VerifyMetadataBuffer(verifyer)) {
97 metadataBuffer = Akonadi2::GetMetadata(metadataData); 107 metadataBuffer = Akonadi2::GetMetadata(metadataData->Data());
98 } 108 }
99 } 109 }
100 110
@@ -102,15 +112,15 @@ QSharedPointer<Akonadi2::Domain::BufferAdaptor> DummyEventAdaptorFactory::create
102 if (auto localData = entity.local()) { 112 if (auto localData = entity.local()) {
103 flatbuffers::Verifier verifyer(localData->Data(), localData->size()); 113 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
104 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) { 114 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
105 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData); 115 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData->Data());
106 } 116 }
107 } 117 }
108 118
109 auto adaptor = QSharedPointer<DummyEventAdaptor>::create(); 119 auto adaptor = QSharedPointer<DummyEventAdaptor>::create();
110 adaptor->mLocalBuffer = localBuffer; 120 adaptor->mLocalBuffer = localBuffer;
121 adaptor->mLocalMapper = mLocalMapper;
111 adaptor->mResourceBuffer = resourceBuffer; 122 adaptor->mResourceBuffer = resourceBuffer;
112 adaptor->mResourceMapper = mResourceMapper; 123 adaptor->mResourceMapper = mResourceMapper;
113 adaptor->mLocalMapper = mLocalMapper;
114 return adaptor; 124 return adaptor;
115} 125}
116 126
@@ -135,6 +145,6 @@ void DummyEventAdaptorFactory::createBuffer(const Akonadi2::Domain::Event &event
135 Akonadi2::Domain::Buffer::FinishEventBuffer(localFbb, location); 145 Akonadi2::Domain::Buffer::FinishEventBuffer(localFbb, location);
136 } 146 }
137 147
138 Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, localFbb.GetBufferPointer(), localFbb.GetSize(), eventFbb.GetBufferPointer(), eventFbb.GetSize(), 0, 0); 148 Akonadi2::EntityBuffer::assembleEntityBuffer(fbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize());
139} 149}
140 150
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp
index cd930f6..1aaec68 100644
--- a/dummyresource/facade.cpp
+++ b/dummyresource/facade.cpp
@@ -31,6 +31,7 @@
31#include "createentity_generated.h" 31#include "createentity_generated.h"
32#include "domainadaptor.h" 32#include "domainadaptor.h"
33#include <common/entitybuffer.h> 33#include <common/entitybuffer.h>
34#include <common/index.h>
34 35
35using namespace DummyCalendar; 36using namespace DummyCalendar;
36using namespace flatbuffers; 37using namespace flatbuffers;
@@ -73,11 +74,11 @@ Async::Job<void> DummyResourceFacade::remove(const Akonadi2::Domain::Event &doma
73 return Async::null<void>(); 74 return Async::null<void>();
74} 75}
75 76
76static std::function<bool(const std::string &key, DummyEvent const *buffer)> prepareQuery(const Akonadi2::Query &query) 77static std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> prepareQuery(const Akonadi2::Query &query)
77{ 78{
78 //Compose some functions to make query matching fast. 79 //Compose some functions to make query matching fast.
79 //This way we can process the query once, and convert all values into something that can be compared quickly 80 //This way we can process the query once, and convert all values into something that can be compared quickly
80 std::function<bool(const std::string &key, DummyEvent const *buffer)> preparedQuery; 81 std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery;
81 if (!query.ids.isEmpty()) { 82 if (!query.ids.isEmpty()) {
82 //Match by id 83 //Match by id
83 //TODO: for id's a direct lookup would be way faster 84 //TODO: for id's a direct lookup would be way faster
@@ -88,15 +89,26 @@ static std::function<bool(const std::string &key, DummyEvent const *buffer)> pre
88 for (const auto &id : query.ids) { 89 for (const auto &id : query.ids) {
89 ids << id.toStdString(); 90 ids << id.toStdString();
90 } 91 }
91 preparedQuery = [ids](const std::string &key, DummyEvent const *buffer) { 92 preparedQuery = [ids](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
92 if (ids.contains(key)) { 93 if (ids.contains(key)) {
93 return true; 94 return true;
94 } 95 }
95 return false; 96 return false;
96 }; 97 };
98 } else if (!query.propertyFilter.isEmpty()) {
99 if (query.propertyFilter.contains("uid")) {
100 const QByteArray uid = query.propertyFilter.value("uid").toByteArray();
101 preparedQuery = [uid](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
102 if (local && local->uid() && (QByteArray::fromRawData(local->uid()->c_str(), local->uid()->size()) == uid)) {
103 qDebug() << "uid match";
104 return true;
105 }
106 return false;
107 };
108 }
97 } else { 109 } else {
98 //Match everything 110 //Match everything
99 preparedQuery = [](const std::string &key, DummyEvent const *buffer) { 111 preparedQuery = [](const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local) {
100 return true; 112 return true;
101 }; 113 };
102 } 114 }
@@ -121,65 +133,96 @@ Async::Job<void> DummyResourceFacade::synchronizeResource(bool sync)
121 return Async::null<void>(); 133 return Async::null<void>();
122} 134}
123 135
124Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback) 136void DummyResourceFacade::readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)> preparedQuery)
125{ 137{
126 qDebug() << "load called"; 138 storage->scan(key.data(), key.size(), [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
127 139
128 return synchronizeResource(query.syncOnDemand).then<void>([=](Async::Future<void> &future) { 140 //Skip internals
129 qDebug() << "sync complete"; 141 if (QByteArray::fromRawData(static_cast<char*>(keyValue), keySize).startsWith("__internal")) {
130 //Now that the sync is complete we can execute the query 142 return true;
131 const auto preparedQuery = prepareQuery(query); 143 }
132
133 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
134 144
135 qDebug() << "executing query"; 145 //Extract buffers
136 //We start a transaction explicitly that we'll leave open so the values can be read. 146 Akonadi2::EntityBuffer buffer(dataValue, dataSize);
137 //The transaction will be closed automatically once the storage object is destroyed.
138 storage->startTransaction(Akonadi2::Storage::ReadOnly);
139 //Because we have no indexes yet, we always do a full scan
140 storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool {
141 147
142 //Skip internals 148 DummyEvent const *resourceBuffer = 0;
143 if (QByteArray::fromRawData(static_cast<char*>(keyValue), keySize).startsWith("__internal")) { 149 if (auto resourceData = buffer.entity().resource()) {
144 return true; 150 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
151 if (VerifyDummyEventBuffer(verifyer)) {
152 resourceBuffer = GetDummyEvent(resourceData->Data());
145 } 153 }
154 }
146 155
147 //Extract buffers 156 Akonadi2::Domain::Buffer::Event const *localBuffer = 0;
148 Akonadi2::EntityBuffer buffer(dataValue, dataSize); 157 if (auto localData = buffer.entity().local()) {
149 158 flatbuffers::Verifier verifyer(localData->Data(), localData->size());
150 DummyEvent const *resourceBuffer = 0; 159 if (Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
151 if (auto resourceData = buffer.entity().resource()) { 160 localBuffer = Akonadi2::Domain::Buffer::GetEvent(localData->Data());
152 flatbuffers::Verifier verifyer(resourceData->Data(), resourceData->size());
153 if (VerifyDummyEventBuffer(verifyer)) {
154 resourceBuffer = GetDummyEvent(resourceData);
155 }
156 } 161 }
162 }
157 163
158 Akonadi2::Metadata const *metadataBuffer = 0; 164 Akonadi2::Metadata const *metadataBuffer = 0;
159 if (auto metadataData = buffer.entity().metadata()) { 165 if (auto metadataData = buffer.entity().metadata()) {
160 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size()); 166 flatbuffers::Verifier verifyer(metadataData->Data(), metadataData->size());
161 if (Akonadi2::VerifyMetadataBuffer(verifyer)) { 167 if (Akonadi2::VerifyMetadataBuffer(verifyer)) {
162 metadataBuffer = Akonadi2::GetMetadata(metadataData); 168 metadataBuffer = Akonadi2::GetMetadata(metadataData->Data());
163 }
164 } 169 }
170 }
165 171
166 if (!resourceBuffer || !metadataBuffer) { 172 if (!resourceBuffer || !metadataBuffer) {
167 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); 173 qWarning() << "invalid buffer " << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize));
168 return true; 174 return true;
169 } 175 }
176
177 //We probably only want to create all buffers after the scan
178 //TODO use adapter for query and scan?
179 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer, localBuffer)) {
180 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
181 //This only works for a 1:1 mapping of resource to domain types.
182 //Not i.e. for tags that are stored as flags in each entity of an imap store.
183 auto adaptor = mFactory->createAdaptor(buffer.entity());
184 //TODO only copy requested properties
185 auto memoryAdaptor = QSharedPointer<Akonadi2::Domain::MemoryBufferAdaptor>::create(*adaptor);
186 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor);
187 resultCallback(event);
188 }
189 return true;
190 },
191 [](const Akonadi2::Storage::Error &error) {
192 qDebug() << QString::fromStdString(error.message);
193 });
194}
195
196Async::Job<void> DummyResourceFacade::load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback)
197{
198 return synchronizeResource(query.syncOnDemand).then<void>([=](Async::Future<void> &future) {
199 //Now that the sync is complete we can execute the query
200 const auto preparedQuery = prepareQuery(query);
201
202 auto storage = QSharedPointer<Akonadi2::Storage>::create(Akonadi2::Store::storageLocation(), "org.kde.dummy");
170 203
171 //We probably only want to create all buffers after the scan 204 QVector<QByteArray> keys;
172 //TODO use adapter for query and scan? 205 if (query.propertyFilter.contains("uid")) {
173 if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer)) { 206 static Index uidIndex(Akonadi2::Store::storageLocation(), "org.kde.dummy.index.uid", Akonadi2::Storage::ReadOnly);
174 qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; 207 uidIndex.lookup(query.propertyFilter.value("uid").toByteArray(), [&](const QByteArray &value) {
175 auto adaptor = mFactory->createAdaptor(buffer.entity()); 208 keys << value;
176 //TODO only copy requested properties 209 },
177 auto memoryAdaptor = QSharedPointer<Akonadi2::Domain::MemoryBufferAdaptor>::create(*adaptor); 210 [](const Index::Error &error) {
178 auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, memoryAdaptor); 211 qWarning() << "Error in index: " << QString::fromStdString(error.message);
179 resultCallback(event); 212 });
213 }
214
215 //We start a transaction explicitly that we'll leave open so the values can be read.
216 //The transaction will be closed automatically once the storage object is destroyed.
217 storage->startTransaction(Akonadi2::Storage::ReadOnly);
218 if (keys.isEmpty()) {
219 qDebug() << "full scan";
220 readValue(storage, QByteArray(), resultCallback, preparedQuery);
221 } else {
222 for (const auto &key : keys) {
223 readValue(storage, key, resultCallback, preparedQuery);
180 } 224 }
181 return true; 225 }
182 });
183 future.setFinished(); 226 future.setFinished();
184 }); 227 });
185} 228}
diff --git a/dummyresource/facade.h b/dummyresource/facade.h
index da0b1d6..c9c8047 100644
--- a/dummyresource/facade.h
+++ b/dummyresource/facade.h
@@ -43,6 +43,7 @@ public:
43 virtual Async::Job<void> load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback); 43 virtual Async::Job<void> load(const Akonadi2::Query &query, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback);
44 44
45private: 45private:
46 void readValue(QSharedPointer<Akonadi2::Storage> storage, const QByteArray &key, const std::function<void(const Akonadi2::Domain::Event::Ptr &)> &resultCallback, std::function<bool(const std::string &key, DummyCalendar::DummyEvent const *buffer, Akonadi2::Domain::Buffer::Event const *local)>);
46 Async::Job<void> synchronizeResource(bool sync); 47 Async::Job<void> synchronizeResource(bool sync);
47 QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess; 48 QSharedPointer<Akonadi2::ResourceAccess> mResourceAccess;
48 QSharedPointer<DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent> > mFactory; 49 QSharedPointer<DomainTypeAdaptorFactory<Akonadi2::Domain::Event, Akonadi2::Domain::Buffer::Event, DummyCalendar::DummyEvent> > mFactory;
diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp
index 60a9cf6..18083cb 100644
--- a/dummyresource/resourcefactory.cpp
+++ b/dummyresource/resourcefactory.cpp
@@ -28,6 +28,7 @@
28#include "domainadaptor.h" 28#include "domainadaptor.h"
29#include "commands.h" 29#include "commands.h"
30#include "clientapi.h" 30#include "clientapi.h"
31#include "index.h"
31#include <QUuid> 32#include <QUuid>
32#include <assert.h> 33#include <assert.h>
33 34
@@ -261,8 +262,31 @@ void DummyResource::configurePipeline(Akonadi2::Pipeline *pipeline)
261 auto adaptor = eventFactory->createAdaptor(entity); 262 auto adaptor = eventFactory->createAdaptor(entity);
262 qDebug() << "Summary preprocessor: " << adaptor->getProperty("summary").toString(); 263 qDebug() << "Summary preprocessor: " << adaptor->getProperty("summary").toString();
263 }); 264 });
265
266 auto uidIndexer = new SimpleProcessor("uidIndexer", [eventFactory](const Akonadi2::PipelineState &state, const Akonadi2::Entity &entity) {
267 static Index uidIndex(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/akonadi2/storage", "org.kde.dummy.index.uid", Akonadi2::Storage::ReadWrite);
268
269 auto adaptor = eventFactory->createAdaptor(entity);
270 const auto uid = adaptor->getProperty("uid");
271 if (uid.isValid()) {
272 uidIndex.add(uid.toByteArray(), state.key());
273 }
274
275 //TODO would this be worthwhile for performance reasons?
276 // flatbuffers::Verifier verifyer(entity.local()->Data(), entity.local()->size());
277 // if (!Akonadi2::Domain::Buffer::VerifyEventBuffer(verifyer)) {
278 // qWarning() << "invalid local buffer";
279 // return;
280 // }
281 // auto localEvent = Akonadi2::Domain::Buffer::GetEvent(entity.local()->Data());
282 // if (localEvent && localEvent->uid()) {
283 // qDebug() << "got uid: " << QByteArray::fromRawData(reinterpret_cast<const char *>(localEvent->uid()->Data()), localEvent->uid()->size());
284 // uidIndex.add(QByteArray::fromRawData(reinterpret_cast<const char *>(localEvent->uid()->Data()), localEvent->uid()->size()), state.key());
285 // }
286 });
287
264 //event is the entitytype and not the domain type 288 //event is the entitytype and not the domain type
265 pipeline->setPreprocessors("event", Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer); 289 pipeline->setPreprocessors("event", Akonadi2::Pipeline::NewPipeline, QVector<Akonadi2::Preprocessor*>() << eventIndexer << uidIndexer);
266 mProcessor = new Processor(pipeline, QList<MessageQueue*>() << &mUserQueue << &mSynchronizerQueue); 290 mProcessor = new Processor(pipeline, QList<MessageQueue*>() << &mUserQueue << &mSynchronizerQueue);
267 QObject::connect(mProcessor, &Processor::error, [this](int errorCode, const QString &msg) { onProcessorError(errorCode, msg); }); 291 QObject::connect(mProcessor, &Processor::error, [this](int errorCode, const QString &msg) { onProcessorError(errorCode, msg); });
268} 292}