diff options
-rw-r--r-- | common/CMakeLists.txt | 19 | ||||
-rw-r--r-- | common/clientapi.h | 38 | ||||
-rw-r--r-- | common/domain/event.fbs | 10 | ||||
-rw-r--r-- | common/entitybuffer.fbs | 9 | ||||
-rw-r--r-- | common/metadata.fbs | 7 | ||||
-rw-r--r-- | common/pipeline.cpp | 40 | ||||
-rw-r--r-- | common/pipeline.h | 8 | ||||
-rw-r--r-- | common/storage.h | 2 | ||||
-rw-r--r-- | common/storage_lmdb.cpp | 25 | ||||
-rw-r--r-- | common/test/clientapitest.cpp | 2 | ||||
-rw-r--r-- | dummyresource/facade.cpp | 98 | ||||
-rw-r--r-- | dummyresource/resourcefactory.cpp | 4 |
12 files changed, 198 insertions, 64 deletions
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 001dab5..ec13e07 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt | |||
@@ -1,13 +1,16 @@ | |||
1 | project(akonadi2common) | 1 | project(akonadi2common) |
2 | generate_flatbuffers( | 2 | generate_flatbuffers( |
3 | commands/commandcompletion | 3 | commands/commandcompletion |
4 | commands/createentity | 4 | commands/createentity |
5 | commands/deleteentity | 5 | commands/deleteentity |
6 | commands/fetchentity | 6 | commands/fetchentity |
7 | commands/handshake | 7 | commands/handshake |
8 | commands/modifyentity | 8 | commands/modifyentity |
9 | commands/revisionupdate | 9 | commands/revisionupdate |
10 | ) | 10 | domain/event |
11 | entitybuffer | ||
12 | metadata | ||
13 | ) | ||
11 | 14 | ||
12 | if (STORAGE_unqlite) | 15 | if (STORAGE_unqlite) |
13 | add_definitions(-DUNQLITE_ENABLE_THREADS -fpermissive) | 16 | add_definitions(-DUNQLITE_ENABLE_THREADS -fpermissive) |
diff --git a/common/clientapi.h b/common/clientapi.h index d2757e7..ba0cb19 100644 --- a/common/clientapi.h +++ b/common/clientapi.h | |||
@@ -173,18 +173,36 @@ namespace Akonadi2 { | |||
173 | */ | 173 | */ |
174 | namespace Domain { | 174 | namespace Domain { |
175 | 175 | ||
176 | /** | ||
177 | * This class has to be implemented by resources and can be used as generic interface to access the buffer properties | ||
178 | */ | ||
179 | class BufferAdaptor { | ||
180 | public: | ||
181 | virtual QVariant getProperty(const QString &key) { return QVariant(); } | ||
182 | virtual void setProperty(const QString &key, const QVariant &value) {} | ||
183 | }; | ||
184 | |||
185 | /** | ||
186 | * The domain type interface has two purposes: | ||
187 | * * provide a unified interface to read buffers (for zero-copy reading) | ||
188 | * * record changes to generate changesets for modifications | ||
189 | */ | ||
176 | class AkonadiDomainType { | 190 | class AkonadiDomainType { |
177 | public: | 191 | public: |
178 | AkonadiDomainType(const QString &resourceName, const QString &identifier, qint64 revision) | 192 | AkonadiDomainType(const QString &resourceName, const QString &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor) |
179 | : mResourceName(resourceName), | 193 | : mAdaptor(adaptor), |
194 | mResourceName(resourceName), | ||
180 | mIdentifier(identifier), | 195 | mIdentifier(identifier), |
181 | mRevision(revision) | 196 | mRevision(revision) |
182 | { | 197 | { |
183 | } | 198 | } |
184 | 199 | ||
185 | virtual QVariant getProperty(const QString &key){ return QVariant(); } | 200 | virtual QVariant getProperty(const QString &key){ return mAdaptor->getProperty(key); } |
201 | virtual void setProperty(const QString &key, const QVariant &value){ mChangeSet.insert(key, value); } | ||
186 | 202 | ||
187 | private: | 203 | private: |
204 | QSharedPointer<BufferAdaptor> mAdaptor; | ||
205 | QHash<QString, QVariant> mChangeSet; | ||
188 | /* | 206 | /* |
189 | * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location. | 207 | * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location. |
190 | */ | 208 | */ |
@@ -193,21 +211,19 @@ private: | |||
193 | qint64 mRevision; | 211 | qint64 mRevision; |
194 | }; | 212 | }; |
195 | 213 | ||
196 | class Event : public AkonadiDomainType { | 214 | struct Event : public AkonadiDomainType { |
197 | public: | ||
198 | typedef QSharedPointer<Event> Ptr; | 215 | typedef QSharedPointer<Event> Ptr; |
199 | Event(const QString &resource, const QString &identifier, qint64 revision):AkonadiDomainType(resource, identifier, revision){}; | 216 | using AkonadiDomainType::AkonadiDomainType; |
200 | |||
201 | }; | 217 | }; |
202 | 218 | ||
203 | class Todo : public AkonadiDomainType { | 219 | struct Todo : public AkonadiDomainType { |
204 | public: | ||
205 | typedef QSharedPointer<Todo> Ptr; | 220 | typedef QSharedPointer<Todo> Ptr; |
221 | using AkonadiDomainType::AkonadiDomainType; | ||
206 | }; | 222 | }; |
207 | 223 | ||
208 | class Calendar : public AkonadiDomainType { | 224 | struct Calendar : public AkonadiDomainType { |
209 | public: | ||
210 | typedef QSharedPointer<Calendar> Ptr; | 225 | typedef QSharedPointer<Calendar> Ptr; |
226 | using AkonadiDomainType::AkonadiDomainType; | ||
211 | }; | 227 | }; |
212 | 228 | ||
213 | class Mail : public AkonadiDomainType { | 229 | class Mail : public AkonadiDomainType { |
diff --git a/common/domain/event.fbs b/common/domain/event.fbs new file mode 100644 index 0000000..6865cc5 --- /dev/null +++ b/common/domain/event.fbs | |||
@@ -0,0 +1,10 @@ | |||
1 | namespace Akonadi2.Domain.Buffer; | ||
2 | |||
3 | table Event { | ||
4 | summary:string; | ||
5 | description:string; | ||
6 | attachment:[ubyte]; | ||
7 | } | ||
8 | |||
9 | root_type Event; | ||
10 | file_identifier "AKFB"; | ||
diff --git a/common/entitybuffer.fbs b/common/entitybuffer.fbs new file mode 100644 index 0000000..28c9b2a --- /dev/null +++ b/common/entitybuffer.fbs | |||
@@ -0,0 +1,9 @@ | |||
1 | namespace Akonadi2; | ||
2 | |||
3 | table EntityBuffer { | ||
4 | metadata: [ubyte]; | ||
5 | resource: [ubyte]; | ||
6 | local: [ubyte]; | ||
7 | } | ||
8 | |||
9 | root_type EntityBuffer; | ||
diff --git a/common/metadata.fbs b/common/metadata.fbs new file mode 100644 index 0000000..71684b6 --- /dev/null +++ b/common/metadata.fbs | |||
@@ -0,0 +1,7 @@ | |||
1 | namespace Akonadi2; | ||
2 | |||
3 | table Metadata { | ||
4 | revision: ulong; | ||
5 | } | ||
6 | |||
7 | root_type Metadata; | ||
diff --git a/common/pipeline.cpp b/common/pipeline.cpp index 739909d..5ca8b95 100644 --- a/common/pipeline.cpp +++ b/common/pipeline.cpp | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <QByteArray> | 23 | #include <QByteArray> |
24 | #include <QStandardPaths> | 24 | #include <QStandardPaths> |
25 | #include <QVector> | 25 | #include <QVector> |
26 | #include <QDebug> | ||
27 | #include "entitybuffer_generated.h" | ||
28 | #include "metadata_generated.h" | ||
26 | 29 | ||
27 | namespace Akonadi2 | 30 | namespace Akonadi2 |
28 | { | 31 | { |
@@ -69,11 +72,40 @@ void Pipeline::null() | |||
69 | state.step(); | 72 | state.step(); |
70 | } | 73 | } |
71 | 74 | ||
72 | void Pipeline::newEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entity) | 75 | void Pipeline::newEntity(const QByteArray &key, void *resourceBufferData, size_t size) |
73 | { | 76 | { |
74 | const qint64 newRevision = storage().maxRevision() + 1; | 77 | const qint64 newRevision = storage().maxRevision() + 1; |
75 | //FIXME this should go into a preprocessor | 78 | |
76 | storage().write(key, key.size(), reinterpret_cast<char*>(entity.GetBufferPointer()), entity.GetSize()); | 79 | flatbuffers::FlatBufferBuilder fbb; |
80 | auto builder = Akonadi2::EntityBufferBuilder(fbb); | ||
81 | |||
82 | //Add metadata buffer | ||
83 | { | ||
84 | flatbuffers::FlatBufferBuilder metadataFbb; | ||
85 | auto metadataBuilder = Akonadi2::MetadataBuilder(metadataFbb); | ||
86 | metadataBuilder.add_revision(newRevision); | ||
87 | auto metadataBuffer = metadataBuilder.Finish(); | ||
88 | Akonadi2::FinishMetadataBuffer(fbb, metadataBuffer); | ||
89 | //TODO use memcpy | ||
90 | auto metadata = fbb.CreateVector<uint8_t>(metadataFbb.GetBufferPointer(), metadataFbb.GetSize()); | ||
91 | builder.add_metadata(metadata); | ||
92 | } | ||
93 | |||
94 | //Add resource buffer | ||
95 | { | ||
96 | //TODO use memcpy | ||
97 | auto resource = fbb.CreateVector<uint8_t>(static_cast<uint8_t*>(resourceBufferData), size); | ||
98 | builder.add_resource(resource); | ||
99 | } | ||
100 | |||
101 | //We don't have a local buffer yet | ||
102 | // builder.add_local(); | ||
103 | |||
104 | auto buffer = builder.Finish(); | ||
105 | Akonadi2::FinishEntityBufferBuffer(fbb, buffer); | ||
106 | |||
107 | qDebug() << "writing new entity" << key; | ||
108 | storage().write(key.data(), key.size(), fbb.GetBufferPointer(), fbb.GetSize()); | ||
77 | storage().setMaxRevision(newRevision); | 109 | storage().setMaxRevision(newRevision); |
78 | 110 | ||
79 | PipelineState state(this, NewPipeline, key, d->newPipeline); | 111 | PipelineState state(this, NewPipeline, key, d->newPipeline); |
@@ -81,7 +113,7 @@ void Pipeline::newEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder & | |||
81 | state.step(); | 113 | state.step(); |
82 | } | 114 | } |
83 | 115 | ||
84 | void Pipeline::modifiedEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entityDelta) | 116 | void Pipeline::modifiedEntity(const QByteArray &key, void *data, size_t size) |
85 | { | 117 | { |
86 | PipelineState state(this, ModifiedPipeline, key, d->modifiedPipeline); | 118 | PipelineState state(this, ModifiedPipeline, key, d->modifiedPipeline); |
87 | d->activePipelines << state; | 119 | d->activePipelines << state; |
diff --git a/common/pipeline.h b/common/pipeline.h index d7048ff..159cc1c 100644 --- a/common/pipeline.h +++ b/common/pipeline.h | |||
@@ -46,10 +46,11 @@ public: | |||
46 | 46 | ||
47 | Storage &storage() const; | 47 | Storage &storage() const; |
48 | 48 | ||
49 | // domain objects needed here | ||
50 | void null(); | 49 | void null(); |
51 | void newEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entity); | 50 | //FIXME We should probably directly provide a DomainTypeAdapter here. The data has already been written and we only need to read it for processing. And we need to read all buffers. |
52 | void modifiedEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entityDelta); | 51 | void newEntity(const QByteArray &key, void *resourceBufferData, size_t size); |
52 | //TODO Send local buffer data as well? | ||
53 | void modifiedEntity(const QByteArray &key, void *data, size_t size); | ||
53 | void deletedEntity(const QByteArray &key); | 54 | void deletedEntity(const QByteArray &key); |
54 | 55 | ||
55 | Q_SIGNALS: | 56 | Q_SIGNALS: |
@@ -72,7 +73,6 @@ private: | |||
72 | class AKONADI2COMMON_EXPORT PipelineState | 73 | class AKONADI2COMMON_EXPORT PipelineState |
73 | { | 74 | { |
74 | public: | 75 | public: |
75 | // domain objects? | ||
76 | PipelineState(); | 76 | PipelineState(); |
77 | PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters); | 77 | PipelineState(Pipeline *pipeline, Pipeline::Type type, const QByteArray &key, const QVector<Preprocessor *> &filters); |
78 | PipelineState(const PipelineState &other); | 78 | PipelineState(const PipelineState &other); |
diff --git a/common/storage.h b/common/storage.h index 6cfa3d6..6ae7838 100644 --- a/common/storage.h +++ b/common/storage.h | |||
@@ -52,7 +52,7 @@ public: | |||
52 | //TODO: row removal | 52 | //TODO: row removal |
53 | //TODO: cursor based read | 53 | //TODO: cursor based read |
54 | //TODO: query? | 54 | //TODO: query? |
55 | bool write(const char *key, size_t keySize, const char *value, size_t valueSize); | 55 | bool write(void const *key, size_t keySize, void const *value, size_t valueSize); |
56 | bool write(const std::string &sKey, const std::string &sValue); | 56 | bool write(const std::string &sKey, const std::string &sValue); |
57 | void read(const std::string &sKey, | 57 | void read(const std::string &sKey, |
58 | const std::function<bool(const std::string &value)> &resultHandler); | 58 | const std::function<bool(const std::string &value)> &resultHandler); |
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp index eeb0045..42e3d33 100644 --- a/common/storage_lmdb.cpp +++ b/common/storage_lmdb.cpp | |||
@@ -194,17 +194,17 @@ void Storage::abortTransaction() | |||
194 | d->transaction = 0; | 194 | d->transaction = 0; |
195 | } | 195 | } |
196 | 196 | ||
197 | bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize) | 197 | bool Storage::write(void const *keyPtr, size_t keySize, void const *valuePtr, size_t valueSize) |
198 | { | ||
199 | return write(std::string(key, keySize), std::string(value, valueSize)); | ||
200 | } | ||
201 | |||
202 | bool Storage::write(const std::string &sKey, const std::string &sValue) | ||
203 | { | 198 | { |
204 | if (!d->env) { | 199 | if (!d->env) { |
205 | return false; | 200 | return false; |
206 | } | 201 | } |
207 | 202 | ||
203 | if (d->mode == ReadOnly) { | ||
204 | std::cerr << "tried to write in read-only mode." << std::endl; | ||
205 | return false; | ||
206 | } | ||
207 | |||
208 | const bool implicitTransaction = !d->transaction || d->readTransaction; | 208 | const bool implicitTransaction = !d->transaction || d->readTransaction; |
209 | if (implicitTransaction) { | 209 | if (implicitTransaction) { |
210 | // TODO: if this fails, still try the write below? | 210 | // TODO: if this fails, still try the write below? |
@@ -215,10 +215,10 @@ bool Storage::write(const std::string &sKey, const std::string &sValue) | |||
215 | 215 | ||
216 | int rc; | 216 | int rc; |
217 | MDB_val key, data; | 217 | MDB_val key, data; |
218 | key.mv_size = sKey.size(); | 218 | key.mv_size = keySize; |
219 | key.mv_data = (void*)sKey.data(); | 219 | key.mv_data = const_cast<void*>(keyPtr); |
220 | data.mv_size = sValue.size(); | 220 | data.mv_size = valueSize; |
221 | data.mv_data = (void*)sValue.data(); | 221 | data.mv_data = const_cast<void*>(valuePtr); |
222 | rc = mdb_put(d->transaction, d->dbi, &key, &data, 0); | 222 | rc = mdb_put(d->transaction, d->dbi, &key, &data, 0); |
223 | 223 | ||
224 | if (rc) { | 224 | if (rc) { |
@@ -236,6 +236,11 @@ bool Storage::write(const std::string &sKey, const std::string &sValue) | |||
236 | return !rc; | 236 | return !rc; |
237 | } | 237 | } |
238 | 238 | ||
239 | bool Storage::write(const std::string &sKey, const std::string &sValue) | ||
240 | { | ||
241 | return write(const_cast<char*>(sKey.data()), sKey.size(), const_cast<char*>(sValue.data()), sValue.size()); | ||
242 | } | ||
243 | |||
239 | void Storage::read(const std::string &sKey, | 244 | void Storage::read(const std::string &sKey, |
240 | const std::function<bool(const std::string &value)> &resultHandler, | 245 | const std::function<bool(const std::string &value)> &resultHandler, |
241 | const std::function<void(const Storage::Error &error)> &errorHandler) | 246 | const std::function<void(const Storage::Error &error)> &errorHandler) |
diff --git a/common/test/clientapitest.cpp b/common/test/clientapitest.cpp index dd634f1..2ba0dcf 100644 --- a/common/test/clientapitest.cpp +++ b/common/test/clientapitest.cpp | |||
@@ -31,7 +31,7 @@ private Q_SLOTS: | |||
31 | void testLoad() | 31 | void testLoad() |
32 | { | 32 | { |
33 | DummyResourceFacade facade; | 33 | DummyResourceFacade facade; |
34 | facade.results << QSharedPointer<Akonadi2::Domain::Event>::create("resource", "id", 0); | 34 | facade.results << QSharedPointer<Akonadi2::Domain::Event>::create("resource", "id", 0, QSharedPointer<Akonadi2::Domain::BufferAdaptor>()); |
35 | 35 | ||
36 | Akonadi2::FacadeFactory::instance().registerFacade<Akonadi2::Domain::Event, DummyResourceFacade>("dummyresource", [facade](){ return new DummyResourceFacade(facade); }); | 36 | Akonadi2::FacadeFactory::instance().registerFacade<Akonadi2::Domain::Event, DummyResourceFacade>("dummyresource", [facade](){ return new DummyResourceFacade(facade); }); |
37 | 37 | ||
diff --git a/dummyresource/facade.cpp b/dummyresource/facade.cpp index c2871bb..458aba6 100644 --- a/dummyresource/facade.cpp +++ b/dummyresource/facade.cpp | |||
@@ -25,15 +25,51 @@ | |||
25 | #include "common/resourceaccess.h" | 25 | #include "common/resourceaccess.h" |
26 | #include "common/commands.h" | 26 | #include "common/commands.h" |
27 | #include "dummycalendar_generated.h" | 27 | #include "dummycalendar_generated.h" |
28 | #include "event_generated.h" | ||
29 | #include "entitybuffer_generated.h" | ||
30 | #include "metadata_generated.h" | ||
28 | 31 | ||
29 | using namespace DummyCalendar; | 32 | using namespace DummyCalendar; |
30 | using namespace flatbuffers; | 33 | using namespace flatbuffers; |
31 | 34 | ||
35 | /** | ||
36 | * The property mapper holds accessor functions for all properties. | ||
37 | * | ||
38 | * It is by default initialized with accessors that access the local-only buffer, | ||
39 | * and resource simply have to overwrite those accessors. | ||
40 | */ | ||
41 | template<typename BufferType> | ||
42 | class PropertyMapper | ||
43 | { | ||
44 | public: | ||
45 | void setProperty(const QString &key, const QVariant &value, BufferType *buffer) | ||
46 | { | ||
47 | if (mWriteAccessors.contains(key)) { | ||
48 | auto accessor = mWriteAccessors.value(key); | ||
49 | return accessor(value, buffer); | ||
50 | } | ||
51 | } | ||
52 | |||
53 | virtual QVariant getProperty(const QString &key, BufferType const *buffer) const | ||
54 | { | ||
55 | if (mReadAccessors.contains(key)) { | ||
56 | auto accessor = mReadAccessors.value(key); | ||
57 | return accessor(buffer); | ||
58 | } | ||
59 | return QVariant(); | ||
60 | } | ||
61 | QHash<QString, std::function<QVariant(BufferType const *)> > mReadAccessors; | ||
62 | QHash<QString, std::function<void(const QVariant &, BufferType*)> > mWriteAccessors; | ||
63 | }; | ||
64 | |||
32 | DummyResourceFacade::DummyResourceFacade() | 65 | DummyResourceFacade::DummyResourceFacade() |
33 | : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), | 66 | : Akonadi2::StoreFacade<Akonadi2::Domain::Event>(), |
34 | mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")) | 67 | mResourceAccess(new Akonadi2::ResourceAccess("org.kde.dummy")) |
35 | { | 68 | { |
36 | // connect(mResourceAccess.data(), &ResourceAccess::ready, this, onReadyChanged); | 69 | PropertyMapper<DummyEvent> mapper; |
70 | mapper.mReadAccessors.insert("summary", [](DummyEvent const *buffer) -> QVariant { | ||
71 | return QString::fromStdString(buffer->summary()->c_str()); | ||
72 | }); | ||
37 | } | 73 | } |
38 | 74 | ||
39 | DummyResourceFacade::~DummyResourceFacade() | 75 | DummyResourceFacade::~DummyResourceFacade() |
@@ -65,32 +101,43 @@ void DummyResourceFacade::remove(const Akonadi2::Domain::Event &domainObject) | |||
65 | //-how do we free/munmap the data if we don't know when no one references it any longer? => no munmap needed, but read transaction to keep pointer alive | 101 | //-how do we free/munmap the data if we don't know when no one references it any longer? => no munmap needed, but read transaction to keep pointer alive |
66 | //-we could bind the lifetime to the query | 102 | //-we could bind the lifetime to the query |
67 | //=> perhaps do heap allocate and use smart pointer? | 103 | //=> perhaps do heap allocate and use smart pointer? |
68 | class DummyEventAdaptor : public Akonadi2::Domain::Event | 104 | // |
105 | |||
106 | |||
107 | //This will become a generic implementation that simply takes the resource buffer and local buffer pointer | ||
108 | class DummyEventAdaptor : public Akonadi2::Domain::BufferAdaptor | ||
69 | { | 109 | { |
70 | public: | 110 | public: |
71 | DummyEventAdaptor(const QString &resource, const QString &identifier, qint64 revision) | 111 | DummyEventAdaptor() |
72 | :Akonadi2::Domain::Event(resource, identifier, revision) | 112 | : BufferAdaptor() |
73 | { | 113 | { |
114 | |||
74 | } | 115 | } |
75 | 116 | ||
76 | //TODO | 117 | void setProperty(const QString &key, const QVariant &value) |
77 | // void setProperty(const QString &key, const QVariant &value) | 118 | { |
78 | // { | 119 | if (mResourceMapper.mWriteAccessors.contains(key)) { |
79 | // //Record changes to send to resource? | 120 | // mResourceMapper.setProperty(key, value, mResourceBuffer); |
80 | // //The buffer is readonly | 121 | } else { |
81 | // } | 122 | // mLocalMapper.; |
123 | } | ||
124 | } | ||
82 | 125 | ||
83 | virtual QVariant getProperty(const QString &key) const | 126 | virtual QVariant getProperty(const QString &key) const |
84 | { | 127 | { |
85 | if (key == "summary") { | 128 | if (mResourceBuffer && mResourceMapper.mReadAccessors.contains(key)) { |
86 | //FIXME how do we check availability for on-demand request? | 129 | return mResourceMapper.getProperty(key, mResourceBuffer); |
87 | return QString::fromStdString(buffer->summary()->c_str()); | 130 | } else if (mLocalBuffer) { |
131 | return mLocalMapper.getProperty(key, mLocalBuffer); | ||
88 | } | 132 | } |
89 | return QVariant(); | 133 | return QVariant(); |
90 | } | 134 | } |
91 | 135 | ||
92 | //Data is read-only | 136 | Akonadi2::Domain::Buffer::Event const *mLocalBuffer; |
93 | DummyEvent const *buffer; | 137 | DummyEvent const *mResourceBuffer; |
138 | |||
139 | PropertyMapper<Akonadi2::Domain::Buffer::Event> mLocalMapper; | ||
140 | PropertyMapper<DummyEvent> mResourceMapper; | ||
94 | 141 | ||
95 | //Keep query alive so values remain valid | 142 | //Keep query alive so values remain valid |
96 | QSharedPointer<Akonadi2::Storage> storage; | 143 | QSharedPointer<Akonadi2::Storage> storage; |
@@ -140,6 +187,7 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function | |||
140 | qDebug() << "load called"; | 187 | qDebug() << "load called"; |
141 | 188 | ||
142 | synchronizeResource([=]() { | 189 | synchronizeResource([=]() { |
190 | qDebug() << "sync complete"; | ||
143 | //Now that the sync is complete we can execute the query | 191 | //Now that the sync is complete we can execute the query |
144 | const auto preparedQuery = prepareQuery(query); | 192 | const auto preparedQuery = prepareQuery(query); |
145 | 193 | ||
@@ -151,15 +199,19 @@ void DummyResourceFacade::load(const Akonadi2::Query &query, const std::function | |||
151 | storage->startTransaction(Akonadi2::Storage::ReadOnly); | 199 | storage->startTransaction(Akonadi2::Storage::ReadOnly); |
152 | //Because we have no indexes yet, we always do a full scan | 200 | //Because we have no indexes yet, we always do a full scan |
153 | storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { | 201 | storage->scan("", [=](void *keyValue, int keySize, void *dataValue, int dataSize) -> bool { |
154 | //TODO read the three buffers | ||
155 | qDebug() << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); | 202 | qDebug() << QString::fromStdString(std::string(static_cast<char*>(keyValue), keySize)); |
156 | auto eventBuffer = GetDummyEvent(dataValue); | 203 | auto buffer = Akonadi2::GetEntityBuffer(dataValue); |
157 | if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), eventBuffer)) { | 204 | auto resourceBuffer = GetDummyEvent(buffer->resource()); |
158 | //TODO set proper revision | 205 | auto metadataBuffer = Akonadi2::GetMetadata(buffer->resource()); |
159 | qint64 revision = 0; | 206 | auto localBuffer = Akonadi2::Domain::Buffer::GetEvent(buffer->local()); |
160 | auto event = QSharedPointer<DummyEventAdaptor>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision); | 207 | //We probably only want to create all buffers after the scan |
161 | event->buffer = eventBuffer; | 208 | if (preparedQuery && preparedQuery(std::string(static_cast<char*>(keyValue), keySize), resourceBuffer)) { |
162 | event->storage = storage; | 209 | qint64 revision = metadataBuffer->revision(); |
210 | auto adaptor = QSharedPointer<DummyEventAdaptor>::create(); | ||
211 | adaptor->mLocalBuffer = localBuffer; | ||
212 | adaptor->mResourceBuffer = resourceBuffer; | ||
213 | adaptor->storage = storage; | ||
214 | auto event = QSharedPointer<Akonadi2::Domain::Event>::create("org.kde.dummy", QString::fromUtf8(static_cast<char*>(keyValue), keySize), revision, adaptor); | ||
163 | resultCallback(event); | 215 | resultCallback(event); |
164 | } | 216 | } |
165 | return true; | 217 | return true; |
diff --git a/dummyresource/resourcefactory.cpp b/dummyresource/resourcefactory.cpp index 2c43981..6b93985 100644 --- a/dummyresource/resourcefactory.cpp +++ b/dummyresource/resourcefactory.cpp | |||
@@ -103,7 +103,7 @@ void DummyResource::synchronizeWithSource(Akonadi2::Pipeline *pipeline) | |||
103 | const auto key = QUuid::createUuid().toString().toUtf8(); | 103 | const auto key = QUuid::createUuid().toString().toUtf8(); |
104 | //TODO can we really just start populating the buffer and pass the buffer builder? | 104 | //TODO can we really just start populating the buffer and pass the buffer builder? |
105 | qDebug() << "new event"; | 105 | qDebug() << "new event"; |
106 | pipeline->newEntity(key, m_fbb); | 106 | pipeline->newEntity(key, m_fbb.GetBufferPointer(), m_fbb.GetSize()); |
107 | } else { //modification | 107 | } else { //modification |
108 | //TODO diff and create modification if necessary | 108 | //TODO diff and create modification if necessary |
109 | } | 109 | } |
@@ -121,7 +121,7 @@ void DummyResource::processCommand(int commandId, const QByteArray &data, uint s | |||
121 | builder .add_summary(m_fbb.CreateString("summary summary!")); | 121 | builder .add_summary(m_fbb.CreateString("summary summary!")); |
122 | auto buffer = builder.Finish(); | 122 | auto buffer = builder.Finish(); |
123 | DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); | 123 | DummyCalendar::FinishDummyEventBuffer(m_fbb, buffer); |
124 | pipeline->newEntity("fakekey", m_fbb); | 124 | pipeline->newEntity("fakekey", m_fbb.GetBufferPointer(), m_fbb.GetSize()); |
125 | m_fbb.Clear(); | 125 | m_fbb.Clear(); |
126 | } | 126 | } |
127 | 127 | ||