summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2014-12-24 02:15:41 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2014-12-24 02:15:41 +0100
commitc83c2ef64b5a1e4b1dc0102df36687caebb96ff0 (patch)
tree7d0567996c02e9a1ea5909abbab5f68401fd4771 /common
parentd80ff84c28c0be626c1df4528741cddf5a55f547 (diff)
downloadsink-c83c2ef64b5a1e4b1dc0102df36687caebb96ff0.tar.gz
sink-c83c2ef64b5a1e4b1dc0102df36687caebb96ff0.zip
unifying buffer, and a better way to implement domain object adapters.
Diffstat (limited to 'common')
-rw-r--r--common/CMakeLists.txt19
-rw-r--r--common/clientapi.h38
-rw-r--r--common/domain/event.fbs10
-rw-r--r--common/entitybuffer.fbs9
-rw-r--r--common/metadata.fbs7
-rw-r--r--common/pipeline.cpp40
-rw-r--r--common/pipeline.h8
-rw-r--r--common/storage.h2
-rw-r--r--common/storage_lmdb.cpp25
-rw-r--r--common/test/clientapitest.cpp2
10 files changed, 121 insertions, 39 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 @@
1project(akonadi2common) 1project(akonadi2common)
2generate_flatbuffers( 2generate_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
12if (STORAGE_unqlite) 15if (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 */
174namespace Domain { 174namespace 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 */
179class BufferAdaptor {
180public:
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 */
176class AkonadiDomainType { 190class AkonadiDomainType {
177public: 191public:
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
187private: 203private:
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
196class Event : public AkonadiDomainType { 214struct Event : public AkonadiDomainType {
197public:
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
203class Todo : public AkonadiDomainType { 219struct Todo : public AkonadiDomainType {
204public:
205 typedef QSharedPointer<Todo> Ptr; 220 typedef QSharedPointer<Todo> Ptr;
221 using AkonadiDomainType::AkonadiDomainType;
206}; 222};
207 223
208class Calendar : public AkonadiDomainType { 224struct Calendar : public AkonadiDomainType {
209public:
210 typedef QSharedPointer<Calendar> Ptr; 225 typedef QSharedPointer<Calendar> Ptr;
226 using AkonadiDomainType::AkonadiDomainType;
211}; 227};
212 228
213class Mail : public AkonadiDomainType { 229class 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 @@
1namespace Akonadi2.Domain.Buffer;
2
3table Event {
4 summary:string;
5 description:string;
6 attachment:[ubyte];
7}
8
9root_type Event;
10file_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 @@
1namespace Akonadi2;
2
3table EntityBuffer {
4 metadata: [ubyte];
5 resource: [ubyte];
6 local: [ubyte];
7}
8
9root_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 @@
1namespace Akonadi2;
2
3table Metadata {
4 revision: ulong;
5}
6
7root_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
27namespace Akonadi2 30namespace Akonadi2
28{ 31{
@@ -69,11 +72,40 @@ void Pipeline::null()
69 state.step(); 72 state.step();
70} 73}
71 74
72void Pipeline::newEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entity) 75void 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
84void Pipeline::modifiedEntity(const QByteArray &key, flatbuffers::FlatBufferBuilder &entityDelta) 116void 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
55Q_SIGNALS: 56Q_SIGNALS:
@@ -72,7 +73,6 @@ private:
72class AKONADI2COMMON_EXPORT PipelineState 73class AKONADI2COMMON_EXPORT PipelineState
73{ 74{
74public: 75public:
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
197bool Storage::write(const char *key, size_t keySize, const char *value, size_t valueSize) 197bool 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
202bool 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
239bool 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
239void Storage::read(const std::string &sKey, 244void 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