summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/asyncutils.h27
-rw-r--r--common/bufferadaptor.h54
-rw-r--r--common/bufferutils.h29
-rw-r--r--common/commands.cpp22
-rw-r--r--common/commands.h10
-rw-r--r--common/definitions.h4
-rw-r--r--common/domainadaptor.cpp1
-rw-r--r--common/domainadaptor.h52
-rw-r--r--common/domaintypeadaptorfactoryinterface.h17
-rw-r--r--common/entitybuffer.cpp23
-rw-r--r--common/entitybuffer.h14
-rw-r--r--common/facade.cpp26
-rw-r--r--common/facade.h15
-rw-r--r--common/facadefactory.cpp2
-rw-r--r--common/facadefactory.h17
-rw-r--r--common/facadeinterface.h24
-rw-r--r--common/genericresource.cpp378
-rw-r--r--common/genericresource.h29
-rw-r--r--common/index.cpp40
-rw-r--r--common/index.h12
-rw-r--r--common/indexupdater.h22
-rw-r--r--common/inspection.h11
-rw-r--r--common/listener.cpp61
-rw-r--r--common/listener.h16
-rw-r--r--common/log.cpp75
-rw-r--r--common/log.h13
-rw-r--r--common/messagequeue.cpp157
-rw-r--r--common/messagequeue.h17
-rw-r--r--common/modelresult.cpp66
-rw-r--r--common/modelresult.h10
-rw-r--r--common/notification.h4
-rw-r--r--common/notifier.cpp17
-rw-r--r--common/notifier.h4
-rw-r--r--common/pipeline.cpp247
-rw-r--r--common/pipeline.h11
-rw-r--r--common/propertymapper.cpp8
-rw-r--r--common/propertymapper.h71
-rw-r--r--common/query.h14
-rw-r--r--common/queryrunner.cpp292
-rw-r--r--common/queryrunner.h12
-rw-r--r--common/resource.cpp29
-rw-r--r--common/resource.h9
-rw-r--r--common/resourceaccess.cpp253
-rw-r--r--common/resourceaccess.h60
-rw-r--r--common/resourceconfig.cpp1
-rw-r--r--common/resourcecontrol.cpp56
-rw-r--r--common/resourcecontrol.h6
-rw-r--r--common/resourcefacade.cpp22
-rw-r--r--common/resourcefacade.h7
-rw-r--r--common/resultprovider.h124
-rw-r--r--common/resultset.cpp44
-rw-r--r--common/resultset.h60
-rw-r--r--common/storage.h77
-rw-r--r--common/storage_common.cpp78
-rw-r--r--common/storage_lmdb.cpp132
-rw-r--r--common/store.cpp145
-rw-r--r--common/store.h19
-rw-r--r--common/synclistresult.h26
-rw-r--r--common/threadboundary.cpp9
-rw-r--r--common/threadboundary.h8
-rw-r--r--common/typeindex.cpp39
-rw-r--r--common/typeindex.h9
62 files changed, 1513 insertions, 1624 deletions
diff --git a/common/asyncutils.h b/common/asyncutils.h
index ddcc37c..2cf010e 100644
--- a/common/asyncutils.h
+++ b/common/asyncutils.h
@@ -24,19 +24,18 @@
24#include <QFutureWatcher> 24#include <QFutureWatcher>
25 25
26namespace async { 26namespace async {
27 template<typename T> 27template <typename T>
28 KAsync::Job<T> run(const std::function<T()> &f) 28KAsync::Job<T> run(const std::function<T()> &f)
29 { 29{
30 return KAsync::start<T>([f](KAsync::Future<T> &future) { 30 return KAsync::start<T>([f](KAsync::Future<T> &future) {
31 auto result = QtConcurrent::run(f); 31 auto result = QtConcurrent::run(f);
32 auto watcher = new QFutureWatcher<T>; 32 auto watcher = new QFutureWatcher<T>;
33 watcher->setFuture(result); 33 watcher->setFuture(result);
34 QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() { 34 QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() {
35 future.setValue(watcher->future().result()); 35 future.setValue(watcher->future().result());
36 delete watcher; 36 delete watcher;
37 future.setFinished(); 37 future.setFinished();
38 });
39 }); 38 });
40 } 39 });
41 40}
42} 41}
diff --git a/common/bufferadaptor.h b/common/bufferadaptor.h
index 892635f..0087643 100644
--- a/common/bufferadaptor.h
+++ b/common/bufferadaptor.h
@@ -30,44 +30,64 @@ namespace ApplicationDomain {
30/** 30/**
31 * This class has to be implemented by resources and can be used as generic interface to access the buffer properties 31 * This class has to be implemented by resources and can be used as generic interface to access the buffer properties
32 */ 32 */
33class BufferAdaptor { 33class BufferAdaptor
34{
34public: 35public:
35 virtual ~BufferAdaptor() {} 36 virtual ~BufferAdaptor()
36 virtual QVariant getProperty(const QByteArray &key) const { return QVariant(); } 37 {
37 virtual void setProperty(const QByteArray &key, const QVariant &value) {} 38 }
38 virtual QList<QByteArray> availableProperties() const { return QList<QByteArray>(); } 39 virtual QVariant getProperty(const QByteArray &key) const
40 {
41 return QVariant();
42 }
43 virtual void setProperty(const QByteArray &key, const QVariant &value)
44 {
45 }
46 virtual QList<QByteArray> availableProperties() const
47 {
48 return QList<QByteArray>();
49 }
39}; 50};
40 51
41class MemoryBufferAdaptor : public BufferAdaptor { 52class MemoryBufferAdaptor : public BufferAdaptor
53{
42public: 54public:
43 MemoryBufferAdaptor() 55 MemoryBufferAdaptor() : BufferAdaptor()
44 : BufferAdaptor()
45 { 56 {
46 } 57 }
47 58
48 MemoryBufferAdaptor(const BufferAdaptor &buffer, const QList<QByteArray> &properties) 59 MemoryBufferAdaptor(const BufferAdaptor &buffer, const QList<QByteArray> &properties) : BufferAdaptor()
49 : BufferAdaptor()
50 { 60 {
51 if (properties.isEmpty()) { 61 if (properties.isEmpty()) {
52 for(const auto &property : buffer.availableProperties()) { 62 for (const auto &property : buffer.availableProperties()) {
53 mValues.insert(property, buffer.getProperty(property)); 63 mValues.insert(property, buffer.getProperty(property));
54 } 64 }
55 } else { 65 } else {
56 for(const auto &property : properties) { 66 for (const auto &property : properties) {
57 mValues.insert(property, buffer.getProperty(property)); 67 mValues.insert(property, buffer.getProperty(property));
58 } 68 }
59 } 69 }
60 } 70 }
61 71
62 virtual ~MemoryBufferAdaptor() {} 72 virtual ~MemoryBufferAdaptor()
73 {
74 }
63 75
64 virtual QVariant getProperty(const QByteArray &key) const { return mValues.value(key); } 76 virtual QVariant getProperty(const QByteArray &key) const
65 virtual void setProperty(const QByteArray &key, const QVariant &value) { mValues.insert(key, value); } 77 {
66 virtual QByteArrayList availableProperties() const { return mValues.keys(); } 78 return mValues.value(key);
79 }
80 virtual void setProperty(const QByteArray &key, const QVariant &value)
81 {
82 mValues.insert(key, value);
83 }
84 virtual QByteArrayList availableProperties() const
85 {
86 return mValues.keys();
87 }
67 88
68private: 89private:
69 QHash<QByteArray, QVariant> mValues; 90 QHash<QByteArray, QVariant> mValues;
70}; 91};
71
72} 92}
73} 93}
diff --git a/common/bufferutils.h b/common/bufferutils.h
index b08b7f8..1eb5d15 100644
--- a/common/bufferutils.h
+++ b/common/bufferutils.h
@@ -5,22 +5,21 @@
5 5
6namespace Sink { 6namespace Sink {
7namespace BufferUtils { 7namespace BufferUtils {
8 template<typename T> 8template <typename T>
9 static QByteArray extractBuffer(const T *data) 9static QByteArray extractBuffer(const T *data)
10 { 10{
11 return QByteArray::fromRawData(reinterpret_cast<char const *>(data->Data()), data->size()); 11 return QByteArray::fromRawData(reinterpret_cast<char const *>(data->Data()), data->size());
12 } 12}
13 13
14 template<typename T> 14template <typename T>
15 static QByteArray extractBufferCopy(const T *data) 15static QByteArray extractBufferCopy(const T *data)
16 { 16{
17 return QByteArray(reinterpret_cast<char const *>(data->Data()), data->size()); 17 return QByteArray(reinterpret_cast<char const *>(data->Data()), data->size());
18 } 18}
19 19
20 static QByteArray extractBuffer(const flatbuffers::FlatBufferBuilder &fbb) 20static QByteArray extractBuffer(const flatbuffers::FlatBufferBuilder &fbb)
21 { 21{
22 return QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize()); 22 return QByteArray::fromRawData(reinterpret_cast<char const *>(fbb.GetBufferPointer()), fbb.GetSize());
23 } 23}
24} 24}
25} 25}
26
diff --git a/common/commands.cpp b/common/commands.cpp
index 5d38afa..91657b8 100644
--- a/common/commands.cpp
+++ b/common/commands.cpp
@@ -22,15 +22,13 @@
22 22
23#include <QIODevice> 23#include <QIODevice>
24 24
25namespace Sink 25namespace Sink {
26{
27 26
28namespace Commands 27namespace Commands {
29{
30 28
31QByteArray name(int commandId) 29QByteArray name(int commandId)
32{ 30{
33 switch(commandId) { 31 switch (commandId) {
34 case UnknownCommand: 32 case UnknownCommand:
35 return "Unknown"; 33 return "Unknown";
36 case CommandCompletionCommand: 34 case CommandCompletionCommand:
@@ -85,9 +83,9 @@ void write(QIODevice *device, int messageId, int commandId, const char *buffer,
85 size = 0; 83 size = 0;
86 } 84 }
87 85
88 device->write((const char*)&messageId, sizeof(int)); 86 device->write((const char *)&messageId, sizeof(int));
89 device->write((const char*)&commandId, sizeof(int)); 87 device->write((const char *)&commandId, sizeof(int));
90 device->write((const char*)&size, sizeof(uint)); 88 device->write((const char *)&size, sizeof(uint));
91 if (buffer) { 89 if (buffer) {
92 device->write(buffer, size); 90 device->write(buffer, size);
93 } 91 }
@@ -96,10 +94,10 @@ void write(QIODevice *device, int messageId, int commandId, const char *buffer,
96void write(QIODevice *device, int messageId, int commandId, flatbuffers::FlatBufferBuilder &fbb) 94void write(QIODevice *device, int messageId, int commandId, flatbuffers::FlatBufferBuilder &fbb)
97{ 95{
98 const int dataSize = fbb.GetSize(); 96 const int dataSize = fbb.GetSize();
99 device->write((const char*)&messageId, sizeof(int)); 97 device->write((const char *)&messageId, sizeof(int));
100 device->write((const char*)&commandId, sizeof(int)); 98 device->write((const char *)&commandId, sizeof(int));
101 device->write((const char*)&dataSize, sizeof(int)); 99 device->write((const char *)&dataSize, sizeof(int));
102 device->write((const char*)fbb.GetBufferPointer(), dataSize); 100 device->write((const char *)fbb.GetBufferPointer(), dataSize);
103} 101}
104 102
105} // namespace Commands 103} // namespace Commands
diff --git a/common/commands.h b/common/commands.h
index 64abd76..b97bbc6 100644
--- a/common/commands.h
+++ b/common/commands.h
@@ -26,13 +26,12 @@
26 26
27class QIODevice; 27class QIODevice;
28 28
29namespace Sink 29namespace Sink {
30{
31 30
32namespace Commands 31namespace Commands {
33{
34 32
35enum CommandIds { 33enum CommandIds
34{
36 UnknownCommand = 0, 35 UnknownCommand = 0,
37 CommandCompletionCommand, 36 CommandCompletionCommand,
38 HandshakeCommand, 37 HandshakeCommand,
@@ -59,7 +58,6 @@ int SINK_EXPORT headerSize();
59void SINK_EXPORT write(QIODevice *device, int messageId, int commandId); 58void SINK_EXPORT write(QIODevice *device, int messageId, int commandId);
60void SINK_EXPORT write(QIODevice *device, int messageId, int commandId, const char *buffer, uint size); 59void SINK_EXPORT write(QIODevice *device, int messageId, int commandId, const char *buffer, uint size);
61void SINK_EXPORT write(QIODevice *device, int messageId, int commandId, flatbuffers::FlatBufferBuilder &fbb); 60void SINK_EXPORT write(QIODevice *device, int messageId, int commandId, flatbuffers::FlatBufferBuilder &fbb);
62
63} 61}
64 62
65} // namespace Sink 63} // namespace Sink
diff --git a/common/definitions.h b/common/definitions.h
index 029d3f8..96ec27e 100644
--- a/common/definitions.h
+++ b/common/definitions.h
@@ -25,6 +25,6 @@
25#include <QByteArray> 25#include <QByteArray>
26 26
27namespace Sink { 27namespace Sink {
28 QString SINK_EXPORT storageLocation(); 28QString SINK_EXPORT storageLocation();
29 QByteArray SINK_EXPORT resourceName(const QByteArray &instanceIdentifier); 29QByteArray SINK_EXPORT resourceName(const QByteArray &instanceIdentifier);
30} 30}
diff --git a/common/domainadaptor.cpp b/common/domainadaptor.cpp
index 2955cab..dcacc94 100644
--- a/common/domainadaptor.cpp
+++ b/common/domainadaptor.cpp
@@ -18,4 +18,3 @@
18 */ 18 */
19 19
20#include "domainadaptor.h" 20#include "domainadaptor.h"
21
diff --git a/common/domainadaptor.h b/common/domainadaptor.h
index 9ce5a8a..0159c6c 100644
--- a/common/domainadaptor.h
+++ b/common/domainadaptor.h
@@ -40,10 +40,11 @@
40 * Create a buffer from a domain object using the provided mappings 40 * Create a buffer from a domain object using the provided mappings
41 */ 41 */
42template <class Builder, class Buffer> 42template <class Builder, class Buffer>
43flatbuffers::Offset<Buffer> createBufferPart(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, const WritePropertyMapper<Builder> &mapper) 43flatbuffers::Offset<Buffer>
44createBufferPart(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, const WritePropertyMapper<Builder> &mapper)
44{ 45{
45 //First create a primitives such as strings using the mappings 46 // First create a primitives such as strings using the mappings
46 QList<std::function<void(Builder &)> > propertiesToAddToResource; 47 QList<std::function<void(Builder &)>> propertiesToAddToResource;
47 for (const auto &property : domainObject.changedProperties()) { 48 for (const auto &property : domainObject.changedProperties()) {
48 // Trace() << "copying property " << property; 49 // Trace() << "copying property " << property;
49 const auto value = domainObject.getProperty(property); 50 const auto value = domainObject.getProperty(property);
@@ -54,7 +55,7 @@ flatbuffers::Offset<Buffer> createBufferPart(const Sink::ApplicationDomain::Appl
54 } 55 }
55 } 56 }
56 57
57 //Then create all porperties using the above generated builderCalls 58 // Then create all porperties using the above generated builderCalls
58 Builder builder(fbb); 59 Builder builder(fbb);
59 for (auto propertyBuilder : propertiesToAddToResource) { 60 for (auto propertyBuilder : propertiesToAddToResource) {
60 propertyBuilder(builder); 61 propertyBuilder(builder);
@@ -64,7 +65,7 @@ flatbuffers::Offset<Buffer> createBufferPart(const Sink::ApplicationDomain::Appl
64 65
65/** 66/**
66 * Create the buffer and finish the FlatBufferBuilder. 67 * Create the buffer and finish the FlatBufferBuilder.
67 * 68 *
68 * After this the buffer can be extracted from the FlatBufferBuilder object. 69 * After this the buffer can be extracted from the FlatBufferBuilder object.
69 */ 70 */
70template <typename Buffer, typename BufferBuilder> 71template <typename Buffer, typename BufferBuilder>
@@ -88,10 +89,8 @@ template <class LocalBuffer, class ResourceBuffer>
88class GenericBufferAdaptor : public Sink::ApplicationDomain::BufferAdaptor 89class GenericBufferAdaptor : public Sink::ApplicationDomain::BufferAdaptor
89{ 90{
90public: 91public:
91 GenericBufferAdaptor() 92 GenericBufferAdaptor() : BufferAdaptor()
92 : BufferAdaptor()
93 { 93 {
94
95 } 94 }
96 95
97 virtual QVariant getProperty(const QByteArray &key) const 96 virtual QVariant getProperty(const QByteArray &key) const
@@ -112,8 +111,8 @@ public:
112 111
113 LocalBuffer const *mLocalBuffer; 112 LocalBuffer const *mLocalBuffer;
114 ResourceBuffer const *mResourceBuffer; 113 ResourceBuffer const *mResourceBuffer;
115 QSharedPointer<ReadPropertyMapper<LocalBuffer> > mLocalMapper; 114 QSharedPointer<ReadPropertyMapper<LocalBuffer>> mLocalMapper;
116 QSharedPointer<ReadPropertyMapper<ResourceBuffer> > mResourceMapper; 115 QSharedPointer<ReadPropertyMapper<ResourceBuffer>> mResourceMapper;
117}; 116};
118 117
119/** 118/**
@@ -121,23 +120,23 @@ public:
121 * It defines how values are split accross local and resource buffer. 120 * It defines how values are split accross local and resource buffer.
122 * This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way. 121 * This is required by the facade the read the value, and by the pipeline preprocessors to access the domain values in a generic way.
123 */ 122 */
124template<typename DomainType, typename ResourceBuffer, typename ResourceBuilder> 123template <typename DomainType, typename ResourceBuffer, typename ResourceBuilder>
125class SINK_EXPORT DomainTypeAdaptorFactory : public DomainTypeAdaptorFactoryInterface 124class SINK_EXPORT DomainTypeAdaptorFactory : public DomainTypeAdaptorFactoryInterface
126{ 125{
127 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::Buffer LocalBuffer; 126 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::Buffer LocalBuffer;
128 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::BufferBuilder LocalBuilder; 127 typedef typename Sink::ApplicationDomain::TypeImplementation<DomainType>::BufferBuilder LocalBuilder;
128
129public: 129public:
130 DomainTypeAdaptorFactory() : 130 DomainTypeAdaptorFactory()
131 mLocalMapper(Sink::ApplicationDomain::TypeImplementation<DomainType>::initializeReadPropertyMapper()), 131 : mLocalMapper(Sink::ApplicationDomain::TypeImplementation<DomainType>::initializeReadPropertyMapper()),
132 mResourceMapper(QSharedPointer<ReadPropertyMapper<ResourceBuffer> >::create()), 132 mResourceMapper(QSharedPointer<ReadPropertyMapper<ResourceBuffer>>::create()),
133 mLocalWriteMapper(Sink::ApplicationDomain::TypeImplementation<DomainType>::initializeWritePropertyMapper()), 133 mLocalWriteMapper(Sink::ApplicationDomain::TypeImplementation<DomainType>::initializeWritePropertyMapper()),
134 mResourceWriteMapper(QSharedPointer<WritePropertyMapper<ResourceBuilder> >::create()) 134 mResourceWriteMapper(QSharedPointer<WritePropertyMapper<ResourceBuilder>>::create()){};
135 {}; 135 virtual ~DomainTypeAdaptorFactory(){};
136 virtual ~DomainTypeAdaptorFactory() {};
137 136
138 /** 137 /**
139 * Creates an adaptor for the given domain and resource types. 138 * Creates an adaptor for the given domain and resource types.
140 * 139 *
141 * This returns by default a GenericBufferAdaptor initialized with the corresponding property mappers. 140 * This returns by default a GenericBufferAdaptor initialized with the corresponding property mappers.
142 */ 141 */
143 virtual QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> createAdaptor(const Sink::Entity &entity) Q_DECL_OVERRIDE 142 virtual QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> createAdaptor(const Sink::Entity &entity) Q_DECL_OVERRIDE
@@ -146,7 +145,7 @@ public:
146 const auto localBuffer = Sink::EntityBuffer::readBuffer<LocalBuffer>(entity.local()); 145 const auto localBuffer = Sink::EntityBuffer::readBuffer<LocalBuffer>(entity.local());
147 // const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); 146 // const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
148 147
149 auto adaptor = QSharedPointer<GenericBufferAdaptor<LocalBuffer, ResourceBuffer> >::create(); 148 auto adaptor = QSharedPointer<GenericBufferAdaptor<LocalBuffer, ResourceBuffer>>::create();
150 adaptor->mLocalBuffer = localBuffer; 149 adaptor->mLocalBuffer = localBuffer;
151 adaptor->mLocalMapper = mLocalMapper; 150 adaptor->mLocalMapper = mLocalMapper;
152 adaptor->mResourceBuffer = resourceBuffer; 151 adaptor->mResourceBuffer = resourceBuffer;
@@ -154,7 +153,8 @@ public:
154 return adaptor; 153 return adaptor;
155 } 154 }
156 155
157 virtual void createBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = 0, size_t metadataSize = 0) Q_DECL_OVERRIDE 156 virtual void
157 createBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainObject, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = 0, size_t metadataSize = 0) Q_DECL_OVERRIDE
158 { 158 {
159 flatbuffers::FlatBufferBuilder localFbb; 159 flatbuffers::FlatBufferBuilder localFbb;
160 if (mLocalWriteMapper) { 160 if (mLocalWriteMapper) {
@@ -173,10 +173,8 @@ public:
173 173
174 174
175protected: 175protected:
176 QSharedPointer<ReadPropertyMapper<LocalBuffer> > mLocalMapper; 176 QSharedPointer<ReadPropertyMapper<LocalBuffer>> mLocalMapper;
177 QSharedPointer<ReadPropertyMapper<ResourceBuffer> > mResourceMapper; 177 QSharedPointer<ReadPropertyMapper<ResourceBuffer>> mResourceMapper;
178 QSharedPointer<WritePropertyMapper<LocalBuilder> > mLocalWriteMapper; 178 QSharedPointer<WritePropertyMapper<LocalBuilder>> mLocalWriteMapper;
179 QSharedPointer<WritePropertyMapper<ResourceBuilder> > mResourceWriteMapper; 179 QSharedPointer<WritePropertyMapper<ResourceBuilder>> mResourceWriteMapper;
180}; 180};
181
182
diff --git a/common/domaintypeadaptorfactoryinterface.h b/common/domaintypeadaptorfactoryinterface.h
index 4d0ce04..72aa9b9 100644
--- a/common/domaintypeadaptorfactoryinterface.h
+++ b/common/domaintypeadaptorfactoryinterface.h
@@ -21,22 +21,22 @@
21#include <QSharedPointer> 21#include <QSharedPointer>
22 22
23namespace Sink { 23namespace Sink {
24 namespace ApplicationDomain { 24namespace ApplicationDomain {
25 class BufferAdaptor; 25class BufferAdaptor;
26 class ApplicationDomainType; 26class ApplicationDomainType;
27 } 27}
28 struct Entity; 28struct Entity;
29} 29}
30 30
31namespace flatbuffers { 31namespace flatbuffers {
32 class FlatBufferBuilder; 32class FlatBufferBuilder;
33} 33}
34 34
35class DomainTypeAdaptorFactoryInterface 35class DomainTypeAdaptorFactoryInterface
36{ 36{
37public: 37public:
38 typedef QSharedPointer<DomainTypeAdaptorFactoryInterface> Ptr; 38 typedef QSharedPointer<DomainTypeAdaptorFactoryInterface> Ptr;
39 virtual ~DomainTypeAdaptorFactoryInterface() {}; 39 virtual ~DomainTypeAdaptorFactoryInterface(){};
40 virtual QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> createAdaptor(const Sink::Entity &entity) = 0; 40 virtual QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> createAdaptor(const Sink::Entity &entity) = 0;
41 41
42 /* 42 /*
@@ -44,5 +44,6 @@ public:
44 * 44 *
45 * Note that this only serialized parameters that are part of ApplicationDomainType::changedProperties() 45 * Note that this only serialized parameters that are part of ApplicationDomainType::changedProperties()
46 */ 46 */
47 virtual void createBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainType, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = 0, size_t metadataSize = 0) = 0; 47 virtual void
48 createBuffer(const Sink::ApplicationDomain::ApplicationDomainType &domainType, flatbuffers::FlatBufferBuilder &fbb, void const *metadataData = 0, size_t metadataSize = 0) = 0;
48}; 49};
diff --git a/common/entitybuffer.cpp b/common/entitybuffer.cpp
index b4a5cb2..950bc46 100644
--- a/common/entitybuffer.cpp
+++ b/common/entitybuffer.cpp
@@ -6,8 +6,7 @@
6 6
7using namespace Sink; 7using namespace Sink;
8 8
9EntityBuffer::EntityBuffer(const void *dataValue, int dataSize) 9EntityBuffer::EntityBuffer(const void *dataValue, int dataSize) : mEntity(nullptr)
10 : mEntity(nullptr)
11{ 10{
12 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(dataValue), dataSize); 11 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(dataValue), dataSize);
13 // Q_ASSERT(Sink::VerifyEntity(verifyer)); 12 // Q_ASSERT(Sink::VerifyEntity(verifyer));
@@ -18,10 +17,8 @@ EntityBuffer::EntityBuffer(const void *dataValue, int dataSize)
18 } 17 }
19} 18}
20 19
21EntityBuffer::EntityBuffer(const QByteArray &data) 20EntityBuffer::EntityBuffer(const QByteArray &data) : EntityBuffer(data.constData(), data.size())
22 : EntityBuffer(data.constData(), data.size())
23{ 21{
24
25} 22}
26 23
27bool EntityBuffer::isValid() const 24bool EntityBuffer::isValid() const
@@ -35,7 +32,7 @@ const Sink::Entity &EntityBuffer::entity()
35 return *mEntity; 32 return *mEntity;
36} 33}
37 34
38const uint8_t* EntityBuffer::resourceBuffer() 35const uint8_t *EntityBuffer::resourceBuffer()
39{ 36{
40 if (!mEntity) { 37 if (!mEntity) {
41 qDebug() << "no buffer"; 38 qDebug() << "no buffer";
@@ -44,7 +41,7 @@ const uint8_t* EntityBuffer::resourceBuffer()
44 return mEntity->resource()->Data(); 41 return mEntity->resource()->Data();
45} 42}
46 43
47const uint8_t* EntityBuffer::metadataBuffer() 44const uint8_t *EntityBuffer::metadataBuffer()
48{ 45{
49 if (!mEntity) { 46 if (!mEntity) {
50 return nullptr; 47 return nullptr;
@@ -52,7 +49,7 @@ const uint8_t* EntityBuffer::metadataBuffer()
52 return mEntity->metadata()->Data(); 49 return mEntity->metadata()->Data();
53} 50}
54 51
55const uint8_t* EntityBuffer::localBuffer() 52const uint8_t *EntityBuffer::localBuffer()
56{ 53{
57 if (!mEntity) { 54 if (!mEntity) {
58 return nullptr; 55 return nullptr;
@@ -68,17 +65,18 @@ void EntityBuffer::extractResourceBuffer(void *dataValue, int dataSize, const st
68 } 65 }
69} 66}
70 67
71flatbuffers::Offset<flatbuffers::Vector<uint8_t> > EntityBuffer::appendAsVector(flatbuffers::FlatBufferBuilder &fbb, void const *data, size_t size) 68flatbuffers::Offset<flatbuffers::Vector<uint8_t>> EntityBuffer::appendAsVector(flatbuffers::FlatBufferBuilder &fbb, void const *data, size_t size)
72{ 69{
73 //Since we do memcpy trickery, this will only work on little endian 70 // Since we do memcpy trickery, this will only work on little endian
74 assert(FLATBUFFERS_LITTLEENDIAN); 71 assert(FLATBUFFERS_LITTLEENDIAN);
75 uint8_t *rawDataPtr = Q_NULLPTR; 72 uint8_t *rawDataPtr = Q_NULLPTR;
76 const auto pos = fbb.CreateUninitializedVector<uint8_t>(size, &rawDataPtr); 73 const auto pos = fbb.CreateUninitializedVector<uint8_t>(size, &rawDataPtr);
77 std::memcpy((void*)rawDataPtr, data, size); 74 std::memcpy((void *)rawDataPtr, data, size);
78 return pos; 75 return pos;
79} 76}
80 77
81void EntityBuffer::assembleEntityBuffer(flatbuffers::FlatBufferBuilder &fbb, void const *metadataData, size_t metadataSize, void const *resourceData, size_t resourceSize, void const *localData, size_t localSize) 78void EntityBuffer::assembleEntityBuffer(
79 flatbuffers::FlatBufferBuilder &fbb, void const *metadataData, size_t metadataSize, void const *resourceData, size_t resourceSize, void const *localData, size_t localSize)
82{ 80{
83 auto metadata = appendAsVector(fbb, metadataData, metadataSize); 81 auto metadata = appendAsVector(fbb, metadataData, metadataSize);
84 auto resource = appendAsVector(fbb, resourceData, resourceSize); 82 auto resource = appendAsVector(fbb, resourceData, resourceSize);
@@ -86,4 +84,3 @@ void EntityBuffer::assembleEntityBuffer(flatbuffers::FlatBufferBuilder &fbb, voi
86 auto entity = Sink::CreateEntity(fbb, metadata, resource, local); 84 auto entity = Sink::CreateEntity(fbb, metadata, resource, local);
87 Sink::FinishEntityBuffer(fbb, entity); 85 Sink::FinishEntityBuffer(fbb, entity);
88} 86}
89
diff --git a/common/entitybuffer.h b/common/entitybuffer.h
index 474a619..24f0b6b 100644
--- a/common/entitybuffer.h
+++ b/common/entitybuffer.h
@@ -8,7 +8,8 @@
8namespace Sink { 8namespace Sink {
9struct Entity; 9struct Entity;
10 10
11class SINK_EXPORT EntityBuffer { 11class SINK_EXPORT EntityBuffer
12{
12public: 13public:
13 EntityBuffer(const void *dataValue, int size); 14 EntityBuffer(const void *dataValue, int size);
14 EntityBuffer(const QByteArray &data); 15 EntityBuffer(const QByteArray &data);
@@ -25,9 +26,10 @@ public:
25 * We can't use union's either (which would allow to have a field that stores a selection of tables), as we don't want to modify 26 * We can't use union's either (which would allow to have a field that stores a selection of tables), as we don't want to modify
26 * the entity schema for each resource's buffers. 27 * the entity schema for each resource's buffers.
27 */ 28 */
28 static void assembleEntityBuffer(flatbuffers::FlatBufferBuilder &fbb, void const *metadataData, size_t metadataSize, void const *resourceData, size_t resourceSize, void const *localData, size_t localSize); 29 static void assembleEntityBuffer(
29 static flatbuffers::Offset<flatbuffers::Vector<uint8_t> > appendAsVector(flatbuffers::FlatBufferBuilder &fbb, void const *data, size_t size); 30 flatbuffers::FlatBufferBuilder &fbb, void const *metadataData, size_t metadataSize, void const *resourceData, size_t resourceSize, void const *localData, size_t localSize);
30 template<typename T> 31 static flatbuffers::Offset<flatbuffers::Vector<uint8_t>> appendAsVector(flatbuffers::FlatBufferBuilder &fbb, void const *data, size_t size);
32 template <typename T>
31 static const T *readBuffer(const uint8_t *data, int size) 33 static const T *readBuffer(const uint8_t *data, int size)
32 { 34 {
33 flatbuffers::Verifier verifier(data, size); 35 flatbuffers::Verifier verifier(data, size);
@@ -37,7 +39,7 @@ public:
37 return nullptr; 39 return nullptr;
38 } 40 }
39 41
40 template<typename T> 42 template <typename T>
41 static const T *readBuffer(const flatbuffers::Vector<uint8_t> *data) 43 static const T *readBuffer(const flatbuffers::Vector<uint8_t> *data)
42 { 44 {
43 if (data) { 45 if (data) {
@@ -50,6 +52,4 @@ public:
50private: 52private:
51 const Entity *mEntity; 53 const Entity *mEntity;
52}; 54};
53
54} 55}
55
diff --git a/common/facade.cpp b/common/facade.cpp
index 1219887..803f85c 100644
--- a/common/facade.cpp
+++ b/common/facade.cpp
@@ -32,31 +32,29 @@ using namespace Sink;
32#undef DEBUG_AREA 32#undef DEBUG_AREA
33#define DEBUG_AREA "client.facade" 33#define DEBUG_AREA "client.facade"
34 34
35template<class DomainType> 35template <class DomainType>
36GenericFacade<DomainType>::GenericFacade(const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory , const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess) 36GenericFacade<DomainType>::GenericFacade(
37 : Sink::StoreFacade<DomainType>(), 37 const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory, const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess)
38 mResourceAccess(resourceAccess), 38 : Sink::StoreFacade<DomainType>(), mResourceAccess(resourceAccess), mDomainTypeAdaptorFactory(adaptorFactory), mResourceInstanceIdentifier(resourceIdentifier)
39 mDomainTypeAdaptorFactory(adaptorFactory),
40 mResourceInstanceIdentifier(resourceIdentifier)
41{ 39{
42 if (!mResourceAccess) { 40 if (!mResourceAccess) {
43 mResourceAccess = ResourceAccessFactory::instance().getAccess(resourceIdentifier); 41 mResourceAccess = ResourceAccessFactory::instance().getAccess(resourceIdentifier);
44 } 42 }
45} 43}
46 44
47template<class DomainType> 45template <class DomainType>
48GenericFacade<DomainType>::~GenericFacade() 46GenericFacade<DomainType>::~GenericFacade()
49{ 47{
50} 48}
51 49
52template<class DomainType> 50template <class DomainType>
53QByteArray GenericFacade<DomainType>::bufferTypeForDomainType() 51QByteArray GenericFacade<DomainType>::bufferTypeForDomainType()
54{ 52{
55 //We happen to have a one to one mapping 53 // We happen to have a one to one mapping
56 return Sink::ApplicationDomain::getTypeName<DomainType>(); 54 return Sink::ApplicationDomain::getTypeName<DomainType>();
57} 55}
58 56
59template<class DomainType> 57template <class DomainType>
60KAsync::Job<void> GenericFacade<DomainType>::create(const DomainType &domainObject) 58KAsync::Job<void> GenericFacade<DomainType>::create(const DomainType &domainObject)
61{ 59{
62 if (!mDomainTypeAdaptorFactory) { 60 if (!mDomainTypeAdaptorFactory) {
@@ -68,7 +66,7 @@ KAsync::Job<void> GenericFacade<DomainType>::create(const DomainType &domainObje
68 return mResourceAccess->sendCreateCommand(bufferTypeForDomainType(), BufferUtils::extractBuffer(entityFbb)); 66 return mResourceAccess->sendCreateCommand(bufferTypeForDomainType(), BufferUtils::extractBuffer(entityFbb));
69} 67}
70 68
71template<class DomainType> 69template <class DomainType>
72KAsync::Job<void> GenericFacade<DomainType>::modify(const DomainType &domainObject) 70KAsync::Job<void> GenericFacade<DomainType>::modify(const DomainType &domainObject)
73{ 71{
74 if (!mDomainTypeAdaptorFactory) { 72 if (!mDomainTypeAdaptorFactory) {
@@ -80,16 +78,16 @@ KAsync::Job<void> GenericFacade<DomainType>::modify(const DomainType &domainObje
80 return mResourceAccess->sendModifyCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType(), QByteArrayList(), BufferUtils::extractBuffer(entityFbb)); 78 return mResourceAccess->sendModifyCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType(), QByteArrayList(), BufferUtils::extractBuffer(entityFbb));
81} 79}
82 80
83template<class DomainType> 81template <class DomainType>
84KAsync::Job<void> GenericFacade<DomainType>::remove(const DomainType &domainObject) 82KAsync::Job<void> GenericFacade<DomainType>::remove(const DomainType &domainObject)
85{ 83{
86 return mResourceAccess->sendDeleteCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType()); 84 return mResourceAccess->sendDeleteCommand(domainObject.identifier(), domainObject.revision(), bufferTypeForDomainType());
87} 85}
88 86
89template<class DomainType> 87template <class DomainType>
90QPair<KAsync::Job<void>, typename ResultEmitter<typename DomainType::Ptr>::Ptr> GenericFacade<DomainType>::load(const Sink::Query &query) 88QPair<KAsync::Job<void>, typename ResultEmitter<typename DomainType::Ptr>::Ptr> GenericFacade<DomainType>::load(const Sink::Query &query)
91{ 89{
92 //The runner lives for the lifetime of the query 90 // The runner lives for the lifetime of the query
93 auto runner = new QueryRunner<DomainType>(query, mResourceAccess, mResourceInstanceIdentifier, mDomainTypeAdaptorFactory, bufferTypeForDomainType()); 91 auto runner = new QueryRunner<DomainType>(query, mResourceAccess, mResourceInstanceIdentifier, mDomainTypeAdaptorFactory, bufferTypeForDomainType());
94 runner->setResultTransformation(mResultTransformation); 92 runner->setResultTransformation(mResultTransformation);
95 return qMakePair(KAsync::null<void>(), runner->emitter()); 93 return qMakePair(KAsync::null<void>(), runner->emitter());
diff --git a/common/facade.h b/common/facade.h
index 99fbcdc..a24ac7a 100644
--- a/common/facade.h
+++ b/common/facade.h
@@ -33,8 +33,9 @@ namespace Sink {
33 33
34/** 34/**
35 * Default facade implementation for resources that are implemented in a separate process using the ResourceAccess class. 35 * Default facade implementation for resources that are implemented in a separate process using the ResourceAccess class.
36 * 36 *
37 * Ideally a basic resource has no implementation effort for the facades and can simply instanciate default implementations (meaning it only has to implement the factory with all supported types). 37 * Ideally a basic resource has no implementation effort for the facades and can simply instanciate default implementations (meaning it only has to implement the factory with all
38 * supported types).
38 * A resource has to implement: 39 * A resource has to implement:
39 * * A facade factory registering all available facades 40 * * A facade factory registering all available facades
40 * * An adaptor factory if it uses special resource buffers (default implementation can be used otherwise) 41 * * An adaptor factory if it uses special resource buffers (default implementation can be used otherwise)
@@ -43,16 +44,17 @@ namespace Sink {
43 * Additionally a resource only has to provide a synchronizer plugin to execute the synchronization 44 * Additionally a resource only has to provide a synchronizer plugin to execute the synchronization
44 */ 45 */
45template <typename DomainType> 46template <typename DomainType>
46class SINK_EXPORT GenericFacade: public Sink::StoreFacade<DomainType> 47class SINK_EXPORT GenericFacade : public Sink::StoreFacade<DomainType>
47{ 48{
48public: 49public:
49 /** 50 /**
50 * Create a new GenericFacade 51 * Create a new GenericFacade
51 * 52 *
52 * @param resourceIdentifier is the identifier of the resource instance 53 * @param resourceIdentifier is the identifier of the resource instance
53 * @param adaptorFactory is the adaptor factory used to generate the mappings from domain to resource types and vice versa 54 * @param adaptorFactory is the adaptor factory used to generate the mappings from domain to resource types and vice versa
54 */ 55 */
55 GenericFacade(const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory = DomainTypeAdaptorFactoryInterface::Ptr(), const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess = QSharedPointer<Sink::ResourceAccessInterface>()); 56 GenericFacade(const QByteArray &resourceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &adaptorFactory = DomainTypeAdaptorFactoryInterface::Ptr(),
57 const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess = QSharedPointer<Sink::ResourceAccessInterface>());
56 ~GenericFacade(); 58 ~GenericFacade();
57 59
58 static QByteArray bufferTypeForDomainType(); 60 static QByteArray bufferTypeForDomainType();
@@ -63,10 +65,9 @@ public:
63 65
64protected: 66protected:
65 std::function<void(Sink::ApplicationDomain::ApplicationDomainType &domainObject)> mResultTransformation; 67 std::function<void(Sink::ApplicationDomain::ApplicationDomainType &domainObject)> mResultTransformation;
66 //TODO use one resource access instance per application & per resource 68 // TODO use one resource access instance per application & per resource
67 QSharedPointer<Sink::ResourceAccessInterface> mResourceAccess; 69 QSharedPointer<Sink::ResourceAccessInterface> mResourceAccess;
68 DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory; 70 DomainTypeAdaptorFactoryInterface::Ptr mDomainTypeAdaptorFactory;
69 QByteArray mResourceInstanceIdentifier; 71 QByteArray mResourceInstanceIdentifier;
70}; 72};
71
72} 73}
diff --git a/common/facadefactory.cpp b/common/facadefactory.cpp
index d9ee5f7..ab52681 100644
--- a/common/facadefactory.cpp
+++ b/common/facadefactory.cpp
@@ -64,7 +64,7 @@ std::shared_ptr<void> FacadeFactory::getFacade(const QByteArray &resource, const
64 const QByteArray k = key(resource, typeName); 64 const QByteArray k = key(resource, typeName);
65 if (!mFacadeRegistry.contains(k)) { 65 if (!mFacadeRegistry.contains(k)) {
66 locker.unlock(); 66 locker.unlock();
67 //This will call FacadeFactory::instace() internally 67 // This will call FacadeFactory::instace() internally
68 Sink::ResourceFactory::load(QString::fromLatin1(resource)); 68 Sink::ResourceFactory::load(QString::fromLatin1(resource));
69 locker.relock(); 69 locker.relock();
70 } 70 }
diff --git a/common/facadefactory.h b/common/facadefactory.h
index ef2a3f9..83b8898 100644
--- a/common/facadefactory.h
+++ b/common/facadefactory.h
@@ -38,7 +38,8 @@ namespace Sink {
38 * 38 *
39 * If we were to provide default implementations for certain capabilities. Here would be the place to do so. 39 * If we were to provide default implementations for certain capabilities. Here would be the place to do so.
40 */ 40 */
41class SINK_EXPORT FacadeFactory { 41class SINK_EXPORT FacadeFactory
42{
42public: 43public:
43 typedef std::function<std::shared_ptr<void>(const QByteArray &)> FactoryFunction; 44 typedef std::function<std::shared_ptr<void>(const QByteArray &)> FactoryFunction;
44 45
@@ -48,10 +49,10 @@ public:
48 49
49 static QByteArray key(const QByteArray &resource, const QByteArray &type); 50 static QByteArray key(const QByteArray &resource, const QByteArray &type);
50 51
51 template<class DomainType, class Facade> 52 template <class DomainType, class Facade>
52 void registerFacade(const QByteArray &resource) 53 void registerFacade(const QByteArray &resource)
53 { 54 {
54 registerFacade(resource, [](const QByteArray &instanceIdentifier){ return std::make_shared<Facade>(instanceIdentifier); }, ApplicationDomain::getTypeName<DomainType>()); 55 registerFacade(resource, [](const QByteArray &instanceIdentifier) { return std::make_shared<Facade>(instanceIdentifier); }, ApplicationDomain::getTypeName<DomainType>());
55 } 56 }
56 57
57 /* 58 /*
@@ -59,7 +60,7 @@ public:
59 * 60 *
60 * Primarily for testing. 61 * Primarily for testing.
61 */ 62 */
62 template<class DomainType, class Facade> 63 template <class DomainType, class Facade>
63 void registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction) 64 void registerFacade(const QByteArray &resource, const FactoryFunction &customFactoryFunction)
64 { 65 {
65 registerFacade(resource, customFactoryFunction, ApplicationDomain::getTypeName<DomainType>()); 66 registerFacade(resource, customFactoryFunction, ApplicationDomain::getTypeName<DomainType>());
@@ -72,11 +73,11 @@ public:
72 */ 73 */
73 void resetFactory(); 74 void resetFactory();
74 75
75 template<class DomainType> 76 template <class DomainType>
76 std::shared_ptr<StoreFacade<DomainType> > getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier) 77 std::shared_ptr<StoreFacade<DomainType>> getFacade(const QByteArray &resource, const QByteArray &instanceIdentifier)
77 { 78 {
78 const QByteArray typeName = ApplicationDomain::getTypeName<DomainType>(); 79 const QByteArray typeName = ApplicationDomain::getTypeName<DomainType>();
79 return std::static_pointer_cast<StoreFacade<DomainType> >(getFacade(resource, instanceIdentifier, typeName)); 80 return std::static_pointer_cast<StoreFacade<DomainType>>(getFacade(resource, instanceIdentifier, typeName));
80 } 81 }
81 82
82private: 83private:
@@ -87,6 +88,4 @@ private:
87 QHash<QByteArray, FactoryFunction> mFacadeRegistry; 88 QHash<QByteArray, FactoryFunction> mFacadeRegistry;
88 static QMutex sMutex; 89 static QMutex sMutex;
89}; 90};
90
91} 91}
92
diff --git a/common/facadeinterface.h b/common/facadeinterface.h
index 17cba5e..7d5dd7d 100644
--- a/common/facadeinterface.h
+++ b/common/facadeinterface.h
@@ -32,17 +32,21 @@ class Query;
32 32
33/** 33/**
34 * Interface for the store facade. 34 * Interface for the store facade.
35 * 35 *
36 * All methods are synchronous. 36 * All methods are synchronous.
37 * Facades are stateful (they hold connections to resources and database). 37 * Facades are stateful (they hold connections to resources and database).
38 * 38 *
39 * TODO: would it make sense to split the write, read and notification parts? (we could potentially save some connections) 39 * TODO: would it make sense to split the write, read and notification parts? (we could potentially save some connections)
40 */ 40 */
41template<class DomainType> 41template <class DomainType>
42class StoreFacade { 42class StoreFacade
43{
43public: 44public:
44 virtual ~StoreFacade(){}; 45 virtual ~StoreFacade(){};
45 QByteArray type() const { return ApplicationDomain::getTypeName<DomainType>(); } 46 QByteArray type() const
47 {
48 return ApplicationDomain::getTypeName<DomainType>();
49 }
46 50
47 /** 51 /**
48 * Create an entity in the store. 52 * Create an entity in the store.
@@ -68,11 +72,12 @@ public:
68 /** 72 /**
69 * Load entities from the store. 73 * Load entities from the store.
70 */ 74 */
71 virtual QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr > load(const Query &query) = 0; 75 virtual QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr> load(const Query &query) = 0;
72}; 76};
73 77
74template<class DomainType> 78template <class DomainType>
75class NullFacade : public StoreFacade<DomainType> { 79class NullFacade : public StoreFacade<DomainType>
80{
76public: 81public:
77 virtual ~NullFacade(){}; 82 virtual ~NullFacade(){};
78 KAsync::Job<void> create(const DomainType &domainObject) 83 KAsync::Job<void> create(const DomainType &domainObject)
@@ -90,10 +95,9 @@ public:
90 return KAsync::error<void>(-1, "Failed to create a facade"); 95 return KAsync::error<void>(-1, "Failed to create a facade");
91 } 96 }
92 97
93 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr > load(const Query &query) 98 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr> load(const Query &query)
94 { 99 {
95 return qMakePair(KAsync::null<void>(), typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr()); 100 return qMakePair(KAsync::null<void>(), typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr());
96 } 101 }
97}; 102};
98
99} 103}
diff --git a/common/genericresource.cpp b/common/genericresource.cpp
index 74a8cfb..9c9a12f 100644
--- a/common/genericresource.cpp
+++ b/common/genericresource.cpp
@@ -20,7 +20,7 @@
20#include <QTime> 20#include <QTime>
21 21
22static int sBatchSize = 100; 22static int sBatchSize = 100;
23//This interval directly affects the roundtrip time of single commands 23// This interval directly affects the roundtrip time of single commands
24static int sCommitInterval = 10; 24static int sCommitInterval = 10;
25 25
26using namespace Sink; 26using namespace Sink;
@@ -39,26 +39,23 @@ class ChangeReplay : public QObject
39{ 39{
40 Q_OBJECT 40 Q_OBJECT
41public: 41public:
42
43 typedef std::function<KAsync::Job<void>(const QByteArray &type, const QByteArray &key, const QByteArray &value)> ReplayFunction; 42 typedef std::function<KAsync::Job<void>(const QByteArray &type, const QByteArray &key, const QByteArray &value)> ReplayFunction;
44 43
45 ChangeReplay(const QString &resourceName, const ReplayFunction &replayFunction) 44 ChangeReplay(const QString &resourceName, const ReplayFunction &replayFunction)
46 : mStorage(storageLocation(), resourceName, Storage::ReadOnly), 45 : mStorage(storageLocation(), resourceName, Storage::ReadOnly), mChangeReplayStore(storageLocation(), resourceName + ".changereplay", Storage::ReadWrite), mReplayFunction(replayFunction)
47 mChangeReplayStore(storageLocation(), resourceName + ".changereplay", Storage::ReadWrite),
48 mReplayFunction(replayFunction)
49 { 46 {
50
51 } 47 }
52 48
53 qint64 getLastReplayedRevision() 49 qint64 getLastReplayedRevision()
54 { 50 {
55 qint64 lastReplayedRevision = 0; 51 qint64 lastReplayedRevision = 0;
56 auto replayStoreTransaction = mChangeReplayStore.createTransaction(Storage::ReadOnly); 52 auto replayStoreTransaction = mChangeReplayStore.createTransaction(Storage::ReadOnly);
57 replayStoreTransaction.openDatabase().scan("lastReplayedRevision", [&lastReplayedRevision](const QByteArray &key, const QByteArray &value) -> bool { 53 replayStoreTransaction.openDatabase().scan("lastReplayedRevision",
58 lastReplayedRevision = value.toLongLong(); 54 [&lastReplayedRevision](const QByteArray &key, const QByteArray &value) -> bool {
59 return false; 55 lastReplayedRevision = value.toLongLong();
60 }, [](const Storage::Error &) { 56 return false;
61 }); 57 },
58 [](const Storage::Error &) {});
62 return lastReplayedRevision; 59 return lastReplayedRevision;
63 } 60 }
64 61
@@ -79,28 +76,30 @@ public slots:
79 auto mainStoreTransaction = mStorage.createTransaction(Storage::ReadOnly); 76 auto mainStoreTransaction = mStorage.createTransaction(Storage::ReadOnly);
80 auto replayStoreTransaction = mChangeReplayStore.createTransaction(Storage::ReadWrite); 77 auto replayStoreTransaction = mChangeReplayStore.createTransaction(Storage::ReadWrite);
81 qint64 lastReplayedRevision = 1; 78 qint64 lastReplayedRevision = 1;
82 replayStoreTransaction.openDatabase().scan("lastReplayedRevision", [&lastReplayedRevision](const QByteArray &key, const QByteArray &value) -> bool { 79 replayStoreTransaction.openDatabase().scan("lastReplayedRevision",
83 lastReplayedRevision = value.toLongLong(); 80 [&lastReplayedRevision](const QByteArray &key, const QByteArray &value) -> bool {
84 return false; 81 lastReplayedRevision = value.toLongLong();
85 }, [](const Storage::Error &) { 82 return false;
86 }); 83 },
84 [](const Storage::Error &) {});
87 const qint64 topRevision = Storage::maxRevision(mainStoreTransaction); 85 const qint64 topRevision = Storage::maxRevision(mainStoreTransaction);
88 86
89 Trace() << "Changereplay from " << lastReplayedRevision << " to " << topRevision; 87 Trace() << "Changereplay from " << lastReplayedRevision << " to " << topRevision;
90 if (lastReplayedRevision <= topRevision) { 88 if (lastReplayedRevision <= topRevision) {
91 qint64 revision = lastReplayedRevision; 89 qint64 revision = lastReplayedRevision;
92 for (;revision <= topRevision; revision++) { 90 for (; revision <= topRevision; revision++) {
93 const auto uid = Storage::getUidFromRevision(mainStoreTransaction, revision); 91 const auto uid = Storage::getUidFromRevision(mainStoreTransaction, revision);
94 const auto type = Storage::getTypeFromRevision(mainStoreTransaction, revision); 92 const auto type = Storage::getTypeFromRevision(mainStoreTransaction, revision);
95 const auto key = Storage::assembleKey(uid, revision); 93 const auto key = Storage::assembleKey(uid, revision);
96 Storage::mainDatabase(mainStoreTransaction, type).scan(key, [&lastReplayedRevision, type, this](const QByteArray &key, const QByteArray &value) -> bool { 94 Storage::mainDatabase(mainStoreTransaction, type)
97 mReplayFunction(type, key, value).exec(); 95 .scan(key,
98 //TODO make for loop async, and pass to async replay function together with type 96 [&lastReplayedRevision, type, this](const QByteArray &key, const QByteArray &value) -> bool {
99 Trace() << "Replaying " << key; 97 mReplayFunction(type, key, value).exec();
100 return false; 98 // TODO make for loop async, and pass to async replay function together with type
101 }, [key](const Storage::Error &) { 99 Trace() << "Replaying " << key;
102 ErrorMsg() << "Failed to replay change " << key; 100 return false;
103 }); 101 },
102 [key](const Storage::Error &) { ErrorMsg() << "Failed to replay change " << key; });
104 } 103 }
105 revision--; 104 revision--;
106 replayStoreTransaction.openDatabase().write("lastReplayedRevision", QByteArray::number(revision)); 105 replayStoreTransaction.openDatabase().write("lastReplayedRevision", QByteArray::number(revision));
@@ -126,15 +125,12 @@ class CommandProcessor : public QObject
126{ 125{
127 Q_OBJECT 126 Q_OBJECT
128 typedef std::function<KAsync::Job<void>(void const *, size_t)> InspectionFunction; 127 typedef std::function<KAsync::Job<void>(void const *, size_t)> InspectionFunction;
128
129public: 129public:
130 CommandProcessor(Sink::Pipeline *pipeline, QList<MessageQueue*> commandQueues) 130 CommandProcessor(Sink::Pipeline *pipeline, QList<MessageQueue *> commandQueues) : QObject(), mPipeline(pipeline), mCommandQueues(commandQueues), mProcessingLock(false)
131 : QObject(),
132 mPipeline(pipeline),
133 mCommandQueues(commandQueues),
134 mProcessingLock(false)
135 { 131 {
136 mPipeline->startTransaction(); 132 mPipeline->startTransaction();
137 //FIXME Should be initialized to the current value of the change replay queue 133 // FIXME Should be initialized to the current value of the change replay queue
138 mLowerBoundRevision = Storage::maxRevision(mPipeline->transaction()); 134 mLowerBoundRevision = Storage::maxRevision(mPipeline->transaction());
139 mPipeline->commit(); 135 mPipeline->commit();
140 136
@@ -176,18 +172,20 @@ private slots:
176 return; 172 return;
177 } 173 }
178 mProcessingLock = true; 174 mProcessingLock = true;
179 auto job = processPipeline().then<void>([this]() { 175 auto job = processPipeline()
180 mProcessingLock = false; 176 .then<void>([this]() {
181 if (messagesToProcessAvailable()) { 177 mProcessingLock = false;
182 process(); 178 if (messagesToProcessAvailable()) {
183 } 179 process();
184 }).exec(); 180 }
181 })
182 .exec();
185 } 183 }
186 184
187 KAsync::Job<qint64> processQueuedCommand(const Sink::QueuedCommand *queuedCommand) 185 KAsync::Job<qint64> processQueuedCommand(const Sink::QueuedCommand *queuedCommand)
188 { 186 {
189 Log() << "Processing command: " << Sink::Commands::name(queuedCommand->commandId()); 187 Log() << "Processing command: " << Sink::Commands::name(queuedCommand->commandId());
190 //Throw command into appropriate pipeline 188 // Throw command into appropriate pipeline
191 switch (queuedCommand->commandId()) { 189 switch (queuedCommand->commandId()) {
192 case Sink::Commands::DeleteEntityCommand: 190 case Sink::Commands::DeleteEntityCommand:
193 return mPipeline->deletedEntity(queuedCommand->command()->Data(), queuedCommand->command()->size()); 191 return mPipeline->deletedEntity(queuedCommand->command()->Data(), queuedCommand->command()->size());
@@ -197,9 +195,7 @@ private slots:
197 return mPipeline->newEntity(queuedCommand->command()->Data(), queuedCommand->command()->size()); 195 return mPipeline->newEntity(queuedCommand->command()->Data(), queuedCommand->command()->size());
198 case Sink::Commands::InspectionCommand: 196 case Sink::Commands::InspectionCommand:
199 if (mInspect) { 197 if (mInspect) {
200 return mInspect(queuedCommand->command()->Data(), queuedCommand->command()->size()).then<qint64>([]() { 198 return mInspect(queuedCommand->command()->Data(), queuedCommand->command()->size()).then<qint64>([]() { return -1; });
201 return -1;
202 });
203 } else { 199 } else {
204 return KAsync::error<qint64>(-1, "Missing inspection command."); 200 return KAsync::error<qint64>(-1, "Missing inspection command.");
205 } 201 }
@@ -218,50 +214,47 @@ private slots:
218 auto queuedCommand = Sink::GetQueuedCommand(data.constData()); 214 auto queuedCommand = Sink::GetQueuedCommand(data.constData());
219 const auto commandId = queuedCommand->commandId(); 215 const auto commandId = queuedCommand->commandId();
220 Trace() << "Dequeued Command: " << Sink::Commands::name(commandId); 216 Trace() << "Dequeued Command: " << Sink::Commands::name(commandId);
221 return processQueuedCommand(queuedCommand).then<qint64, qint64>( 217 return processQueuedCommand(queuedCommand)
222 [commandId](qint64 createdRevision) -> qint64 { 218 .then<qint64, qint64>(
223 Trace() << "Command pipeline processed: " << Sink::Commands::name(commandId); 219 [commandId](qint64 createdRevision) -> qint64 {
224 return createdRevision; 220 Trace() << "Command pipeline processed: " << Sink::Commands::name(commandId);
225 } 221 return createdRevision;
226 , 222 },
227 [](int errorCode, QString errorMessage) { 223 [](int errorCode, QString errorMessage) {
228 //FIXME propagate error, we didn't handle it 224 // FIXME propagate error, we didn't handle it
229 Warning() << "Error while processing queue command: " << errorMessage; 225 Warning() << "Error while processing queue command: " << errorMessage;
230 } 226 });
231 );
232 } 227 }
233 228
234 //Process all messages of this queue 229 // Process all messages of this queue
235 KAsync::Job<void> processQueue(MessageQueue *queue) 230 KAsync::Job<void> processQueue(MessageQueue *queue)
236 { 231 {
237 auto time = QSharedPointer<QTime>::create(); 232 auto time = QSharedPointer<QTime>::create();
238 return KAsync::start<void>([this](){ 233 return KAsync::start<void>([this]() { mPipeline->startTransaction(); })
239 mPipeline->startTransaction(); 234 .then(KAsync::dowhile([queue]() { return !queue->isEmpty(); },
240 }).then(KAsync::dowhile( 235 [this, queue, time](KAsync::Future<void> &future) {
241 [queue]() { return !queue->isEmpty(); }, 236 queue->dequeueBatch(sBatchSize,
242 [this, queue, time](KAsync::Future<void> &future) { 237 [this, time](const QByteArray &data) {
243 queue->dequeueBatch(sBatchSize, [this, time](const QByteArray &data) { 238 time->start();
244 time->start(); 239 return KAsync::start<void>([this, data, time](KAsync::Future<void> &future) {
245 return KAsync::start<void>([this, data, time](KAsync::Future<void> &future) { 240 processQueuedCommand(data)
246 processQueuedCommand(data).then<void, qint64>([&future, this, time](qint64 createdRevision) { 241 .then<void, qint64>([&future, this, time](qint64 createdRevision) {
247 Trace() << "Created revision " << createdRevision << ". Processing took: " << Log::TraceTime(time->elapsed()); 242 Trace() << "Created revision " << createdRevision << ". Processing took: " << Log::TraceTime(time->elapsed());
243 future.setFinished();
244 })
245 .exec();
246 });
247 })
248 .then<void>([&future, queue]() { future.setFinished(); },
249 [&future](int i, QString error) {
250 if (i != MessageQueue::ErrorCodes::NoMessageFound) {
251 Warning() << "Error while getting message from messagequeue: " << error;
252 }
248 future.setFinished(); 253 future.setFinished();
249 }).exec(); 254 })
250 }); 255 .exec();
251 } 256 }))
252 ).then<void>([&future, queue](){ 257 .then<void>([this]() { mPipeline->commit(); });
253 future.setFinished();
254 },
255 [&future](int i, QString error) {
256 if (i != MessageQueue::ErrorCodes::NoMessageFound) {
257 Warning() << "Error while getting message from messagequeue: " << error;
258 }
259 future.setFinished();
260 }).exec();
261 }
262 )).then<void>([this]() {
263 mPipeline->commit();
264 });
265 } 258 }
266 259
267 KAsync::Job<void> processPipeline() 260 KAsync::Job<void> processPipeline()
@@ -276,29 +269,29 @@ private slots:
276 mPipeline->commit(); 269 mPipeline->commit();
277 Trace() << "Cleanup done." << Log::TraceTime(time->elapsed()); 270 Trace() << "Cleanup done." << Log::TraceTime(time->elapsed());
278 271
279 //Go through all message queues 272 // Go through all message queues
280 auto it = QSharedPointer<QListIterator<MessageQueue*> >::create(mCommandQueues); 273 auto it = QSharedPointer<QListIterator<MessageQueue *>>::create(mCommandQueues);
281 return KAsync::dowhile( 274 return KAsync::dowhile([it]() { return it->hasNext(); },
282 [it]() { return it->hasNext(); },
283 [it, this](KAsync::Future<void> &future) { 275 [it, this](KAsync::Future<void> &future) {
284 auto time = QSharedPointer<QTime>::create(); 276 auto time = QSharedPointer<QTime>::create();
285 time->start(); 277 time->start();
286 278
287 auto queue = it->next(); 279 auto queue = it->next();
288 processQueue(queue).then<void>([&future, time]() { 280 processQueue(queue)
289 Trace() << "Queue processed." << Log::TraceTime(time->elapsed()); 281 .then<void>([&future, time]() {
290 future.setFinished(); 282 Trace() << "Queue processed." << Log::TraceTime(time->elapsed());
291 }).exec(); 283 future.setFinished();
292 } 284 })
293 ); 285 .exec();
286 });
294 } 287 }
295 288
296private: 289private:
297 Sink::Pipeline *mPipeline; 290 Sink::Pipeline *mPipeline;
298 //Ordered by priority 291 // Ordered by priority
299 QList<MessageQueue*> mCommandQueues; 292 QList<MessageQueue *> mCommandQueues;
300 bool mProcessingLock; 293 bool mProcessingLock;
301 //The lowest revision we no longer need 294 // The lowest revision we no longer need
302 qint64 mLowerBoundRevision; 295 qint64 mLowerBoundRevision;
303 InspectionFunction mInspect; 296 InspectionFunction mInspect;
304}; 297};
@@ -308,14 +301,14 @@ private:
308 301
309GenericResource::GenericResource(const QByteArray &resourceInstanceIdentifier, const QSharedPointer<Pipeline> &pipeline) 302GenericResource::GenericResource(const QByteArray &resourceInstanceIdentifier, const QSharedPointer<Pipeline> &pipeline)
310 : Sink::Resource(), 303 : Sink::Resource(),
311 mUserQueue(Sink::storageLocation(), resourceInstanceIdentifier + ".userqueue"), 304 mUserQueue(Sink::storageLocation(), resourceInstanceIdentifier + ".userqueue"),
312 mSynchronizerQueue(Sink::storageLocation(), resourceInstanceIdentifier + ".synchronizerqueue"), 305 mSynchronizerQueue(Sink::storageLocation(), resourceInstanceIdentifier + ".synchronizerqueue"),
313 mResourceInstanceIdentifier(resourceInstanceIdentifier), 306 mResourceInstanceIdentifier(resourceInstanceIdentifier),
314 mPipeline(pipeline ? pipeline : QSharedPointer<Sink::Pipeline>::create(resourceInstanceIdentifier)), 307 mPipeline(pipeline ? pipeline : QSharedPointer<Sink::Pipeline>::create(resourceInstanceIdentifier)),
315 mError(0), 308 mError(0),
316 mClientLowerBoundRevision(std::numeric_limits<qint64>::max()) 309 mClientLowerBoundRevision(std::numeric_limits<qint64>::max())
317{ 310{
318 mProcessor = new CommandProcessor(mPipeline.data(), QList<MessageQueue*>() << &mUserQueue << &mSynchronizerQueue); 311 mProcessor = new CommandProcessor(mPipeline.data(), QList<MessageQueue *>() << &mUserQueue << &mSynchronizerQueue);
319 mProcessor->setInspectionCommand([this](void const *command, size_t size) { 312 mProcessor->setInspectionCommand([this](void const *command, size_t size) {
320 flatbuffers::Verifier verifier((const uint8_t *)command, size); 313 flatbuffers::Verifier verifier((const uint8_t *)command, size);
321 if (Sink::Commands::VerifyInspectionBuffer(verifier)) { 314 if (Sink::Commands::VerifyInspectionBuffer(verifier)) {
@@ -330,22 +323,26 @@ GenericResource::GenericResource(const QByteArray &resourceInstanceIdentifier, c
330 QDataStream s(expectedValueString); 323 QDataStream s(expectedValueString);
331 QVariant expectedValue; 324 QVariant expectedValue;
332 s >> expectedValue; 325 s >> expectedValue;
333 inspect(inspectionType, inspectionId, domainType, entityId, property, expectedValue).then<void>([=]() { 326 inspect(inspectionType, inspectionId, domainType, entityId, property, expectedValue)
334 Log_area("resource.inspection") << "Inspection was successful: " << inspectionType << inspectionId << entityId; 327 .then<void>(
335 Sink::Notification n; 328 [=]() {
336 n.type = Sink::Commands::NotificationType_Inspection; 329 Log_area("resource.inspection") << "Inspection was successful: " << inspectionType << inspectionId << entityId;
337 n.id = inspectionId; 330 Sink::Notification n;
338 n.code = Sink::Commands::NotificationCode_Success; 331 n.type = Sink::Commands::NotificationType_Inspection;
339 emit notify(n); 332 n.id = inspectionId;
340 }, [=](int code, const QString &message) { 333 n.code = Sink::Commands::NotificationCode_Success;
341 Log() << "Inspection failed: "<< inspectionType << inspectionId << entityId << message; 334 emit notify(n);
342 Sink::Notification n; 335 },
343 n.type = Sink::Commands::NotificationType_Inspection; 336 [=](int code, const QString &message) {
344 n.message = message; 337 Log() << "Inspection failed: " << inspectionType << inspectionId << entityId << message;
345 n.id = inspectionId; 338 Sink::Notification n;
346 n.code = Sink::Commands::NotificationCode_Failure; 339 n.type = Sink::Commands::NotificationType_Inspection;
347 emit notify(n); 340 n.message = message;
348 }).exec(); 341 n.id = inspectionId;
342 n.code = Sink::Commands::NotificationCode_Failure;
343 emit notify(n);
344 })
345 .exec();
349 return KAsync::null<void>(); 346 return KAsync::null<void>();
350 } 347 }
351 return KAsync::error<void>(-1, "Invalid inspection command."); 348 return KAsync::error<void>(-1, "Invalid inspection command.");
@@ -353,9 +350,9 @@ GenericResource::GenericResource(const QByteArray &resourceInstanceIdentifier, c
353 QObject::connect(mProcessor, &CommandProcessor::error, [this](int errorCode, const QString &msg) { onProcessorError(errorCode, msg); }); 350 QObject::connect(mProcessor, &CommandProcessor::error, [this](int errorCode, const QString &msg) { onProcessorError(errorCode, msg); });
354 QObject::connect(mPipeline.data(), &Pipeline::revisionUpdated, this, &Resource::revisionUpdated); 351 QObject::connect(mPipeline.data(), &Pipeline::revisionUpdated, this, &Resource::revisionUpdated);
355 mSourceChangeReplay = new ChangeReplay(resourceInstanceIdentifier, [this](const QByteArray &type, const QByteArray &key, const QByteArray &value) { 352 mSourceChangeReplay = new ChangeReplay(resourceInstanceIdentifier, [this](const QByteArray &type, const QByteArray &key, const QByteArray &value) {
356 //This results in a deadlock when a sync is in progress and we try to create a second writing transaction (which is why we turn changereplay off during the sync) 353 // This results in a deadlock when a sync is in progress and we try to create a second writing transaction (which is why we turn changereplay off during the sync)
357 auto synchronizationStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier + ".synchronization", Sink::Storage::ReadWrite); 354 auto synchronizationStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier + ".synchronization", Sink::Storage::ReadWrite);
358 return this->replay(*synchronizationStore, type, key, value).then<void>([synchronizationStore](){}); 355 return this->replay(*synchronizationStore, type, key, value).then<void>([synchronizationStore]() {});
359 }); 356 });
360 enableChangeReplay(true); 357 enableChangeReplay(true);
361 mClientLowerBoundRevision = mPipeline->cleanedUpRevision(); 358 mClientLowerBoundRevision = mPipeline->cleanedUpRevision();
@@ -372,7 +369,8 @@ GenericResource::~GenericResource()
372 delete mSourceChangeReplay; 369 delete mSourceChangeReplay;
373} 370}
374 371
375KAsync::Job<void> GenericResource::inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) 372KAsync::Job<void> GenericResource::inspect(
373 int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue)
376{ 374{
377 Warning() << "Inspection not implemented"; 375 Warning() << "Inspection not implemented";
378 return KAsync::null<void>(); 376 return KAsync::null<void>();
@@ -390,7 +388,7 @@ void GenericResource::enableChangeReplay(bool enable)
390 } 388 }
391} 389}
392 390
393void GenericResource::addType(const QByteArray &type, DomainTypeAdaptorFactoryInterface::Ptr factory, const QVector<Sink::Preprocessor*> &preprocessors) 391void GenericResource::addType(const QByteArray &type, DomainTypeAdaptorFactoryInterface::Ptr factory, const QVector<Sink::Preprocessor *> &preprocessors)
394{ 392{
395 mPipeline->setPreprocessors(type, preprocessors); 393 mPipeline->setPreprocessors(type, preprocessors);
396 mPipeline->setAdaptorFactory(type, factory); 394 mPipeline->setAdaptorFactory(type, factory);
@@ -463,14 +461,16 @@ KAsync::Job<void> GenericResource::synchronizeWithSource()
463{ 461{
464 return KAsync::start<void>([this]() { 462 return KAsync::start<void>([this]() {
465 Log() << " Synchronizing"; 463 Log() << " Synchronizing";
466 //Changereplay would deadlock otherwise when trying to open the synchronization store 464 // Changereplay would deadlock otherwise when trying to open the synchronization store
467 enableChangeReplay(false); 465 enableChangeReplay(false);
468 auto mainStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier, Sink::Storage::ReadOnly); 466 auto mainStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier, Sink::Storage::ReadOnly);
469 auto syncStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier + ".synchronization", Sink::Storage::ReadWrite); 467 auto syncStore = QSharedPointer<Sink::Storage>::create(Sink::storageLocation(), mResourceInstanceIdentifier + ".synchronization", Sink::Storage::ReadWrite);
470 synchronizeWithSource(*mainStore, *syncStore).then<void>([this, mainStore, syncStore]() { 468 synchronizeWithSource(*mainStore, *syncStore)
471 Log() << "Done Synchronizing"; 469 .then<void>([this, mainStore, syncStore]() {
472 enableChangeReplay(true); 470 Log() << "Done Synchronizing";
473 }).exec(); 471 enableChangeReplay(true);
472 })
473 .exec();
474 }); 474 });
475} 475}
476 476
@@ -484,42 +484,39 @@ static void waitForDrained(KAsync::Future<void> &f, MessageQueue &queue)
484 if (queue.isEmpty()) { 484 if (queue.isEmpty()) {
485 f.setFinished(); 485 f.setFinished();
486 } else { 486 } else {
487 QObject::connect(&queue, &MessageQueue::drained, [&f]() { 487 QObject::connect(&queue, &MessageQueue::drained, [&f]() { f.setFinished(); });
488 f.setFinished();
489 });
490 } 488 }
491}; 489};
492 490
493KAsync::Job<void> GenericResource::processAllMessages() 491KAsync::Job<void> GenericResource::processAllMessages()
494{ 492{
495 //We have to wait for all items to be processed to ensure the synced items are available when a query gets executed. 493 // We have to wait for all items to be processed to ensure the synced items are available when a query gets executed.
496 //TODO: report errors while processing sync? 494 // TODO: report errors while processing sync?
497 //TODO JOBAPI: A helper that waits for n events and then continues? 495 // TODO JOBAPI: A helper that waits for n events and then continues?
498 return KAsync::start<void>([this](KAsync::Future<void> &f) { 496 return KAsync::start<void>([this](KAsync::Future<void> &f) {
499 if (mCommitQueueTimer.isActive()) { 497 if (mCommitQueueTimer.isActive()) {
500 auto context = new QObject; 498 auto context = new QObject;
501 QObject::connect(&mCommitQueueTimer, &QTimer::timeout, context, [&f, context]() { 499 QObject::connect(&mCommitQueueTimer, &QTimer::timeout, context, [&f, context]() {
502 delete context; 500 delete context;
501 f.setFinished();
502 });
503 } else {
504 f.setFinished();
505 }
506 })
507 .then<void>([this](KAsync::Future<void> &f) { waitForDrained(f, mSynchronizerQueue); })
508 .then<void>([this](KAsync::Future<void> &f) { waitForDrained(f, mUserQueue); })
509 .then<void>([this](KAsync::Future<void> &f) {
510 if (mSourceChangeReplay->allChangesReplayed()) {
503 f.setFinished(); 511 f.setFinished();
504 }); 512 } else {
505 } else { 513 auto context = new QObject;
506 f.setFinished(); 514 QObject::connect(mSourceChangeReplay, &ChangeReplay::changesReplayed, context, [&f, context]() {
507 } 515 delete context;
508 }).then<void>([this](KAsync::Future<void> &f) { 516 f.setFinished();
509 waitForDrained(f, mSynchronizerQueue); 517 });
510 }).then<void>([this](KAsync::Future<void> &f) { 518 }
511 waitForDrained(f, mUserQueue); 519 });
512 }).then<void>([this](KAsync::Future<void> &f) {
513 if (mSourceChangeReplay->allChangesReplayed()) {
514 f.setFinished();
515 } else {
516 auto context = new QObject;
517 QObject::connect(mSourceChangeReplay, &ChangeReplay::changesReplayed, context, [&f, context]() {
518 delete context;
519 f.setFinished();
520 });
521 }
522 });
523} 520}
524 521
525void GenericResource::updateLowerBoundRevision() 522void GenericResource::updateLowerBoundRevision()
@@ -533,14 +530,15 @@ void GenericResource::setLowerBoundRevision(qint64 revision)
533 updateLowerBoundRevision(); 530 updateLowerBoundRevision();
534} 531}
535 532
536void GenericResource::createEntity(const QByteArray &sinkId, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback) 533void GenericResource::createEntity(const QByteArray &sinkId, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject,
534 DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback)
537{ 535{
538 //These changes are coming from the source 536 // These changes are coming from the source
539 const auto replayToSource = false; 537 const auto replayToSource = false;
540 flatbuffers::FlatBufferBuilder entityFbb; 538 flatbuffers::FlatBufferBuilder entityFbb;
541 adaptorFactory.createBuffer(domainObject, entityFbb); 539 adaptorFactory.createBuffer(domainObject, entityFbb);
542 flatbuffers::FlatBufferBuilder fbb; 540 flatbuffers::FlatBufferBuilder fbb;
543 //This is the resource type and not the domain type 541 // This is the resource type and not the domain type
544 auto entityId = fbb.CreateString(sinkId.toStdString()); 542 auto entityId = fbb.CreateString(sinkId.toStdString());
545 auto type = fbb.CreateString(bufferType.toStdString()); 543 auto type = fbb.CreateString(bufferType.toStdString());
546 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); 544 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize());
@@ -549,18 +547,19 @@ void GenericResource::createEntity(const QByteArray &sinkId, const QByteArray &b
549 callback(BufferUtils::extractBuffer(fbb)); 547 callback(BufferUtils::extractBuffer(fbb));
550} 548}
551 549
552void GenericResource::modifyEntity(const QByteArray &sinkId, qint64 revision, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback) 550void GenericResource::modifyEntity(const QByteArray &sinkId, qint64 revision, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject,
551 DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback)
553{ 552{
554 //These changes are coming from the source 553 // These changes are coming from the source
555 const auto replayToSource = false; 554 const auto replayToSource = false;
556 flatbuffers::FlatBufferBuilder entityFbb; 555 flatbuffers::FlatBufferBuilder entityFbb;
557 adaptorFactory.createBuffer(domainObject, entityFbb); 556 adaptorFactory.createBuffer(domainObject, entityFbb);
558 flatbuffers::FlatBufferBuilder fbb; 557 flatbuffers::FlatBufferBuilder fbb;
559 auto entityId = fbb.CreateString(sinkId.toStdString()); 558 auto entityId = fbb.CreateString(sinkId.toStdString());
560 //This is the resource type and not the domain type 559 // This is the resource type and not the domain type
561 auto type = fbb.CreateString(bufferType.toStdString()); 560 auto type = fbb.CreateString(bufferType.toStdString());
562 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); 561 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize());
563 //TODO removals 562 // TODO removals
564 auto location = Sink::Commands::CreateModifyEntity(fbb, revision, entityId, 0, type, delta, replayToSource); 563 auto location = Sink::Commands::CreateModifyEntity(fbb, revision, entityId, 0, type, delta, replayToSource);
565 Sink::Commands::FinishModifyEntityBuffer(fbb, location); 564 Sink::Commands::FinishModifyEntityBuffer(fbb, location);
566 callback(BufferUtils::extractBuffer(fbb)); 565 callback(BufferUtils::extractBuffer(fbb));
@@ -568,11 +567,11 @@ void GenericResource::modifyEntity(const QByteArray &sinkId, qint64 revision, co
568 567
569void GenericResource::deleteEntity(const QByteArray &sinkId, qint64 revision, const QByteArray &bufferType, std::function<void(const QByteArray &)> callback) 568void GenericResource::deleteEntity(const QByteArray &sinkId, qint64 revision, const QByteArray &bufferType, std::function<void(const QByteArray &)> callback)
570{ 569{
571 //These changes are coming from the source 570 // These changes are coming from the source
572 const auto replayToSource = false; 571 const auto replayToSource = false;
573 flatbuffers::FlatBufferBuilder fbb; 572 flatbuffers::FlatBufferBuilder fbb;
574 auto entityId = fbb.CreateString(sinkId.toStdString()); 573 auto entityId = fbb.CreateString(sinkId.toStdString());
575 //This is the resource type and not the domain type 574 // This is the resource type and not the domain type
576 auto type = fbb.CreateString(bufferType.toStdString()); 575 auto type = fbb.CreateString(bufferType.toStdString());
577 auto location = Sink::Commands::CreateDeleteEntity(fbb, revision, entityId, type, replayToSource); 576 auto location = Sink::Commands::CreateDeleteEntity(fbb, revision, entityId, type, replayToSource);
578 Sink::Commands::FinishDeleteEntityBuffer(fbb, location); 577 Sink::Commands::FinishDeleteEntityBuffer(fbb, location);
@@ -581,7 +580,8 @@ void GenericResource::deleteEntity(const QByteArray &sinkId, qint64 revision, co
581 580
582void GenericResource::recordRemoteId(const QByteArray &bufferType, const QByteArray &localId, const QByteArray &remoteId, Sink::Storage::Transaction &transaction) 581void GenericResource::recordRemoteId(const QByteArray &bufferType, const QByteArray &localId, const QByteArray &remoteId, Sink::Storage::Transaction &transaction)
583{ 582{
584 Index("rid.mapping." + bufferType, transaction).add(remoteId, localId);; 583 Index("rid.mapping." + bufferType, transaction).add(remoteId, localId);
584 ;
585 Index("localid.mapping." + bufferType, transaction).add(localId, remoteId); 585 Index("localid.mapping." + bufferType, transaction).add(localId, remoteId);
586} 586}
587 587
@@ -600,7 +600,7 @@ void GenericResource::updateRemoteId(const QByteArray &bufferType, const QByteAr
600 600
601QByteArray GenericResource::resolveRemoteId(const QByteArray &bufferType, const QByteArray &remoteId, Sink::Storage::Transaction &transaction) 601QByteArray GenericResource::resolveRemoteId(const QByteArray &bufferType, const QByteArray &remoteId, Sink::Storage::Transaction &transaction)
602{ 602{
603 //Lookup local id for remote id, or insert a new pair otherwise 603 // Lookup local id for remote id, or insert a new pair otherwise
604 Index index("rid.mapping." + bufferType, transaction); 604 Index index("rid.mapping." + bufferType, transaction);
605 QByteArray sinkId = index.lookup(remoteId); 605 QByteArray sinkId = index.lookup(remoteId);
606 if (sinkId.isEmpty()) { 606 if (sinkId.isEmpty()) {
@@ -621,19 +621,19 @@ QByteArray GenericResource::resolveLocalId(const QByteArray &bufferType, const Q
621 return remoteId; 621 return remoteId;
622} 622}
623 623
624void GenericResource::scanForRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QByteArray &bufferType, const std::function<void(const std::function<void(const QByteArray &key)> &callback)> &entryGenerator, std::function<bool(const QByteArray &remoteId)> exists) 624void GenericResource::scanForRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QByteArray &bufferType,
625 const std::function<void(const std::function<void(const QByteArray &key)> &callback)> &entryGenerator, std::function<bool(const QByteArray &remoteId)> exists)
625{ 626{
626 entryGenerator([this, &transaction, bufferType, &synchronizationTransaction, &exists](const QByteArray &key) { 627 entryGenerator([this, &transaction, bufferType, &synchronizationTransaction, &exists](const QByteArray &key) {
627 auto sinkId = Sink::Storage::uidFromKey(key); 628 auto sinkId = Sink::Storage::uidFromKey(key);
628 Trace() << "Checking for removal " << key; 629 Trace() << "Checking for removal " << key;
629 const auto remoteId = resolveLocalId(bufferType, sinkId, synchronizationTransaction); 630 const auto remoteId = resolveLocalId(bufferType, sinkId, synchronizationTransaction);
630 //If we have no remoteId, the entity hasn't been replayed to the source yet 631 // If we have no remoteId, the entity hasn't been replayed to the source yet
631 if (!remoteId.isEmpty()) { 632 if (!remoteId.isEmpty()) {
632 if (!exists(remoteId)) { 633 if (!exists(remoteId)) {
633 Trace() << "Found a removed entity: " << sinkId; 634 Trace() << "Found a removed entity: " << sinkId;
634 deleteEntity(sinkId, Sink::Storage::maxRevision(transaction), bufferType, [this](const QByteArray &buffer) { 635 deleteEntity(sinkId, Sink::Storage::maxRevision(transaction), bufferType,
635 enqueueCommand(mSynchronizerQueue, Sink::Commands::DeleteEntityCommand, buffer); 636 [this](const QByteArray &buffer) { enqueueCommand(mSynchronizerQueue, Sink::Commands::DeleteEntityCommand, buffer); });
636 });
637 } 637 }
638 } 638 }
639 }); 639 });
@@ -642,32 +642,31 @@ void GenericResource::scanForRemovals(Sink::Storage::Transaction &transaction, S
642static QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> getLatest(const Sink::Storage::NamedDatabase &db, const QByteArray &uid, DomainTypeAdaptorFactoryInterface &adaptorFactory) 642static QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> getLatest(const Sink::Storage::NamedDatabase &db, const QByteArray &uid, DomainTypeAdaptorFactoryInterface &adaptorFactory)
643{ 643{
644 QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> current; 644 QSharedPointer<Sink::ApplicationDomain::BufferAdaptor> current;
645 db.findLatest(uid, [&current, &adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool { 645 db.findLatest(uid,
646 Sink::EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); 646 [&current, &adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool {
647 if (!buffer.isValid()) { 647 Sink::EntityBuffer buffer(const_cast<const char *>(data.data()), data.size());
648 Warning() << "Read invalid buffer from disk"; 648 if (!buffer.isValid()) {
649 } else { 649 Warning() << "Read invalid buffer from disk";
650 current = adaptorFactory.createAdaptor(buffer.entity()); 650 } else {
651 } 651 current = adaptorFactory.createAdaptor(buffer.entity());
652 return false; 652 }
653 }, 653 return false;
654 [](const Sink::Storage::Error &error) { 654 },
655 Warning() << "Failed to read current value from storage: " << error.message; 655 [](const Sink::Storage::Error &error) { Warning() << "Failed to read current value from storage: " << error.message; });
656 });
657 return current; 656 return current;
658} 657}
659 658
660void GenericResource::createOrModify(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, DomainTypeAdaptorFactoryInterface &adaptorFactory, const QByteArray &bufferType, const QByteArray &remoteId, const Sink::ApplicationDomain::ApplicationDomainType &entity) 659void GenericResource::createOrModify(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction,
660 DomainTypeAdaptorFactoryInterface &adaptorFactory, const QByteArray &bufferType, const QByteArray &remoteId, const Sink::ApplicationDomain::ApplicationDomainType &entity)
661{ 661{
662 auto mainDatabase = Storage::mainDatabase(transaction, bufferType); 662 auto mainDatabase = Storage::mainDatabase(transaction, bufferType);
663 const auto sinkId = resolveRemoteId(bufferType, remoteId, synchronizationTransaction); 663 const auto sinkId = resolveRemoteId(bufferType, remoteId, synchronizationTransaction);
664 const auto found = mainDatabase.contains(sinkId); 664 const auto found = mainDatabase.contains(sinkId);
665 if (!found) { 665 if (!found) {
666 Trace() << "Found a new entity: " << remoteId; 666 Trace() << "Found a new entity: " << remoteId;
667 createEntity(sinkId, bufferType, entity, adaptorFactory, [this](const QByteArray &buffer) { 667 createEntity(
668 enqueueCommand(mSynchronizerQueue, Sink::Commands::CreateEntityCommand, buffer); 668 sinkId, bufferType, entity, adaptorFactory, [this](const QByteArray &buffer) { enqueueCommand(mSynchronizerQueue, Sink::Commands::CreateEntityCommand, buffer); });
669 }); 669 } else { // modification
670 } else { //modification
671 if (auto current = getLatest(mainDatabase, sinkId, adaptorFactory)) { 670 if (auto current = getLatest(mainDatabase, sinkId, adaptorFactory)) {
672 bool changed = false; 671 bool changed = false;
673 for (const auto &property : entity.changedProperties()) { 672 for (const auto &property : entity.changedProperties()) {
@@ -678,9 +677,8 @@ void GenericResource::createOrModify(Sink::Storage::Transaction &transaction, Si
678 } 677 }
679 if (changed) { 678 if (changed) {
680 Trace() << "Found a modified entity: " << remoteId; 679 Trace() << "Found a modified entity: " << remoteId;
681 modifyEntity(sinkId, Sink::Storage::maxRevision(transaction), bufferType, entity, adaptorFactory, [this](const QByteArray &buffer) { 680 modifyEntity(sinkId, Sink::Storage::maxRevision(transaction), bufferType, entity, adaptorFactory,
682 enqueueCommand(mSynchronizerQueue, Sink::Commands::ModifyEntityCommand, buffer); 681 [this](const QByteArray &buffer) { enqueueCommand(mSynchronizerQueue, Sink::Commands::ModifyEntityCommand, buffer); });
683 });
684 } 682 }
685 } else { 683 } else {
686 Warning() << "Failed to get current entity"; 684 Warning() << "Failed to get current entity";
diff --git a/common/genericresource.h b/common/genericresource.h
index b9bb994..9665d6b 100644
--- a/common/genericresource.h
+++ b/common/genericresource.h
@@ -29,8 +29,7 @@
29class CommandProcessor; 29class CommandProcessor;
30class ChangeReplay; 30class ChangeReplay;
31 31
32namespace Sink 32namespace Sink {
33{
34class Pipeline; 33class Pipeline;
35class Preprocessor; 34class Preprocessor;
36 35
@@ -48,7 +47,8 @@ public:
48 virtual KAsync::Job<void> synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore); 47 virtual KAsync::Job<void> synchronizeWithSource(Sink::Storage &mainStore, Sink::Storage &synchronizationStore);
49 virtual KAsync::Job<void> processAllMessages() Q_DECL_OVERRIDE; 48 virtual KAsync::Job<void> processAllMessages() Q_DECL_OVERRIDE;
50 virtual void setLowerBoundRevision(qint64 revision) Q_DECL_OVERRIDE; 49 virtual void setLowerBoundRevision(qint64 revision) Q_DECL_OVERRIDE;
51 virtual KAsync::Job<void> inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue); 50 virtual KAsync::Job<void>
51 inspect(int inspectionType, const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue);
52 52
53 int error() const; 53 int error() const;
54 54
@@ -61,13 +61,15 @@ private slots:
61 61
62protected: 62protected:
63 void enableChangeReplay(bool); 63 void enableChangeReplay(bool);
64 void addType(const QByteArray &type, DomainTypeAdaptorFactoryInterface::Ptr factory, const QVector<Sink::Preprocessor*> &preprocessors); 64 void addType(const QByteArray &type, DomainTypeAdaptorFactoryInterface::Ptr factory, const QVector<Sink::Preprocessor *> &preprocessors);
65 virtual KAsync::Job<void> replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value); 65 virtual KAsync::Job<void> replay(Sink::Storage &synchronizationStore, const QByteArray &type, const QByteArray &key, const QByteArray &value);
66 void onProcessorError(int errorCode, const QString &errorMessage); 66 void onProcessorError(int errorCode, const QString &errorMessage);
67 void enqueueCommand(MessageQueue &mq, int commandId, const QByteArray &data); 67 void enqueueCommand(MessageQueue &mq, int commandId, const QByteArray &data);
68 68
69 static void createEntity(const QByteArray &localId, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback); 69 static void createEntity(const QByteArray &localId, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject,
70 static void modifyEntity(const QByteArray &localId, qint64 revision, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject, DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback); 70 DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback);
71 static void modifyEntity(const QByteArray &localId, qint64 revision, const QByteArray &bufferType, const Sink::ApplicationDomain::ApplicationDomainType &domainObject,
72 DomainTypeAdaptorFactoryInterface &adaptorFactory, std::function<void(const QByteArray &)> callback);
71 static void deleteEntity(const QByteArray &localId, qint64 revision, const QByteArray &bufferType, std::function<void(const QByteArray &)> callback); 73 static void deleteEntity(const QByteArray &localId, qint64 revision, const QByteArray &bufferType, std::function<void(const QByteArray &)> callback);
72 74
73 /** 75 /**
@@ -79,36 +81,38 @@ protected:
79 81
80 /** 82 /**
81 * Tries to find a local id for the remote id, and creates a new local id otherwise. 83 * Tries to find a local id for the remote id, and creates a new local id otherwise.
82 * 84 *
83 * The new local id is recorded in the local to remote id mapping. 85 * The new local id is recorded in the local to remote id mapping.
84 */ 86 */
85 QByteArray resolveRemoteId(const QByteArray &type, const QByteArray &remoteId, Sink::Storage::Transaction &transaction); 87 QByteArray resolveRemoteId(const QByteArray &type, const QByteArray &remoteId, Sink::Storage::Transaction &transaction);
86 88
87 /** 89 /**
88 * Tries to find a remote id for a local id. 90 * Tries to find a remote id for a local id.
89 * 91 *
90 * This can fail if the entity hasn't been written back to the server yet. 92 * This can fail if the entity hasn't been written back to the server yet.
91 */ 93 */
92 QByteArray resolveLocalId(const QByteArray &bufferType, const QByteArray &localId, Sink::Storage::Transaction &transaction); 94 QByteArray resolveLocalId(const QByteArray &bufferType, const QByteArray &localId, Sink::Storage::Transaction &transaction);
93 95
94 /** 96 /**
95 * A synchronous algorithm to remove entities that are no longer existing. 97 * A synchronous algorithm to remove entities that are no longer existing.
96 * 98 *
97 * A list of entities is generated by @param entryGenerator. 99 * A list of entities is generated by @param entryGenerator.
98 * The entiry Generator typically iterates over an index to produce all existing entries. 100 * The entiry Generator typically iterates over an index to produce all existing entries.
99 * This algorithm calls @param exists for every entity of type @param type, with its remoteId. For every entity where @param exists returns false, 101 * This algorithm calls @param exists for every entity of type @param type, with its remoteId. For every entity where @param exists returns false,
100 * an entity delete command is enqueued. 102 * an entity delete command is enqueued.
101 * 103 *
102 * All functions are called synchronously, and both @param entryGenerator and @param exists need to be synchronous. 104 * All functions are called synchronously, and both @param entryGenerator and @param exists need to be synchronous.
103 */ 105 */
104 void scanForRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QByteArray &bufferType, const std::function<void(const std::function<void(const QByteArray &key)> &callback)> &entryGenerator, std::function<bool(const QByteArray &remoteId)> exists); 106 void scanForRemovals(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, const QByteArray &bufferType,
107 const std::function<void(const std::function<void(const QByteArray &key)> &callback)> &entryGenerator, std::function<bool(const QByteArray &remoteId)> exists);
105 108
106 /** 109 /**
107 * An algorithm to create or modify the entity. 110 * An algorithm to create or modify the entity.
108 * 111 *
109 * Depending on whether the entity is locally available, or has changed. 112 * Depending on whether the entity is locally available, or has changed.
110 */ 113 */
111 void createOrModify(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, DomainTypeAdaptorFactoryInterface &adaptorFactory, const QByteArray &bufferType, const QByteArray &remoteId, const Sink::ApplicationDomain::ApplicationDomainType &entity); 114 void createOrModify(Sink::Storage::Transaction &transaction, Sink::Storage::Transaction &synchronizationTransaction, DomainTypeAdaptorFactoryInterface &adaptorFactory,
115 const QByteArray &bufferType, const QByteArray &remoteId, const Sink::ApplicationDomain::ApplicationDomainType &entity);
112 116
113 MessageQueue mUserQueue; 117 MessageQueue mUserQueue;
114 MessageQueue mSynchronizerQueue; 118 MessageQueue mSynchronizerQueue;
@@ -122,5 +126,4 @@ private:
122 QTimer mCommitQueueTimer; 126 QTimer mCommitQueueTimer;
123 qint64 mClientLowerBoundRevision; 127 qint64 mClientLowerBoundRevision;
124}; 128};
125
126} 129}
diff --git a/common/index.cpp b/common/index.cpp
index e35b838..b5e9980 100644
--- a/common/index.cpp
+++ b/common/index.cpp
@@ -7,17 +7,14 @@
7 7
8Index::Index(const QString &storageRoot, const QString &name, Sink::Storage::AccessMode mode) 8Index::Index(const QString &storageRoot, const QString &name, Sink::Storage::AccessMode mode)
9 : mTransaction(Sink::Storage(storageRoot, name, mode).createTransaction(mode)), 9 : mTransaction(Sink::Storage(storageRoot, name, mode).createTransaction(mode)),
10 mDb(mTransaction.openDatabase(name.toLatin1(), std::function<void(const Sink::Storage::Error &)>(), true)), 10 mDb(mTransaction.openDatabase(name.toLatin1(), std::function<void(const Sink::Storage::Error &)>(), true)),
11 mName(name) 11 mName(name)
12{ 12{
13
14} 13}
15 14
16Index::Index(const QByteArray &name, Sink::Storage::Transaction &transaction) 15Index::Index(const QByteArray &name, Sink::Storage::Transaction &transaction)
17 : mDb(transaction.openDatabase(name, std::function<void(const Sink::Storage::Error &)>(), true)), 16 : mDb(transaction.openDatabase(name, std::function<void(const Sink::Storage::Error &)>(), true)), mName(name)
18 mName(name)
19{ 17{
20
21} 18}
22 19
23void Index::add(const QByteArray &key, const QByteArray &value) 20void Index::add(const QByteArray &key, const QByteArray &value)
@@ -30,30 +27,23 @@ void Index::remove(const QByteArray &key, const QByteArray &value)
30 mDb.remove(key, value); 27 mDb.remove(key, value);
31} 28}
32 29
33void Index::lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler, 30void Index::lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler, const std::function<void(const Error &error)> &errorHandler, bool matchSubStringKeys)
34 const std::function<void(const Error &error)> &errorHandler, bool matchSubStringKeys)
35{ 31{
36 mDb.scan(key, [this, resultHandler](const QByteArray &key, const QByteArray &value) -> bool { 32 mDb.scan(key,
37 resultHandler(value); 33 [this, resultHandler](const QByteArray &key, const QByteArray &value) -> bool {
38 return true; 34 resultHandler(value);
39 }, 35 return true;
40 [errorHandler](const Sink::Storage::Error &error) { 36 },
41 Warning() << "Error while retrieving value" << error.message; 37 [errorHandler](const Sink::Storage::Error &error) {
42 errorHandler(Error(error.store, error.code, error.message)); 38 Warning() << "Error while retrieving value" << error.message;
43 }, 39 errorHandler(Error(error.store, error.code, error.message));
44 matchSubStringKeys); 40 },
41 matchSubStringKeys);
45} 42}
46 43
47QByteArray Index::lookup(const QByteArray &key) 44QByteArray Index::lookup(const QByteArray &key)
48{ 45{
49 QByteArray result; 46 QByteArray result;
50 lookup(key, 47 lookup(key, [&result](const QByteArray &value) { result = value; }, [this](const Index::Error &error) { Trace() << "Error while retrieving value" << error.message; });
51 [&result](const QByteArray &value) {
52 result = value;
53 },
54 [this](const Index::Error &error) {
55 Trace() << "Error while retrieving value" << error.message;
56 });
57 return result; 48 return result;
58} 49}
59
diff --git a/common/index.h b/common/index.h
index 3ee322a..0345f56 100644
--- a/common/index.h
+++ b/common/index.h
@@ -12,15 +12,17 @@
12class SINK_EXPORT Index 12class SINK_EXPORT Index
13{ 13{
14public: 14public:
15 enum ErrorCodes { 15 enum ErrorCodes
16 {
16 IndexNotAvailable = -1 17 IndexNotAvailable = -1
17 }; 18 };
18 19
19 class Error 20 class Error
20 { 21 {
21 public: 22 public:
22 Error(const QByteArray &s, int c, const QByteArray &m) 23 Error(const QByteArray &s, int c, const QByteArray &m) : store(s), message(m), code(c)
23 : store(s), message(m), code(c) {} 24 {
25 }
24 QByteArray store; 26 QByteArray store;
25 QByteArray message; 27 QByteArray message;
26 int code; 28 int code;
@@ -32,8 +34,8 @@ public:
32 void add(const QByteArray &key, const QByteArray &value); 34 void add(const QByteArray &key, const QByteArray &value);
33 void remove(const QByteArray &key, const QByteArray &value); 35 void remove(const QByteArray &key, const QByteArray &value);
34 36
35 void lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler, 37 void lookup(const QByteArray &key, const std::function<void(const QByteArray &value)> &resultHandler, const std::function<void(const Error &error)> &errorHandler,
36 const std::function<void(const Error &error)> &errorHandler, bool matchSubStringKeys = false); 38 bool matchSubStringKeys = false);
37 QByteArray lookup(const QByteArray &key); 39 QByteArray lookup(const QByteArray &key);
38 40
39private: 41private:
diff --git a/common/indexupdater.h b/common/indexupdater.h
index ced220b..deaaa16 100644
--- a/common/indexupdater.h
+++ b/common/indexupdater.h
@@ -21,14 +21,11 @@
21#include <pipeline.h> 21#include <pipeline.h>
22#include <index.h> 22#include <index.h>
23 23
24class IndexUpdater : public Sink::Preprocessor { 24class IndexUpdater : public Sink::Preprocessor
25{
25public: 26public:
26 IndexUpdater(const QByteArray &index, const QByteArray &type, const QByteArray &property) 27 IndexUpdater(const QByteArray &index, const QByteArray &type, const QByteArray &property) : mIndexIdentifier(index), mBufferType(type), mProperty(property)
27 :mIndexIdentifier(index),
28 mBufferType(type),
29 mProperty(property)
30 { 28 {
31
32 } 29 }
33 30
34 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 31 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
@@ -36,7 +33,8 @@ public:
36 add(newEntity.getProperty(mProperty), uid, transaction); 33 add(newEntity.getProperty(mProperty), uid, transaction);
37 } 34 }
38 35
39 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 36 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity,
37 Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
40 { 38 {
41 remove(oldEntity.getProperty(mProperty), uid, transaction); 39 remove(oldEntity.getProperty(mProperty), uid, transaction);
42 add(newEntity.getProperty(mProperty), uid, transaction); 40 add(newEntity.getProperty(mProperty), uid, transaction);
@@ -57,7 +55,7 @@ private:
57 55
58 void remove(const QVariant &value, const QByteArray &uid, Sink::Storage::Transaction &transaction) 56 void remove(const QVariant &value, const QByteArray &uid, Sink::Storage::Transaction &transaction)
59 { 57 {
60 //TODO hide notfound error 58 // TODO hide notfound error
61 Index(mIndexIdentifier, transaction).remove(value.toByteArray(), uid); 59 Index(mIndexIdentifier, transaction).remove(value.toByteArray(), uid);
62 } 60 }
63 61
@@ -66,15 +64,17 @@ private:
66 QByteArray mProperty; 64 QByteArray mProperty;
67}; 65};
68 66
69template<typename DomainType> 67template <typename DomainType>
70class DefaultIndexUpdater : public Sink::Preprocessor { 68class DefaultIndexUpdater : public Sink::Preprocessor
69{
71public: 70public:
72 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 71 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
73 { 72 {
74 Sink::ApplicationDomain::TypeImplementation<DomainType>::index(uid, newEntity, transaction); 73 Sink::ApplicationDomain::TypeImplementation<DomainType>::index(uid, newEntity, transaction);
75 } 74 }
76 75
77 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 76 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity,
77 Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
78 { 78 {
79 Sink::ApplicationDomain::TypeImplementation<DomainType>::removeIndex(uid, oldEntity, transaction); 79 Sink::ApplicationDomain::TypeImplementation<DomainType>::removeIndex(uid, oldEntity, transaction);
80 Sink::ApplicationDomain::TypeImplementation<DomainType>::index(uid, newEntity, transaction); 80 Sink::ApplicationDomain::TypeImplementation<DomainType>::index(uid, newEntity, transaction);
diff --git a/common/inspection.h b/common/inspection.h
index d85eab6..7abcd1c 100644
--- a/common/inspection.h
+++ b/common/inspection.h
@@ -24,9 +24,10 @@
24#include "applicationdomaintype.h" 24#include "applicationdomaintype.h"
25 25
26namespace Sink { 26namespace Sink {
27 namespace ResourceControl { 27namespace ResourceControl {
28 28
29struct Inspection { 29struct Inspection
30{
30 static Inspection PropertyInspection(const Sink::ApplicationDomain::Entity &entity, const QByteArray &property, const QVariant &expectedValue) 31 static Inspection PropertyInspection(const Sink::ApplicationDomain::Entity &entity, const QByteArray &property, const QVariant &expectedValue)
31 { 32 {
32 Inspection inspection; 33 Inspection inspection;
@@ -46,7 +47,8 @@ struct Inspection {
46 return inspection; 47 return inspection;
47 } 48 }
48 49
49 enum Type { 50 enum Type
51 {
50 PropertyInspectionType, 52 PropertyInspectionType,
51 ExistenceInspectionType 53 ExistenceInspectionType
52 }; 54 };
@@ -55,6 +57,5 @@ struct Inspection {
55 QByteArray property; 57 QByteArray property;
56 QVariant expectedValue; 58 QVariant expectedValue;
57}; 59};
58 60}
59 }
60} 61}
diff --git a/common/listener.cpp b/common/listener.cpp
index ed6f305..145267a 100644
--- a/common/listener.cpp
+++ b/common/listener.cpp
@@ -51,8 +51,7 @@ Listener::Listener(const QByteArray &resourceInstanceIdentifier, QObject *parent
51 m_clientBufferProcessesTimer(new QTimer(this)), 51 m_clientBufferProcessesTimer(new QTimer(this)),
52 m_messageId(0) 52 m_messageId(0)
53{ 53{
54 connect(m_server, &QLocalServer::newConnection, 54 connect(m_server, &QLocalServer::newConnection, this, &Listener::acceptConnection);
55 this, &Listener::acceptConnection);
56 Trace() << "Trying to open " << m_resourceInstanceIdentifier; 55 Trace() << "Trying to open " << m_resourceInstanceIdentifier;
57 56
58 if (!m_server->listen(QString::fromLatin1(m_resourceInstanceIdentifier))) { 57 if (!m_server->listen(QString::fromLatin1(m_resourceInstanceIdentifier))) {
@@ -77,12 +76,11 @@ Listener::Listener(const QByteArray &resourceInstanceIdentifier, QObject *parent
77 } 76 }
78 }); 77 });
79 78
80 //TODO: experiment with different timeouts 79 // TODO: experiment with different timeouts
81 // or even just drop down to invoking the method queued? => invoke queued unless we need throttling 80 // or even just drop down to invoking the method queued? => invoke queued unless we need throttling
82 m_clientBufferProcessesTimer->setInterval(0); 81 m_clientBufferProcessesTimer->setInterval(0);
83 m_clientBufferProcessesTimer->setSingleShot(true); 82 m_clientBufferProcessesTimer->setSingleShot(true);
84 connect(m_clientBufferProcessesTimer, &QTimer::timeout, 83 connect(m_clientBufferProcessesTimer, &QTimer::timeout, this, &Listener::processClientBuffers);
85 this, &Listener::processClientBuffers);
86} 84}
87 85
88Listener::~Listener() 86Listener::~Listener()
@@ -91,7 +89,7 @@ Listener::~Listener()
91 89
92void Listener::closeAllConnections() 90void Listener::closeAllConnections()
93{ 91{
94 for (Client &client: m_connections) { 92 for (Client &client : m_connections) {
95 if (client.socket) { 93 if (client.socket) {
96 disconnect(client.socket, 0, this, 0); 94 disconnect(client.socket, 0, this, 0);
97 client.socket->close(); 95 client.socket->close();
@@ -114,13 +112,11 @@ void Listener::acceptConnection()
114 } 112 }
115 113
116 m_connections << Client("Unknown Client", socket); 114 m_connections << Client("Unknown Client", socket);
117 connect(socket, &QIODevice::readyRead, 115 connect(socket, &QIODevice::readyRead, this, &Listener::onDataAvailable);
118 this, &Listener::onDataAvailable); 116 connect(socket, &QLocalSocket::disconnected, this, &Listener::clientDropped);
119 connect(socket, &QLocalSocket::disconnected,
120 this, &Listener::clientDropped);
121 m_checkConnectionsTimer->stop(); 117 m_checkConnectionsTimer->stop();
122 118
123 //If this is the first client, set the lower limit for revision cleanup 119 // If this is the first client, set the lower limit for revision cleanup
124 if (m_connections.size() == 1) { 120 if (m_connections.size() == 1) {
125 loadResource()->setLowerBoundRevision(0); 121 loadResource()->setLowerBoundRevision(0);
126 } 122 }
@@ -157,7 +153,7 @@ void Listener::clientDropped()
157 153
158void Listener::checkConnections() 154void Listener::checkConnections()
159{ 155{
160 //If this was the last client, disengage the lower limit for revision cleanup 156 // If this was the last client, disengage the lower limit for revision cleanup
161 if (m_connections.isEmpty()) { 157 if (m_connections.isEmpty()) {
162 loadResource()->setLowerBoundRevision(std::numeric_limits<qint64>::max()); 158 loadResource()->setLowerBoundRevision(std::numeric_limits<qint64>::max());
163 } 159 }
@@ -176,7 +172,7 @@ void Listener::onDataAvailable()
176void Listener::readFromSocket(QLocalSocket *socket) 172void Listener::readFromSocket(QLocalSocket *socket)
177{ 173{
178 Trace() << "Reading from socket..."; 174 Trace() << "Reading from socket...";
179 for (Client &client: m_connections) { 175 for (Client &client : m_connections) {
180 if (client.socket == socket) { 176 if (client.socket == socket) {
181 client.commandBuffer += socket->readAll(); 177 client.commandBuffer += socket->readAll();
182 if (!m_clientBufferProcessesTimer->isActive()) { 178 if (!m_clientBufferProcessesTimer->isActive()) {
@@ -189,11 +185,11 @@ void Listener::readFromSocket(QLocalSocket *socket)
189 185
190void Listener::processClientBuffers() 186void Listener::processClientBuffers()
191{ 187{
192 //TODO: we should not process all clients, but iterate async over them and process 188 // TODO: we should not process all clients, but iterate async over them and process
193 // one command from each in turn to ensure all clients get fair handling of 189 // one command from each in turn to ensure all clients get fair handling of
194 // commands? 190 // commands?
195 bool again = false; 191 bool again = false;
196 for (Client &client: m_connections) { 192 for (Client &client : m_connections) {
197 if (!client.socket || !client.socket->isValid() || client.commandBuffer.isEmpty()) { 193 if (!client.socket || !client.socket->isValid() || client.commandBuffer.isEmpty()) {
198 continue; 194 continue;
199 } 195 }
@@ -237,9 +233,10 @@ void Listener::processCommand(int commandId, uint messageId, const QByteArray &c
237 job = job.then<void>(loadResource()->processAllMessages()); 233 job = job.then<void>(loadResource()->processAllMessages());
238 } 234 }
239 job.then<void>([callback, timer]() { 235 job.then<void>([callback, timer]() {
240 Trace() << "Sync took " << Sink::Log::TraceTime(timer->elapsed()); 236 Trace() << "Sync took " << Sink::Log::TraceTime(timer->elapsed());
241 callback(true); 237 callback(true);
242 }).exec(); 238 })
239 .exec();
243 return; 240 return;
244 } else { 241 } else {
245 Warning() << "received invalid command"; 242 Warning() << "received invalid command";
@@ -256,7 +253,7 @@ void Listener::processCommand(int commandId, uint messageId, const QByteArray &c
256 break; 253 break;
257 case Sink::Commands::ShutdownCommand: 254 case Sink::Commands::ShutdownCommand:
258 Log() << QString("\tReceived shutdown command from %1").arg(client.name); 255 Log() << QString("\tReceived shutdown command from %1").arg(client.name);
259 //Immediately reject new connections 256 // Immediately reject new connections
260 m_server->close(); 257 m_server->close();
261 QTimer::singleShot(0, this, &Listener::quit); 258 QTimer::singleShot(0, this, &Listener::quit);
262 break; 259 break;
@@ -273,16 +270,14 @@ void Listener::processCommand(int commandId, uint messageId, const QByteArray &c
273 Warning() << "received invalid command"; 270 Warning() << "received invalid command";
274 } 271 }
275 loadResource()->setLowerBoundRevision(lowerBoundRevision()); 272 loadResource()->setLowerBoundRevision(lowerBoundRevision());
276 } 273 } break;
277 break;
278 case Sink::Commands::RemoveFromDiskCommand: { 274 case Sink::Commands::RemoveFromDiskCommand: {
279 Log() << QString("\tReceived a remove from disk command from %1").arg(client.name); 275 Log() << QString("\tReceived a remove from disk command from %1").arg(client.name);
280 m_resource->removeDataFromDisk(); 276 m_resource->removeDataFromDisk();
281 delete m_resource; 277 delete m_resource;
282 m_resource = nullptr; 278 m_resource = nullptr;
283 loadResource()->setLowerBoundRevision(0); 279 loadResource()->setLowerBoundRevision(0);
284 } 280 } break;
285 break;
286 default: 281 default:
287 if (commandId > Sink::Commands::CustomCommand) { 282 if (commandId > Sink::Commands::CustomCommand) {
288 Log() << QString("\tReceived custom command from %1: ").arg(client.name) << commandId; 283 Log() << QString("\tReceived custom command from %1: ").arg(client.name) << commandId;
@@ -313,7 +308,7 @@ qint64 Listener::lowerBoundRevision()
313 308
314void Listener::quit() 309void Listener::quit()
315{ 310{
316 //Broadcast shutdown notifications to open clients, so they don't try to restart the resource 311 // Broadcast shutdown notifications to open clients, so they don't try to restart the resource
317 auto command = Sink::Commands::CreateNotification(m_fbb, Sink::Commands::NotificationType::NotificationType_Shutdown); 312 auto command = Sink::Commands::CreateNotification(m_fbb, Sink::Commands::NotificationType::NotificationType_Shutdown);
318 Sink::Commands::FinishNotificationBuffer(m_fbb, command); 313 Sink::Commands::FinishNotificationBuffer(m_fbb, command);
319 for (Client &client : m_connections) { 314 for (Client &client : m_connections) {
@@ -323,7 +318,7 @@ void Listener::quit()
323 } 318 }
324 m_fbb.Clear(); 319 m_fbb.Clear();
325 320
326 //Connections will be cleaned up later 321 // Connections will be cleaned up later
327 emit noClients(); 322 emit noClients();
328} 323}
329 324
@@ -334,12 +329,12 @@ bool Listener::processClientBuffer(Client &client)
334 return false; 329 return false;
335 } 330 }
336 331
337 const uint messageId = *(uint*)client.commandBuffer.constData(); 332 const uint messageId = *(uint *)client.commandBuffer.constData();
338 const int commandId = *(int*)(client.commandBuffer.constData() + sizeof(uint)); 333 const int commandId = *(int *)(client.commandBuffer.constData() + sizeof(uint));
339 const uint size = *(uint*)(client.commandBuffer.constData() + sizeof(int) + sizeof(uint)); 334 const uint size = *(uint *)(client.commandBuffer.constData() + sizeof(int) + sizeof(uint));
340 Trace() << "Received message. Id:" << messageId << " CommandId: " << commandId << " Size: " << size; 335 Trace() << "Received message. Id:" << messageId << " CommandId: " << commandId << " Size: " << size;
341 336
342 //TODO: reject messages above a certain size? 337 // TODO: reject messages above a certain size?
343 338
344 const bool commandComplete = size <= uint(client.commandBuffer.size() - headerSize); 339 const bool commandComplete = size <= uint(client.commandBuffer.size() - headerSize);
345 if (commandComplete) { 340 if (commandComplete) {
@@ -386,7 +381,7 @@ void Listener::updateClientsWithRevision(qint64 revision)
386 auto command = Sink::Commands::CreateRevisionUpdate(m_fbb, revision); 381 auto command = Sink::Commands::CreateRevisionUpdate(m_fbb, revision);
387 Sink::Commands::FinishRevisionUpdateBuffer(m_fbb, command); 382 Sink::Commands::FinishRevisionUpdateBuffer(m_fbb, command);
388 383
389 for (const Client &client: m_connections) { 384 for (const Client &client : m_connections) {
390 if (!client.socket || !client.socket->isValid()) { 385 if (!client.socket || !client.socket->isValid()) {
391 continue; 386 continue;
392 } 387 }
@@ -423,10 +418,8 @@ Sink::Resource *Listener::loadResource()
423 m_resource = resourceFactory->createResource(m_resourceInstanceIdentifier); 418 m_resource = resourceFactory->createResource(m_resourceInstanceIdentifier);
424 Trace() << QString("Resource factory: %1").arg((qlonglong)resourceFactory); 419 Trace() << QString("Resource factory: %1").arg((qlonglong)resourceFactory);
425 Trace() << QString("\tResource: %1").arg((qlonglong)m_resource); 420 Trace() << QString("\tResource: %1").arg((qlonglong)m_resource);
426 connect(m_resource, &Sink::Resource::revisionUpdated, 421 connect(m_resource, &Sink::Resource::revisionUpdated, this, &Listener::refreshRevision);
427 this, &Listener::refreshRevision); 422 connect(m_resource, &Sink::Resource::notify, this, &Listener::notify);
428 connect(m_resource, &Sink::Resource::notify,
429 this, &Listener::notify);
430 } else { 423 } else {
431 ErrorMsg() << "Failed to load resource " << m_resourceName; 424 ErrorMsg() << "Failed to load resource " << m_resourceName;
432 m_resource = new Sink::Resource; 425 m_resource = new Sink::Resource;
diff --git a/common/listener.h b/common/listener.h
index 49ded1a..aca7c50 100644
--- a/common/listener.h
+++ b/common/listener.h
@@ -26,10 +26,9 @@
26#include <QLocalSocket> 26#include <QLocalSocket>
27#include <flatbuffers/flatbuffers.h> 27#include <flatbuffers/flatbuffers.h>
28 28
29namespace Sink 29namespace Sink {
30{ 30class Resource;
31 class Resource; 31class Notification;
32 class Notification;
33} 32}
34 33
35class QTimer; 34class QTimer;
@@ -38,16 +37,11 @@ class QLocalServer;
38class Client 37class Client
39{ 38{
40public: 39public:
41 Client() 40 Client() : socket(nullptr), currentRevision(0)
42 : socket(nullptr),
43 currentRevision(0)
44 { 41 {
45 } 42 }
46 43
47 Client(const QString &n, QLocalSocket *s) 44 Client(const QString &n, QLocalSocket *s) : name(n), socket(s), currentRevision(0)
48 : name(n),
49 socket(s),
50 currentRevision(0)
51 { 45 {
52 } 46 }
53 47
diff --git a/common/log.cpp b/common/log.cpp
index 96c6f82..b0f6237 100644
--- a/common/log.cpp
+++ b/common/log.cpp
@@ -16,67 +16,88 @@ static QSharedPointer<QSettings> config()
16 return QSharedPointer<QSettings>::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/log.ini", QSettings::IniFormat); 16 return QSharedPointer<QSettings>::create(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/sink/log.ini", QSettings::IniFormat);
17} 17}
18 18
19class DebugStream: public QIODevice 19class DebugStream : public QIODevice
20{ 20{
21public: 21public:
22 QString m_location; 22 QString m_location;
23 DebugStream() 23 DebugStream() : QIODevice()
24 : QIODevice()
25 { 24 {
26 open(WriteOnly); 25 open(WriteOnly);
27 } 26 }
28 virtual ~DebugStream(); 27 virtual ~DebugStream();
29 28
30 bool isSequential() const { return true; } 29 bool isSequential() const
31 qint64 readData(char *, qint64) { return 0; /* eof */ } 30 {
32 qint64 readLineData(char *, qint64) { return 0; /* eof */ } 31 return true;
32 }
33 qint64 readData(char *, qint64)
34 {
35 return 0; /* eof */
36 }
37 qint64 readLineData(char *, qint64)
38 {
39 return 0; /* eof */
40 }
33 qint64 writeData(const char *data, qint64 len) 41 qint64 writeData(const char *data, qint64 len)
34 { 42 {
35 std::cout << data << std::endl; 43 std::cout << data << std::endl;
36 return len; 44 return len;
37 } 45 }
46
38private: 47private:
39 Q_DISABLE_COPY(DebugStream) 48 Q_DISABLE_COPY(DebugStream)
40}; 49};
41 50
42//Virtual method anchor 51// Virtual method anchor
43DebugStream::~DebugStream() 52DebugStream::~DebugStream()
44{} 53{
54}
45 55
46class NullStream: public QIODevice 56class NullStream : public QIODevice
47{ 57{
48public: 58public:
49 NullStream() 59 NullStream() : QIODevice()
50 : QIODevice()
51 { 60 {
52 open(WriteOnly); 61 open(WriteOnly);
53 } 62 }
54 virtual ~NullStream(); 63 virtual ~NullStream();
55 64
56 bool isSequential() const { return true; } 65 bool isSequential() const
57 qint64 readData(char *, qint64) { return 0; /* eof */ } 66 {
58 qint64 readLineData(char *, qint64) { return 0; /* eof */ } 67 return true;
68 }
69 qint64 readData(char *, qint64)
70 {
71 return 0; /* eof */
72 }
73 qint64 readLineData(char *, qint64)
74 {
75 return 0; /* eof */
76 }
59 qint64 writeData(const char *data, qint64 len) 77 qint64 writeData(const char *data, qint64 len)
60 { 78 {
61 return len; 79 return len;
62 } 80 }
81
63private: 82private:
64 Q_DISABLE_COPY(NullStream) 83 Q_DISABLE_COPY(NullStream)
65}; 84};
66 85
67//Virtual method anchor 86// Virtual method anchor
68NullStream::~NullStream() 87NullStream::~NullStream()
69{} 88{
70 89}
71 /* 90
72 * ANSI color codes: 91/*
73 * 0: reset colors/style 92 * ANSI color codes:
74 * 1: bold 93 * 0: reset colors/style
75 * 4: underline 94 * 1: bold
76 * 30 - 37: black, red, green, yellow, blue, magenta, cyan, and white text 95 * 4: underline
77 * 40 - 47: black, red, green, yellow, blue, magenta, cyan, and white background 96 * 30 - 37: black, red, green, yellow, blue, magenta, cyan, and white text
78 */ 97 * 40 - 47: black, red, green, yellow, blue, magenta, cyan, and white background
79enum ANSI_Colors { 98 */
99enum ANSI_Colors
100{
80 DoNothing = -1, 101 DoNothing = -1,
81 Reset = 0, 102 Reset = 0,
82 Bold = 1, 103 Bold = 1,
@@ -211,7 +232,7 @@ static bool caseInsensitiveContains(const QByteArray &pattern, const QByteArrayL
211 return false; 232 return false;
212} 233}
213 234
214QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char* file, const char* function, const char* debugArea) 235QDebug Sink::Log::debugStream(DebugLevel debugLevel, int line, const char *file, const char *function, const char *debugArea)
215{ 236{
216 static NullStream nullstream; 237 static NullStream nullstream;
217 if (debugLevel < debugOutputLevel()) { 238 if (debugLevel < debugOutputLevel()) {
diff --git a/common/log.h b/common/log.h
index 415c7f7..0e92ea9 100644
--- a/common/log.h
+++ b/common/log.h
@@ -6,7 +6,8 @@
6namespace Sink { 6namespace Sink {
7namespace Log { 7namespace Log {
8 8
9enum DebugLevel { 9enum DebugLevel
10{
10 Trace, 11 Trace,
11 Log, 12 Log,
12 Warning, 13 Warning,
@@ -24,14 +25,15 @@ DebugLevel SINK_EXPORT debugLevelFromName(const QByteArray &name);
24void SINK_EXPORT setDebugOutputLevel(DebugLevel); 25void SINK_EXPORT setDebugOutputLevel(DebugLevel);
25DebugLevel SINK_EXPORT debugOutputLevel(); 26DebugLevel SINK_EXPORT debugOutputLevel();
26 27
27enum FilterType { 28enum FilterType
29{
28 Area, 30 Area,
29 ApplicationName 31 ApplicationName
30}; 32};
31 33
32/** 34/**
33 * Sets a debug output filter. 35 * Sets a debug output filter.
34 * 36 *
35 * Everything that is not matching the filter is ignored. 37 * Everything that is not matching the filter is ignored.
36 * An empty filter matches everything. 38 * An empty filter matches everything.
37 * 39 *
@@ -53,7 +55,7 @@ QByteArrayList SINK_EXPORT debugOutputFilter(FilterType type);
53void SINK_EXPORT setDebugOutputFields(const QByteArrayList &filter); 55void SINK_EXPORT setDebugOutputFields(const QByteArrayList &filter);
54QByteArrayList SINK_EXPORT debugOutputFields(); 56QByteArrayList SINK_EXPORT debugOutputFields();
55 57
56QDebug SINK_EXPORT debugStream(DebugLevel debugLevel, int line, const char* file, const char* function, const char* debugArea = 0); 58QDebug SINK_EXPORT debugStream(DebugLevel debugLevel, int line, const char *file, const char *function, const char *debugArea = 0);
57 59
58struct SINK_EXPORT TraceTime 60struct SINK_EXPORT TraceTime
59{ 61{
@@ -66,7 +68,6 @@ inline QDebug SINK_EXPORT operator<<(QDebug d, const TraceTime &time)
66 d << time.time << "[ms]"; 68 d << time.time << "[ms]";
67 return d; 69 return d;
68} 70}
69
70} 71}
71} 72}
72 73
@@ -83,5 +84,5 @@ inline QDebug SINK_EXPORT operator<<(QDebug d, const TraceTime &time)
83#define Trace() Sink::Log::debugStream(Sink::Log::DebugLevel::Trace, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA) 84#define Trace() Sink::Log::debugStream(Sink::Log::DebugLevel::Trace, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA)
84#define Log() Sink::Log::debugStream(Sink::Log::DebugLevel::Log, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA) 85#define Log() Sink::Log::debugStream(Sink::Log::DebugLevel::Log, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA)
85#define Warning() Sink::Log::debugStream(Sink::Log::DebugLevel::Warning, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA) 86#define Warning() Sink::Log::debugStream(Sink::Log::DebugLevel::Warning, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA)
86//FIXME Error clashes with Storage::Error and MessageQueue::Error 87// FIXME Error clashes with Storage::Error and MessageQueue::Error
87#define ErrorMsg() Sink::Log::debugStream(Sink::Log::DebugLevel::Error, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA) 88#define ErrorMsg() Sink::Log::debugStream(Sink::Log::DebugLevel::Error, __LINE__, __FILE__, Q_FUNC_INFO, DEBUG_AREA)
diff --git a/common/messagequeue.cpp b/common/messagequeue.cpp
index 73198a5..fd86635 100644
--- a/common/messagequeue.cpp
+++ b/common/messagequeue.cpp
@@ -3,41 +3,38 @@
3#include <QDebug> 3#include <QDebug>
4#include <log.h> 4#include <log.h>
5 5
6static KAsync::Job<void> waitForCompletion(QList<KAsync::Future<void> > &futures) 6static KAsync::Job<void> waitForCompletion(QList<KAsync::Future<void>> &futures)
7{ 7{
8 auto context = new QObject; 8 auto context = new QObject;
9 return KAsync::start<void>([futures, context](KAsync::Future<void> &future) { 9 return KAsync::start<void>([futures, context](KAsync::Future<void> &future) {
10 const auto total = futures.size(); 10 const auto total = futures.size();
11 auto count = QSharedPointer<int>::create(); 11 auto count = QSharedPointer<int>::create();
12 int i = 0; 12 int i = 0;
13 for (KAsync::Future<void> subFuture : futures) { 13 for (KAsync::Future<void> subFuture : futures) {
14 i++; 14 i++;
15 if (subFuture.isFinished()) { 15 if (subFuture.isFinished()) {
16 *count += 1; 16 *count += 1;
17 continue; 17 continue;
18 } 18 }
19 //FIXME bind lifetime all watcher to future (repectively the main job 19 // FIXME bind lifetime all watcher to future (repectively the main job
20 auto watcher = QSharedPointer<KAsync::FutureWatcher<void> >::create(); 20 auto watcher = QSharedPointer<KAsync::FutureWatcher<void>>::create();
21 QObject::connect(watcher.data(), &KAsync::FutureWatcher<void>::futureReady, 21 QObject::connect(watcher.data(), &KAsync::FutureWatcher<void>::futureReady, [count, total, &future]() {
22 [count, total, &future](){ 22 *count += 1;
23 *count += 1; 23 if (*count == total) {
24 if (*count == total) { 24 future.setFinished();
25 future.setFinished(); 25 }
26 } 26 });
27 }); 27 watcher->setFuture(subFuture);
28 watcher->setFuture(subFuture); 28 context->setProperty(QString("future%1").arg(i).toLatin1().data(), QVariant::fromValue(watcher));
29 context->setProperty(QString("future%1").arg(i).toLatin1().data(), QVariant::fromValue(watcher)); 29 }
30 } 30 if (*count == total) {
31 if (*count == total) { 31 future.setFinished();
32 future.setFinished(); 32 }
33 } 33 })
34 }).then<void>([context]() { 34 .then<void>([context]() { delete context; });
35 delete context;
36 });
37} 35}
38 36
39MessageQueue::MessageQueue(const QString &storageRoot, const QString &name) 37MessageQueue::MessageQueue(const QString &storageRoot, const QString &name) : mStorage(storageRoot, name, Sink::Storage::ReadWrite)
40 : mStorage(storageRoot, name, Sink::Storage::ReadWrite)
41{ 38{
42} 39}
43 40
@@ -47,7 +44,7 @@ MessageQueue::~MessageQueue()
47 44
48void MessageQueue::enqueue(void const *msg, size_t size) 45void MessageQueue::enqueue(void const *msg, size_t size)
49{ 46{
50 enqueue(QByteArray::fromRawData(static_cast<const char*>(msg), size)); 47 enqueue(QByteArray::fromRawData(static_cast<const char *>(msg), size));
51} 48}
52 49
53void MessageQueue::startTransaction() 50void MessageQueue::startTransaction()
@@ -96,19 +93,13 @@ void MessageQueue::processRemovals()
96 mPendingRemoval.clear(); 93 mPendingRemoval.clear();
97} 94}
98 95
99void MessageQueue::dequeue(const std::function<void(void *ptr, int size, std::function<void(bool success)>)> &resultHandler, 96void MessageQueue::dequeue(const std::function<void(void *ptr, int size, std::function<void(bool success)>)> &resultHandler, const std::function<void(const Error &error)> &errorHandler)
100 const std::function<void(const Error &error)> &errorHandler)
101{ 97{
102 dequeueBatch(1, [resultHandler](const QByteArray &value) { 98 dequeueBatch(1, [resultHandler](const QByteArray &value) {
103 return KAsync::start<void>([&value,resultHandler](KAsync::Future<void> &future) { 99 return KAsync::start<void>([&value, resultHandler](KAsync::Future<void> &future) {
104 resultHandler(const_cast<void*>(static_cast<const void*>(value.data())), value.size(), [&future](bool success){ 100 resultHandler(const_cast<void *>(static_cast<const void *>(value.data())), value.size(), [&future](bool success) { future.setFinished(); });
105 future.setFinished();
106 });
107 }); 101 });
108 }).then<void>([](){}, 102 }).then<void>([]() {}, [errorHandler](int error, const QString &errorString) { errorHandler(Error("messagequeue", error, errorString.toLatin1())); }).exec();
109 [errorHandler](int error, const QString &errorString) {
110 errorHandler(Error("messagequeue", error, errorString.toLatin1()));
111 }).exec();
112} 103}
113 104
114KAsync::Job<void> MessageQueue::dequeueBatch(int maxBatchSize, const std::function<KAsync::Job<void>(const QByteArray &)> &resultHandler) 105KAsync::Job<void> MessageQueue::dequeueBatch(int maxBatchSize, const std::function<KAsync::Job<void>(const QByteArray &)> &resultHandler)
@@ -116,41 +107,46 @@ KAsync::Job<void> MessageQueue::dequeueBatch(int maxBatchSize, const std::functi
116 auto resultCount = QSharedPointer<int>::create(0); 107 auto resultCount = QSharedPointer<int>::create(0);
117 return KAsync::start<void>([this, maxBatchSize, resultHandler, resultCount](KAsync::Future<void> &future) { 108 return KAsync::start<void>([this, maxBatchSize, resultHandler, resultCount](KAsync::Future<void> &future) {
118 int count = 0; 109 int count = 0;
119 QList<KAsync::Future<void> > waitCondition; 110 QList<KAsync::Future<void>> waitCondition;
120 mStorage.createTransaction(Sink::Storage::ReadOnly).openDatabase().scan("", [this, resultHandler, resultCount, &count, maxBatchSize, &waitCondition](const QByteArray &key, const QByteArray &value) -> bool { 111 mStorage.createTransaction(Sink::Storage::ReadOnly)
121 if (Sink::Storage::isInternalKey(key) || mPendingRemoval.contains(key)) { 112 .openDatabase()
122 return true; 113 .scan("",
123 } 114 [this, resultHandler, resultCount, &count, maxBatchSize, &waitCondition](const QByteArray &key, const QByteArray &value) -> bool {
124 *resultCount += 1; 115 if (Sink::Storage::isInternalKey(key) || mPendingRemoval.contains(key)) {
125 //We need a copy of the key here, otherwise we can't store it in the lambda (the pointers will become invalid) 116 return true;
126 mPendingRemoval << QByteArray(key.constData(), key.size()); 117 }
118 *resultCount += 1;
119 // We need a copy of the key here, otherwise we can't store it in the lambda (the pointers will become invalid)
120 mPendingRemoval << QByteArray(key.constData(), key.size());
127 121
128 waitCondition << resultHandler(value).exec(); 122 waitCondition << resultHandler(value).exec();
129 123
130 count++; 124 count++;
131 if (count < maxBatchSize) { 125 if (count < maxBatchSize) {
132 return true; 126 return true;
133 } 127 }
134 return false; 128 return false;
135 }, 129 },
136 [](const Sink::Storage::Error &error) { 130 [](const Sink::Storage::Error &error) {
137 ErrorMsg() << "Error while retrieving value" << error.message; 131 ErrorMsg() << "Error while retrieving value" << error.message;
138 // errorHandler(Error(error.store, error.code, error.message)); 132 // errorHandler(Error(error.store, error.code, error.message));
139 }); 133 });
140 134
141 // Trace() << "Waiting on " << waitCondition.size() << " results"; 135 // Trace() << "Waiting on " << waitCondition.size() << " results";
142 ::waitForCompletion(waitCondition).then<void>([this, resultCount, &future]() { 136 ::waitForCompletion(waitCondition)
143 processRemovals(); 137 .then<void>([this, resultCount, &future]() {
144 if (*resultCount == 0) { 138 processRemovals();
145 future.setError(static_cast<int>(ErrorCodes::NoMessageFound), "No message found"); 139 if (*resultCount == 0) {
146 future.setFinished(); 140 future.setError(static_cast<int>(ErrorCodes::NoMessageFound), "No message found");
147 } else { 141 future.setFinished();
148 if (isEmpty()) { 142 } else {
149 emit this->drained(); 143 if (isEmpty()) {
144 emit this->drained();
145 }
146 future.setFinished();
150 } 147 }
151 future.setFinished(); 148 })
152 } 149 .exec();
153 }).exec();
154 }); 150 });
155} 151}
156 152
@@ -160,16 +156,15 @@ bool MessageQueue::isEmpty()
160 auto t = mStorage.createTransaction(Sink::Storage::ReadOnly); 156 auto t = mStorage.createTransaction(Sink::Storage::ReadOnly);
161 auto db = t.openDatabase(); 157 auto db = t.openDatabase();
162 if (db) { 158 if (db) {
163 db.scan("", [&count, this](const QByteArray &key, const QByteArray &value) -> bool { 159 db.scan("",
164 if (!Sink::Storage::isInternalKey(key) && !mPendingRemoval.contains(key)) { 160 [&count, this](const QByteArray &key, const QByteArray &value) -> bool {
165 count++; 161 if (!Sink::Storage::isInternalKey(key) && !mPendingRemoval.contains(key)) {
166 return false; 162 count++;
167 } 163 return false;
168 return true; 164 }
169 }, 165 return true;
170 [](const Sink::Storage::Error &error) { 166 },
171 ErrorMsg() << "Error while checking if empty" << error.message; 167 [](const Sink::Storage::Error &error) { ErrorMsg() << "Error while checking if empty" << error.message; });
172 });
173 } 168 }
174 return count == 0; 169 return count == 0;
175} 170}
diff --git a/common/messagequeue.h b/common/messagequeue.h
index 9399055..6f0bddb 100644
--- a/common/messagequeue.h
+++ b/common/messagequeue.h
@@ -16,14 +16,16 @@ class SINK_EXPORT MessageQueue : public QObject
16{ 16{
17 Q_OBJECT 17 Q_OBJECT
18public: 18public:
19 enum ErrorCodes { 19 enum ErrorCodes
20 {
20 NoMessageFound 21 NoMessageFound
21 }; 22 };
22 class Error 23 class Error
23 { 24 {
24 public: 25 public:
25 Error(const QByteArray &s, int c, const QByteArray &m) 26 Error(const QByteArray &s, int c, const QByteArray &m) : store(s), message(m), code(c)
26 : store(s), message(m), code(c) {} 27 {
28 }
27 QByteArray store; 29 QByteArray store;
28 QByteArray message; 30 QByteArray message;
29 int code; 31 int code;
@@ -35,11 +37,10 @@ public:
35 void startTransaction(); 37 void startTransaction();
36 void enqueue(void const *msg, size_t size); 38 void enqueue(void const *msg, size_t size);
37 void enqueue(const QByteArray &value); 39 void enqueue(const QByteArray &value);
38 //Dequeue a message. This will return a new message everytime called. 40 // Dequeue a message. This will return a new message everytime called.
39 //Call the result handler with a success response to remove the message from the store. 41 // Call the result handler with a success response to remove the message from the store.
40 //TODO track processing progress to avoid processing the same message with the same preprocessor twice? 42 // TODO track processing progress to avoid processing the same message with the same preprocessor twice?
41 void dequeue(const std::function<void(void *ptr, int size, std::function<void(bool success)>)> & resultHandler, 43 void dequeue(const std::function<void(void *ptr, int size, std::function<void(bool success)>)> &resultHandler, const std::function<void(const Error &error)> &errorHandler);
42 const std::function<void(const Error &error)> &errorHandler);
43 KAsync::Job<void> dequeueBatch(int maxBatchSize, const std::function<KAsync::Job<void>(const QByteArray &)> &resultHandler); 44 KAsync::Job<void> dequeueBatch(int maxBatchSize, const std::function<KAsync::Job<void>(const QByteArray &)> &resultHandler);
44 bool isEmpty(); 45 bool isEmpty();
45 46
diff --git a/common/modelresult.cpp b/common/modelresult.cpp
index ceefa76..1c06a7d 100644
--- a/common/modelresult.cpp
+++ b/common/modelresult.cpp
@@ -34,11 +34,9 @@ static uint qHash(const Sink::ApplicationDomain::ApplicationDomainType &type)
34 return qHash(type.resourceInstanceIdentifier() + type.identifier()); 34 return qHash(type.resourceInstanceIdentifier() + type.identifier());
35} 35}
36 36
37template<class T, class Ptr> 37template <class T, class Ptr>
38ModelResult<T, Ptr>::ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns) 38ModelResult<T, Ptr>::ModelResult(const Sink::Query &query, const QList<QByteArray> &propertyColumns)
39 :QAbstractItemModel(), 39 : QAbstractItemModel(), mPropertyColumns(propertyColumns), mQuery(query)
40 mPropertyColumns(propertyColumns),
41 mQuery(query)
42{ 40{
43} 41}
44 42
@@ -50,7 +48,7 @@ static qint64 getIdentifier(const QModelIndex &idx)
50 return idx.internalId(); 48 return idx.internalId();
51} 49}
52 50
53template<class T, class Ptr> 51template <class T, class Ptr>
54qint64 ModelResult<T, Ptr>::parentId(const Ptr &value) 52qint64 ModelResult<T, Ptr>::parentId(const Ptr &value)
55{ 53{
56 if (!mQuery.parentProperty.isEmpty()) { 54 if (!mQuery.parentProperty.isEmpty()) {
@@ -62,19 +60,19 @@ qint64 ModelResult<T, Ptr>::parentId(const Ptr &value)
62 return 0; 60 return 0;
63} 61}
64 62
65template<class T, class Ptr> 63template <class T, class Ptr>
66int ModelResult<T, Ptr>::rowCount(const QModelIndex &parent) const 64int ModelResult<T, Ptr>::rowCount(const QModelIndex &parent) const
67{ 65{
68 return mTree[getIdentifier(parent)].size(); 66 return mTree[getIdentifier(parent)].size();
69} 67}
70 68
71template<class T, class Ptr> 69template <class T, class Ptr>
72int ModelResult<T, Ptr>::columnCount(const QModelIndex &parent) const 70int ModelResult<T, Ptr>::columnCount(const QModelIndex &parent) const
73{ 71{
74 return mPropertyColumns.size(); 72 return mPropertyColumns.size();
75} 73}
76 74
77template<class T, class Ptr> 75template <class T, class Ptr>
78QVariant ModelResult<T, Ptr>::headerData(int section, Qt::Orientation orientation, int role) const 76QVariant ModelResult<T, Ptr>::headerData(int section, Qt::Orientation orientation, int role) const
79{ 77{
80 if (role == Qt::DisplayRole) { 78 if (role == Qt::DisplayRole) {
@@ -85,7 +83,7 @@ QVariant ModelResult<T, Ptr>::headerData(int section, Qt::Orientation orientatio
85 return QVariant(); 83 return QVariant();
86} 84}
87 85
88template<class T, class Ptr> 86template <class T, class Ptr>
89QVariant ModelResult<T, Ptr>::data(const QModelIndex &index, int role) const 87QVariant ModelResult<T, Ptr>::data(const QModelIndex &index, int role) const
90{ 88{
91 if (role == DomainObjectRole && index.isValid()) { 89 if (role == DomainObjectRole && index.isValid()) {
@@ -94,7 +92,7 @@ QVariant ModelResult<T, Ptr>::data(const QModelIndex &index, int role) const
94 } 92 }
95 if (role == DomainObjectBaseRole && index.isValid()) { 93 if (role == DomainObjectBaseRole && index.isValid()) {
96 Q_ASSERT(mEntities.contains(index.internalId())); 94 Q_ASSERT(mEntities.contains(index.internalId()));
97 return QVariant::fromValue(mEntities.value(index.internalId()). template staticCast<Sink::ApplicationDomain::ApplicationDomainType>()); 95 return QVariant::fromValue(mEntities.value(index.internalId()).template staticCast<Sink::ApplicationDomain::ApplicationDomainType>());
98 } 96 }
99 if (role == ChildrenFetchedRole) { 97 if (role == ChildrenFetchedRole) {
100 return childrenFetched(index); 98 return childrenFetched(index);
@@ -111,7 +109,7 @@ QVariant ModelResult<T, Ptr>::data(const QModelIndex &index, int role) const
111 return QVariant(); 109 return QVariant();
112} 110}
113 111
114template<class T, class Ptr> 112template <class T, class Ptr>
115QModelIndex ModelResult<T, Ptr>::index(int row, int column, const QModelIndex &parent) const 113QModelIndex ModelResult<T, Ptr>::index(int row, int column, const QModelIndex &parent) const
116{ 114{
117 const auto id = getIdentifier(parent); 115 const auto id = getIdentifier(parent);
@@ -124,7 +122,7 @@ QModelIndex ModelResult<T, Ptr>::index(int row, int column, const QModelIndex &p
124 return QModelIndex(); 122 return QModelIndex();
125} 123}
126 124
127template<class T, class Ptr> 125template <class T, class Ptr>
128QModelIndex ModelResult<T, Ptr>::createIndexFromId(const qint64 &id) const 126QModelIndex ModelResult<T, Ptr>::createIndexFromId(const qint64 &id) const
129{ 127{
130 if (id == 0) { 128 if (id == 0) {
@@ -135,7 +133,7 @@ QModelIndex ModelResult<T, Ptr>::createIndexFromId(const qint64 &id) const
135 return createIndex(row, 0, id); 133 return createIndex(row, 0, id);
136} 134}
137 135
138template<class T, class Ptr> 136template <class T, class Ptr>
139QModelIndex ModelResult<T, Ptr>::parent(const QModelIndex &index) const 137QModelIndex ModelResult<T, Ptr>::parent(const QModelIndex &index) const
140{ 138{
141 auto id = getIdentifier(index); 139 auto id = getIdentifier(index);
@@ -143,7 +141,7 @@ QModelIndex ModelResult<T, Ptr>::parent(const QModelIndex &index) const
143 return createIndexFromId(parentId); 141 return createIndexFromId(parentId);
144} 142}
145 143
146template<class T, class Ptr> 144template <class T, class Ptr>
147bool ModelResult<T, Ptr>::hasChildren(const QModelIndex &parent) const 145bool ModelResult<T, Ptr>::hasChildren(const QModelIndex &parent) const
148{ 146{
149 if (mQuery.parentProperty.isEmpty() && parent.isValid()) { 147 if (mQuery.parentProperty.isEmpty() && parent.isValid()) {
@@ -152,26 +150,26 @@ bool ModelResult<T, Ptr>::hasChildren(const QModelIndex &parent) const
152 return QAbstractItemModel::hasChildren(parent); 150 return QAbstractItemModel::hasChildren(parent);
153} 151}
154 152
155template<class T, class Ptr> 153template <class T, class Ptr>
156bool ModelResult<T, Ptr>::canFetchMore(const QModelIndex &parent) const 154bool ModelResult<T, Ptr>::canFetchMore(const QModelIndex &parent) const
157{ 155{
158 const auto id = parent.internalId(); 156 const auto id = parent.internalId();
159 return !mEntityChildrenFetched.contains(id) || mEntityChildrenFetchComplete.contains(id); 157 return !mEntityChildrenFetched.contains(id) || mEntityChildrenFetchComplete.contains(id);
160} 158}
161 159
162template<class T, class Ptr> 160template <class T, class Ptr>
163void ModelResult<T, Ptr>::fetchMore(const QModelIndex &parent) 161void ModelResult<T, Ptr>::fetchMore(const QModelIndex &parent)
164{ 162{
165 Trace() << "Fetching more: " << parent; 163 Trace() << "Fetching more: " << parent;
166 fetchEntities(parent); 164 fetchEntities(parent);
167} 165}
168 166
169template<class T, class Ptr> 167template <class T, class Ptr>
170void ModelResult<T, Ptr>::add(const Ptr &value) 168void ModelResult<T, Ptr>::add(const Ptr &value)
171{ 169{
172 const auto childId = qHash(*value); 170 const auto childId = qHash(*value);
173 const auto id = parentId(value); 171 const auto id = parentId(value);
174 //Ignore updates we get before the initial fetch is done 172 // Ignore updates we get before the initial fetch is done
175 if (!mEntityChildrenFetched.contains(id)) { 173 if (!mEntityChildrenFetched.contains(id)) {
176 Trace() << "Too early" << id; 174 Trace() << "Too early" << id;
177 return; 175 return;
@@ -199,7 +197,7 @@ void ModelResult<T, Ptr>::add(const Ptr &value)
199} 197}
200 198
201 199
202template<class T, class Ptr> 200template <class T, class Ptr>
203void ModelResult<T, Ptr>::remove(const Ptr &value) 201void ModelResult<T, Ptr>::remove(const Ptr &value)
204{ 202{
205 auto childId = qHash(*value); 203 auto childId = qHash(*value);
@@ -211,11 +209,11 @@ void ModelResult<T, Ptr>::remove(const Ptr &value)
211 mEntities.remove(childId); 209 mEntities.remove(childId);
212 mTree[id].removeAll(childId); 210 mTree[id].removeAll(childId);
213 mParents.remove(childId); 211 mParents.remove(childId);
214 //TODO remove children 212 // TODO remove children
215 endRemoveRows(); 213 endRemoveRows();
216} 214}
217 215
218template<class T, class Ptr> 216template <class T, class Ptr>
219void ModelResult<T, Ptr>::fetchEntities(const QModelIndex &parent) 217void ModelResult<T, Ptr>::fetchEntities(const QModelIndex &parent)
220{ 218{
221 const auto id = getIdentifier(parent); 219 const auto id = getIdentifier(parent);
@@ -229,26 +227,20 @@ void ModelResult<T, Ptr>::fetchEntities(const QModelIndex &parent)
229 } 227 }
230} 228}
231 229
232template<class T, class Ptr> 230template <class T, class Ptr>
233void ModelResult<T, Ptr>::setFetcher(const std::function<void(const Ptr &parent)> &fetcher) 231void ModelResult<T, Ptr>::setFetcher(const std::function<void(const Ptr &parent)> &fetcher)
234{ 232{
235 Trace() << "Setting fetcher"; 233 Trace() << "Setting fetcher";
236 loadEntities = fetcher; 234 loadEntities = fetcher;
237} 235}
238 236
239template<class T, class Ptr> 237template <class T, class Ptr>
240void ModelResult<T, Ptr>::setEmitter(const typename Sink::ResultEmitter<Ptr>::Ptr &emitter) 238void ModelResult<T, Ptr>::setEmitter(const typename Sink::ResultEmitter<Ptr>::Ptr &emitter)
241{ 239{
242 setFetcher([this](const Ptr &parent) {mEmitter->fetch(parent);}); 240 setFetcher([this](const Ptr &parent) { mEmitter->fetch(parent); });
243 emitter->onAdded([this](const Ptr &value) { 241 emitter->onAdded([this](const Ptr &value) { this->add(value); });
244 this->add(value); 242 emitter->onModified([this](const Ptr &value) { this->modify(value); });
245 }); 243 emitter->onRemoved([this](const Ptr &value) { this->remove(value); });
246 emitter->onModified([this](const Ptr &value) {
247 this->modify(value);
248 });
249 emitter->onRemoved([this](const Ptr &value) {
250 this->remove(value);
251 });
252 emitter->onInitialResultSetComplete([this](const Ptr &parent) { 244 emitter->onInitialResultSetComplete([this](const Ptr &parent) {
253 const qint64 parentId = parent ? qHash(*parent) : 0; 245 const qint64 parentId = parent ? qHash(*parent) : 0;
254 const auto parentIndex = createIndexFromId(parentId); 246 const auto parentIndex = createIndexFromId(parentId);
@@ -258,18 +250,18 @@ void ModelResult<T, Ptr>::setEmitter(const typename Sink::ResultEmitter<Ptr>::Pt
258 mEmitter = emitter; 250 mEmitter = emitter;
259} 251}
260 252
261template<class T, class Ptr> 253template <class T, class Ptr>
262bool ModelResult<T, Ptr>::childrenFetched(const QModelIndex &index) const 254bool ModelResult<T, Ptr>::childrenFetched(const QModelIndex &index) const
263{ 255{
264 return mEntityChildrenFetchComplete.contains(getIdentifier(index)); 256 return mEntityChildrenFetchComplete.contains(getIdentifier(index));
265} 257}
266 258
267template<class T, class Ptr> 259template <class T, class Ptr>
268void ModelResult<T, Ptr>::modify(const Ptr &value) 260void ModelResult<T, Ptr>::modify(const Ptr &value)
269{ 261{
270 auto childId = qHash(*value); 262 auto childId = qHash(*value);
271 auto id = parentId(value); 263 auto id = parentId(value);
272 //Ignore updates we get before the initial fetch is done 264 // Ignore updates we get before the initial fetch is done
273 if (!mEntityChildrenFetched.contains(id)) { 265 if (!mEntityChildrenFetched.contains(id)) {
274 return; 266 return;
275 } 267 }
@@ -278,7 +270,7 @@ void ModelResult<T, Ptr>::modify(const Ptr &value)
278 auto i = mTree[id].indexOf(childId); 270 auto i = mTree[id].indexOf(childId);
279 mEntities.remove(childId); 271 mEntities.remove(childId);
280 mEntities.insert(childId, value); 272 mEntities.insert(childId, value);
281 //TODO check for change of parents 273 // TODO check for change of parents
282 auto idx = index(i, 0, parent); 274 auto idx = index(i, 0, parent);
283 emit dataChanged(idx, idx); 275 emit dataChanged(idx, idx);
284} 276}
diff --git a/common/modelresult.h b/common/modelresult.h
index 062517f..0f0c06a 100644
--- a/common/modelresult.h
+++ b/common/modelresult.h
@@ -28,11 +28,12 @@
28#include "query.h" 28#include "query.h"
29#include "resultprovider.h" 29#include "resultprovider.h"
30 30
31template<class T, class Ptr> 31template <class T, class Ptr>
32class ModelResult : public QAbstractItemModel 32class ModelResult : public QAbstractItemModel
33{ 33{
34public: 34public:
35 enum Roles { 35 enum Roles
36 {
36 DomainObjectRole = Qt::UserRole + 1, 37 DomainObjectRole = Qt::UserRole + 1,
37 ChildrenFetchedRole, 38 ChildrenFetchedRole,
38 DomainObjectBaseRole 39 DomainObjectBaseRole
@@ -46,7 +47,7 @@ public:
46 int columnCount(const QModelIndex &parent = QModelIndex()) const; 47 int columnCount(const QModelIndex &parent = QModelIndex()) const;
47 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; 48 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
48 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 49 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
49 QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; 50 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
50 QModelIndex parent(const QModelIndex &index) const; 51 QModelIndex parent(const QModelIndex &index) const;
51 bool hasChildren(const QModelIndex &parent = QModelIndex()) const; 52 bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
52 53
@@ -66,7 +67,7 @@ private:
66 QModelIndex createIndexFromId(const qint64 &id) const; 67 QModelIndex createIndexFromId(const qint64 &id) const;
67 void fetchEntities(const QModelIndex &parent); 68 void fetchEntities(const QModelIndex &parent);
68 69
69 //TODO we should be able to directly use T as index, with an appropriate hash function, and thus have a QMap<T, T> and QList<T> 70 // TODO we should be able to directly use T as index, with an appropriate hash function, and thus have a QMap<T, T> and QList<T>
70 QMap<qint64 /* entity id */, Ptr> mEntities; 71 QMap<qint64 /* entity id */, Ptr> mEntities;
71 QMap<qint64 /* parent entity id */, QList<qint64> /* child entity id*/> mTree; 72 QMap<qint64 /* parent entity id */, QList<qint64> /* child entity id*/> mTree;
72 QMap<qint64 /* child entity id */, qint64 /* parent entity id*/> mParents; 73 QMap<qint64 /* child entity id */, qint64 /* parent entity id*/> mParents;
@@ -77,4 +78,3 @@ private:
77 std::function<void(const Ptr &)> loadEntities; 78 std::function<void(const Ptr &)> loadEntities;
78 typename Sink::ResultEmitter<Ptr>::Ptr mEmitter; 79 typename Sink::ResultEmitter<Ptr>::Ptr mEmitter;
79}; 80};
80
diff --git a/common/notification.h b/common/notification.h
index cf69a99..0eb796d 100644
--- a/common/notification.h
+++ b/common/notification.h
@@ -22,8 +22,7 @@
22#include "sink_export.h" 22#include "sink_export.h"
23#include <QString> 23#include <QString>
24 24
25namespace Sink 25namespace Sink {
26{
27 26
28/** 27/**
29 * A notification 28 * A notification
@@ -36,5 +35,4 @@ public:
36 QString message; 35 QString message;
37 int code; 36 int code;
38}; 37};
39
40} 38}
diff --git a/common/notifier.cpp b/common/notifier.cpp
index e4248df..25d0b85 100644
--- a/common/notifier.cpp
+++ b/common/notifier.cpp
@@ -27,20 +27,18 @@
27 27
28using namespace Sink; 28using namespace Sink;
29 29
30class Sink::Notifier::Private { 30class Sink::Notifier::Private
31{
31public: 32public:
32 Private() 33 Private() : context(new QObject)
33 : context(new QObject)
34 { 34 {
35
36 } 35 }
37 QList<QSharedPointer<ResourceAccess> > resourceAccess; 36 QList<QSharedPointer<ResourceAccess>> resourceAccess;
38 QList<std::function<void(const Notification &)> > handler; 37 QList<std::function<void(const Notification &)>> handler;
39 QSharedPointer<QObject> context; 38 QSharedPointer<QObject> context;
40}; 39};
41 40
42Notifier::Notifier(const QSharedPointer<ResourceAccess> &resourceAccess) 41Notifier::Notifier(const QSharedPointer<ResourceAccess> &resourceAccess) : d(new Sink::Notifier::Private)
43 : d(new Sink::Notifier::Private)
44{ 42{
45 QObject::connect(resourceAccess.data(), &ResourceAccess::notification, d->context.data(), [this](const Notification &notification) { 43 QObject::connect(resourceAccess.data(), &ResourceAccess::notification, d->context.data(), [this](const Notification &notification) {
46 for (const auto &handler : d->handler) { 44 for (const auto &handler : d->handler) {
@@ -50,8 +48,7 @@ Notifier::Notifier(const QSharedPointer<ResourceAccess> &resourceAccess)
50 d->resourceAccess << resourceAccess; 48 d->resourceAccess << resourceAccess;
51} 49}
52 50
53Notifier::Notifier(const QByteArray &instanceIdentifier) 51Notifier::Notifier(const QByteArray &instanceIdentifier) : d(new Sink::Notifier::Private)
54 : d(new Sink::Notifier::Private)
55{ 52{
56 auto resourceAccess = Sink::ResourceAccess::Ptr::create(instanceIdentifier); 53 auto resourceAccess = Sink::ResourceAccess::Ptr::create(instanceIdentifier);
57 resourceAccess->open(); 54 resourceAccess->open();
diff --git a/common/notifier.h b/common/notifier.h
index d16a311..9e75dde 100644
--- a/common/notifier.h
+++ b/common/notifier.h
@@ -32,7 +32,8 @@ namespace Sink {
32class ResourceAccess; 32class ResourceAccess;
33class Notification; 33class Notification;
34 34
35class SINK_EXPORT Notifier { 35class SINK_EXPORT Notifier
36{
36public: 37public:
37 Notifier(const QSharedPointer<ResourceAccess> &resourceAccess); 38 Notifier(const QSharedPointer<ResourceAccess> &resourceAccess);
38 Notifier(const QByteArray &resourceInstanceIdentifier); 39 Notifier(const QByteArray &resourceInstanceIdentifier);
@@ -42,5 +43,4 @@ private:
42 class Private; 43 class Private;
43 QSharedPointer<Private> d; 44 QSharedPointer<Private> d;
44}; 45};
45
46} 46}
diff --git a/common/pipeline.cpp b/common/pipeline.cpp
index 35e582b..65a2f5b 100644
--- a/common/pipeline.cpp
+++ b/common/pipeline.cpp
@@ -40,21 +40,18 @@
40#undef DEBUG_AREA 40#undef DEBUG_AREA
41#define DEBUG_AREA "resource.pipeline" 41#define DEBUG_AREA "resource.pipeline"
42 42
43namespace Sink 43namespace Sink {
44{
45 44
46class Pipeline::Private 45class Pipeline::Private
47{ 46{
48public: 47public:
49 Private(const QString &resourceName) 48 Private(const QString &resourceName) : storage(Sink::storageLocation(), resourceName, Storage::ReadWrite), revisionChanged(false)
50 : storage(Sink::storageLocation(), resourceName, Storage::ReadWrite),
51 revisionChanged(false)
52 { 49 {
53 } 50 }
54 51
55 Storage storage; 52 Storage storage;
56 Storage::Transaction transaction; 53 Storage::Transaction transaction;
57 QHash<QString, QVector<Preprocessor *> > processors; 54 QHash<QString, QVector<Preprocessor *>> processors;
58 QHash<QString, DomainTypeAdaptorFactoryInterface::Ptr> adaptorFactory; 55 QHash<QString, DomainTypeAdaptorFactoryInterface::Ptr> adaptorFactory;
59 bool revisionChanged; 56 bool revisionChanged;
60 void storeNewRevision(qint64 newRevision, const flatbuffers::FlatBufferBuilder &fbb, const QByteArray &bufferType, const QByteArray &uid); 57 void storeNewRevision(qint64 newRevision, const flatbuffers::FlatBufferBuilder &fbb, const QByteArray &bufferType, const QByteArray &uid);
@@ -64,20 +61,16 @@ public:
64 61
65void Pipeline::Private::storeNewRevision(qint64 newRevision, const flatbuffers::FlatBufferBuilder &fbb, const QByteArray &bufferType, const QByteArray &uid) 62void Pipeline::Private::storeNewRevision(qint64 newRevision, const flatbuffers::FlatBufferBuilder &fbb, const QByteArray &bufferType, const QByteArray &uid)
66{ 63{
67 Storage::mainDatabase(transaction, bufferType).write(Storage::assembleKey(uid, newRevision), BufferUtils::extractBuffer(fbb), 64 Storage::mainDatabase(transaction, bufferType)
68 [uid, newRevision](const Storage::Error &error) { 65 .write(Storage::assembleKey(uid, newRevision), BufferUtils::extractBuffer(fbb),
69 Warning() << "Failed to write entity" << uid << newRevision; 66 [uid, newRevision](const Storage::Error &error) { Warning() << "Failed to write entity" << uid << newRevision; });
70 }
71 );
72 revisionChanged = true; 67 revisionChanged = true;
73 Storage::setMaxRevision(transaction, newRevision); 68 Storage::setMaxRevision(transaction, newRevision);
74 Storage::recordRevision(transaction, newRevision, uid, bufferType); 69 Storage::recordRevision(transaction, newRevision, uid, bufferType);
75} 70}
76 71
77 72
78Pipeline::Pipeline(const QString &resourceName, QObject *parent) 73Pipeline::Pipeline(const QString &resourceName, QObject *parent) : QObject(parent), d(new Private(resourceName))
79 : QObject(parent),
80 d(new Private(resourceName))
81{ 74{
82} 75}
83 76
@@ -98,8 +91,8 @@ void Pipeline::setAdaptorFactory(const QString &entityType, DomainTypeAdaptorFac
98 91
99void Pipeline::startTransaction() 92void Pipeline::startTransaction()
100{ 93{
101 //TODO call for all types 94 // TODO call for all types
102 //But avoid doing it during cleanup 95 // But avoid doing it during cleanup
103 // for (auto processor : d->processors[bufferType]) { 96 // for (auto processor : d->processors[bufferType]) {
104 // processor->startBatch(); 97 // processor->startBatch();
105 // } 98 // }
@@ -114,14 +107,15 @@ void Pipeline::startTransaction()
114 107
115void Pipeline::commit() 108void Pipeline::commit()
116{ 109{
117 //TODO call for all types 110 // TODO call for all types
118 //But avoid doing it during cleanup 111 // But avoid doing it during cleanup
119 // for (auto processor : d->processors[bufferType]) { 112 // for (auto processor : d->processors[bufferType]) {
120 // processor->finalize(); 113 // processor->finalize();
121 // } 114 // }
122 const auto revision = Storage::maxRevision(d->transaction); 115 const auto revision = Storage::maxRevision(d->transaction);
123 const auto elapsed = d->transactionTime.elapsed(); 116 const auto elapsed = d->transactionTime.elapsed();
124 Trace() << "Committing revision: " << revision << ":" << d->transactionItemCount << " items in: " << Log::TraceTime(elapsed) << " " << (double)elapsed/(double)qMax(d->transactionItemCount, 1) << "[ms/item]"; 117 Trace() << "Committing revision: " << revision << ":" << d->transactionItemCount << " items in: " << Log::TraceTime(elapsed) << " "
118 << (double)elapsed / (double)qMax(d->transactionItemCount, 1) << "[ms/item]";
125 if (d->transaction) { 119 if (d->transaction) {
126 d->transaction.commit(); 120 d->transaction.commit();
127 } 121 }
@@ -157,7 +151,7 @@ KAsync::Job<qint64> Pipeline::newEntity(void const *command, size_t size)
157 auto createEntity = Commands::GetCreateEntity(command); 151 auto createEntity = Commands::GetCreateEntity(command);
158 152
159 const bool replayToSource = createEntity->replayToSource(); 153 const bool replayToSource = createEntity->replayToSource();
160 const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(createEntity->domainType()->Data()), createEntity->domainType()->size()); 154 const QByteArray bufferType = QByteArray(reinterpret_cast<char const *>(createEntity->domainType()->Data()), createEntity->domainType()->size());
161 { 155 {
162 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size()); 156 flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(createEntity->delta()->Data()), createEntity->delta()->size());
163 if (!VerifyEntityBuffer(verifyer)) { 157 if (!VerifyEntityBuffer(verifyer)) {
@@ -173,7 +167,7 @@ KAsync::Job<qint64> Pipeline::newEntity(void const *command, size_t size)
173 167
174 QByteArray key; 168 QByteArray key;
175 if (createEntity->entityId()) { 169 if (createEntity->entityId()) {
176 key = QByteArray(reinterpret_cast<char const*>(createEntity->entityId()->Data()), createEntity->entityId()->size()); 170 key = QByteArray(reinterpret_cast<char const *>(createEntity->entityId()->Data()), createEntity->entityId()->size());
177 if (Storage::mainDatabase(d->transaction, bufferType).contains(key)) { 171 if (Storage::mainDatabase(d->transaction, bufferType).contains(key)) {
178 ErrorMsg() << "An entity with this id already exists: " << key; 172 ErrorMsg() << "An entity with this id already exists: " << key;
179 return KAsync::error<qint64>(0); 173 return KAsync::error<qint64>(0);
@@ -186,7 +180,7 @@ KAsync::Job<qint64> Pipeline::newEntity(void const *command, size_t size)
186 Q_ASSERT(!key.isEmpty()); 180 Q_ASSERT(!key.isEmpty());
187 const qint64 newRevision = Storage::maxRevision(d->transaction) + 1; 181 const qint64 newRevision = Storage::maxRevision(d->transaction) + 1;
188 182
189 //Add metadata buffer 183 // Add metadata buffer
190 flatbuffers::FlatBufferBuilder metadataFbb; 184 flatbuffers::FlatBufferBuilder metadataFbb;
191 auto metadataBuilder = MetadataBuilder(metadataFbb); 185 auto metadataBuilder = MetadataBuilder(metadataFbb);
192 metadataBuilder.add_revision(newRevision); 186 metadataBuilder.add_revision(newRevision);
@@ -196,7 +190,8 @@ KAsync::Job<qint64> Pipeline::newEntity(void const *command, size_t size)
196 FinishMetadataBuffer(metadataFbb, metadataBuffer); 190 FinishMetadataBuffer(metadataFbb, metadataBuffer);
197 191
198 flatbuffers::FlatBufferBuilder fbb; 192 flatbuffers::FlatBufferBuilder fbb;
199 EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), entity->resource()->Data(), entity->resource()->size(), entity->local()->Data(), entity->local()->size()); 193 EntityBuffer::assembleEntityBuffer(
194 fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), entity->resource()->Data(), entity->resource()->size(), entity->local()->Data(), entity->local()->size());
200 195
201 d->storeNewRevision(newRevision, fbb, bufferType, key); 196 d->storeNewRevision(newRevision, fbb, bufferType, key);
202 197
@@ -207,20 +202,19 @@ KAsync::Job<qint64> Pipeline::newEntity(void const *command, size_t size)
207 } 202 }
208 203
209 Log() << "Pipeline: wrote entity: " << key << newRevision << bufferType; 204 Log() << "Pipeline: wrote entity: " << key << newRevision << bufferType;
210 Storage::mainDatabase(d->transaction, bufferType).scan(Storage::assembleKey(key, newRevision), [this, bufferType, newRevision, adaptorFactory, key](const QByteArray &, const QByteArray &value) -> bool { 205 Storage::mainDatabase(d->transaction, bufferType)
211 auto entity = GetEntity(value); 206 .scan(Storage::assembleKey(key, newRevision),
212 Q_ASSERT(entity->resource() || entity->local()); 207 [this, bufferType, newRevision, adaptorFactory, key](const QByteArray &, const QByteArray &value) -> bool {
213 auto adaptor = adaptorFactory->createAdaptor(*entity); 208 auto entity = GetEntity(value);
214 for (auto processor : d->processors[bufferType]) { 209 Q_ASSERT(entity->resource() || entity->local());
215 processor->newEntity(key, newRevision, *adaptor, d->transaction); 210 auto adaptor = adaptorFactory->createAdaptor(*entity);
216 } 211 for (auto processor : d->processors[bufferType]) {
217 return false; 212 processor->newEntity(key, newRevision, *adaptor, d->transaction);
218 }, [this](const Storage::Error &error) { 213 }
219 ErrorMsg() << "Failed to find value in pipeline: " << error.message; 214 return false;
220 }); 215 },
221 return KAsync::start<qint64>([newRevision](){ 216 [this](const Storage::Error &error) { ErrorMsg() << "Failed to find value in pipeline: " << error.message; });
222 return newRevision; 217 return KAsync::start<qint64>([newRevision]() { return newRevision; });
223 });
224} 218}
225 219
226KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size) 220KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
@@ -242,9 +236,9 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
242 236
243 const qint64 baseRevision = modifyEntity->revision(); 237 const qint64 baseRevision = modifyEntity->revision();
244 const bool replayToSource = modifyEntity->replayToSource(); 238 const bool replayToSource = modifyEntity->replayToSource();
245 //TODO rename modifyEntity->domainType to bufferType 239 // TODO rename modifyEntity->domainType to bufferType
246 const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size()); 240 const QByteArray bufferType = QByteArray(reinterpret_cast<char const *>(modifyEntity->domainType()->Data()), modifyEntity->domainType()->size());
247 const QByteArray key = QByteArray(reinterpret_cast<char const*>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size()); 241 const QByteArray key = QByteArray(reinterpret_cast<char const *>(modifyEntity->entityId()->Data()), modifyEntity->entityId()->size());
248 if (bufferType.isEmpty() || key.isEmpty()) { 242 if (bufferType.isEmpty() || key.isEmpty()) {
249 Warning() << "entity type or key " << bufferType << key; 243 Warning() << "entity type or key " << bufferType << key;
250 return KAsync::error<qint64>(0); 244 return KAsync::error<qint64>(0);
@@ -257,7 +251,7 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
257 } 251 }
258 } 252 }
259 253
260 //TODO use only readPropertyMapper and writePropertyMapper 254 // TODO use only readPropertyMapper and writePropertyMapper
261 auto adaptorFactory = d->adaptorFactory.value(bufferType); 255 auto adaptorFactory = d->adaptorFactory.value(bufferType);
262 if (!adaptorFactory) { 256 if (!adaptorFactory) {
263 Warning() << "no adaptor factory for type " << bufferType; 257 Warning() << "no adaptor factory for type " << bufferType;
@@ -269,30 +263,30 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
269 auto diff = adaptorFactory->createAdaptor(*diffEntity); 263 auto diff = adaptorFactory->createAdaptor(*diffEntity);
270 264
271 QSharedPointer<ApplicationDomain::BufferAdaptor> current; 265 QSharedPointer<ApplicationDomain::BufferAdaptor> current;
272 Storage::mainDatabase(d->transaction, bufferType).findLatest(key, [&current, adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool { 266 Storage::mainDatabase(d->transaction, bufferType)
273 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); 267 .findLatest(key,
274 if (!buffer.isValid()) { 268 [&current, adaptorFactory](const QByteArray &key, const QByteArray &data) -> bool {
275 Warning() << "Read invalid buffer from disk"; 269 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size());
276 } else { 270 if (!buffer.isValid()) {
277 current = adaptorFactory->createAdaptor(buffer.entity()); 271 Warning() << "Read invalid buffer from disk";
278 } 272 } else {
279 return false; 273 current = adaptorFactory->createAdaptor(buffer.entity());
280 }, 274 }
281 [baseRevision](const Storage::Error &error) { 275 return false;
282 Warning() << "Failed to read old revision from storage: " << error.message << "Revision: " << baseRevision; 276 },
283 }); 277 [baseRevision](const Storage::Error &error) { Warning() << "Failed to read old revision from storage: " << error.message << "Revision: " << baseRevision; });
284 278
285 if (!current) { 279 if (!current) {
286 Warning() << "Failed to read local value " << key; 280 Warning() << "Failed to read local value " << key;
287 return KAsync::error<qint64>(0); 281 return KAsync::error<qint64>(0);
288 } 282 }
289 283
290 //resource and uid don't matter at this point 284 // resource and uid don't matter at this point
291 const ApplicationDomain::ApplicationDomainType existingObject("", "", newRevision, current); 285 const ApplicationDomain::ApplicationDomainType existingObject("", "", newRevision, current);
292 auto newObject = ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<ApplicationDomain::ApplicationDomainType>(existingObject); 286 auto newObject = ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<ApplicationDomain::ApplicationDomainType>(existingObject);
293 287
294 //Apply diff 288 // Apply diff
295 //FIXME only apply the properties that are available in the buffer 289 // FIXME only apply the properties that are available in the buffer
296 Trace() << "Applying changed properties: " << diff->availableProperties(); 290 Trace() << "Applying changed properties: " << diff->availableProperties();
297 QSet<QByteArray> changeset; 291 QSet<QByteArray> changeset;
298 for (const auto &property : diff->availableProperties()) { 292 for (const auto &property : diff->availableProperties()) {
@@ -302,17 +296,17 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
302 newObject->setProperty(property, value); 296 newObject->setProperty(property, value);
303 } 297 }
304 } 298 }
305 //Altough we only set some properties, we want all to be serialized 299 // Altough we only set some properties, we want all to be serialized
306 newObject->setChangedProperties(changeset); 300 newObject->setChangedProperties(changeset);
307 301
308 //Remove deletions 302 // Remove deletions
309 if (modifyEntity->deletions()) { 303 if (modifyEntity->deletions()) {
310 for (const auto &property : *modifyEntity->deletions()) { 304 for (const auto &property : *modifyEntity->deletions()) {
311 newObject->setProperty(BufferUtils::extractBuffer(property), QVariant()); 305 newObject->setProperty(BufferUtils::extractBuffer(property), QVariant());
312 } 306 }
313 } 307 }
314 308
315 //Add metadata buffer 309 // Add metadata buffer
316 flatbuffers::FlatBufferBuilder metadataFbb; 310 flatbuffers::FlatBufferBuilder metadataFbb;
317 auto metadataBuilder = MetadataBuilder(metadataFbb); 311 auto metadataBuilder = MetadataBuilder(metadataFbb);
318 metadataBuilder.add_revision(newRevision); 312 metadataBuilder.add_revision(newRevision);
@@ -326,22 +320,21 @@ KAsync::Job<qint64> Pipeline::modifiedEntity(void const *command, size_t size)
326 320
327 d->storeNewRevision(newRevision, fbb, bufferType, key); 321 d->storeNewRevision(newRevision, fbb, bufferType, key);
328 Log() << "Pipeline: modified entity: " << key << newRevision << bufferType; 322 Log() << "Pipeline: modified entity: " << key << newRevision << bufferType;
329 Storage::mainDatabase(d->transaction, bufferType).scan(Storage::assembleKey(key, newRevision), [this, bufferType, newRevision, adaptorFactory, current, key](const QByteArray &k, const QByteArray &value) -> bool { 323 Storage::mainDatabase(d->transaction, bufferType)
330 if (value.isEmpty()) { 324 .scan(Storage::assembleKey(key, newRevision),
331 ErrorMsg() << "Read buffer is empty."; 325 [this, bufferType, newRevision, adaptorFactory, current, key](const QByteArray &k, const QByteArray &value) -> bool {
332 } 326 if (value.isEmpty()) {
333 auto entity = GetEntity(value.data()); 327 ErrorMsg() << "Read buffer is empty.";
334 auto newEntity = adaptorFactory->createAdaptor(*entity); 328 }
335 for (auto processor : d->processors[bufferType]) { 329 auto entity = GetEntity(value.data());
336 processor->modifiedEntity(key, newRevision, *current, *newEntity, d->transaction); 330 auto newEntity = adaptorFactory->createAdaptor(*entity);
337 } 331 for (auto processor : d->processors[bufferType]) {
338 return false; 332 processor->modifiedEntity(key, newRevision, *current, *newEntity, d->transaction);
339 }, [this](const Storage::Error &error) { 333 }
340 ErrorMsg() << "Failed to find value in pipeline: " << error.message; 334 return false;
341 }); 335 },
342 return KAsync::start<qint64>([newRevision](){ 336 [this](const Storage::Error &error) { ErrorMsg() << "Failed to find value in pipeline: " << error.message; });
343 return newRevision; 337 return KAsync::start<qint64>([newRevision]() { return newRevision; });
344 });
345} 338}
346 339
347KAsync::Job<qint64> Pipeline::deletedEntity(void const *command, size_t size) 340KAsync::Job<qint64> Pipeline::deletedEntity(void const *command, size_t size)
@@ -359,26 +352,25 @@ KAsync::Job<qint64> Pipeline::deletedEntity(void const *command, size_t size)
359 auto deleteEntity = Commands::GetDeleteEntity(command); 352 auto deleteEntity = Commands::GetDeleteEntity(command);
360 353
361 const bool replayToSource = deleteEntity->replayToSource(); 354 const bool replayToSource = deleteEntity->replayToSource();
362 const QByteArray bufferType = QByteArray(reinterpret_cast<char const*>(deleteEntity->domainType()->Data()), deleteEntity->domainType()->size()); 355 const QByteArray bufferType = QByteArray(reinterpret_cast<char const *>(deleteEntity->domainType()->Data()), deleteEntity->domainType()->size());
363 const QByteArray key = QByteArray(reinterpret_cast<char const*>(deleteEntity->entityId()->Data()), deleteEntity->entityId()->size()); 356 const QByteArray key = QByteArray(reinterpret_cast<char const *>(deleteEntity->entityId()->Data()), deleteEntity->entityId()->size());
364 357
365 bool found = false; 358 bool found = false;
366 bool alreadyRemoved = false; 359 bool alreadyRemoved = false;
367 Storage::mainDatabase(d->transaction, bufferType).findLatest(key, [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) -> bool { 360 Storage::mainDatabase(d->transaction, bufferType)
368 auto entity = GetEntity(data.data()); 361 .findLatest(key,
369 if (entity && entity->metadata()) { 362 [&found, &alreadyRemoved](const QByteArray &key, const QByteArray &data) -> bool {
370 auto metadata = GetMetadata(entity->metadata()->Data()); 363 auto entity = GetEntity(data.data());
371 found = true; 364 if (entity && entity->metadata()) {
372 if (metadata->operation() == Operation_Removal) { 365 auto metadata = GetMetadata(entity->metadata()->Data());
373 alreadyRemoved = true; 366 found = true;
374 } 367 if (metadata->operation() == Operation_Removal) {
375 368 alreadyRemoved = true;
376 } 369 }
377 return false; 370 }
378 }, 371 return false;
379 [](const Storage::Error &error) { 372 },
380 Warning() << "Failed to read old revision from storage: " << error.message; 373 [](const Storage::Error &error) { Warning() << "Failed to read old revision from storage: " << error.message; });
381 });
382 374
383 if (!found) { 375 if (!found) {
384 Warning() << "Failed to find entity " << key; 376 Warning() << "Failed to find entity " << key;
@@ -391,7 +383,7 @@ KAsync::Job<qint64> Pipeline::deletedEntity(void const *command, size_t size)
391 383
392 const qint64 newRevision = Storage::maxRevision(d->transaction) + 1; 384 const qint64 newRevision = Storage::maxRevision(d->transaction) + 1;
393 385
394 //Add metadata buffer 386 // Add metadata buffer
395 flatbuffers::FlatBufferBuilder metadataFbb; 387 flatbuffers::FlatBufferBuilder metadataFbb;
396 auto metadataBuilder = MetadataBuilder(metadataFbb); 388 auto metadataBuilder = MetadataBuilder(metadataFbb);
397 metadataBuilder.add_revision(newRevision); 389 metadataBuilder.add_revision(newRevision);
@@ -410,28 +402,27 @@ KAsync::Job<qint64> Pipeline::deletedEntity(void const *command, size_t size)
410 } 402 }
411 403
412 QSharedPointer<ApplicationDomain::BufferAdaptor> current; 404 QSharedPointer<ApplicationDomain::BufferAdaptor> current;
413 Storage::mainDatabase(d->transaction, bufferType).findLatest(key, [this, bufferType, newRevision, adaptorFactory, key, &current](const QByteArray &, const QByteArray &data) -> bool { 405 Storage::mainDatabase(d->transaction, bufferType)
414 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); 406 .findLatest(key,
415 if (!buffer.isValid()) { 407 [this, bufferType, newRevision, adaptorFactory, key, &current](const QByteArray &, const QByteArray &data) -> bool {
416 Warning() << "Read invalid buffer from disk"; 408 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size());
417 } else { 409 if (!buffer.isValid()) {
418 current = adaptorFactory->createAdaptor(buffer.entity()); 410 Warning() << "Read invalid buffer from disk";
419 } 411 } else {
420 return false; 412 current = adaptorFactory->createAdaptor(buffer.entity());
421 }, [this](const Storage::Error &error) { 413 }
422 ErrorMsg() << "Failed to find value in pipeline: " << error.message; 414 return false;
423 }); 415 },
416 [this](const Storage::Error &error) { ErrorMsg() << "Failed to find value in pipeline: " << error.message; });
424 417
425 d->storeNewRevision(newRevision, fbb, bufferType, key); 418 d->storeNewRevision(newRevision, fbb, bufferType, key);
426 Log() << "Pipeline: deleted entity: "<< newRevision; 419 Log() << "Pipeline: deleted entity: " << newRevision;
427 420
428 for (auto processor : d->processors[bufferType]) { 421 for (auto processor : d->processors[bufferType]) {
429 processor->deletedEntity(key, newRevision, *current, d->transaction); 422 processor->deletedEntity(key, newRevision, *current, d->transaction);
430 } 423 }
431 424
432 return KAsync::start<qint64>([newRevision](){ 425 return KAsync::start<qint64>([newRevision]() { return newRevision; });
433 return newRevision;
434 });
435} 426}
436 427
437void Pipeline::cleanupRevision(qint64 revision) 428void Pipeline::cleanupRevision(qint64 revision)
@@ -439,24 +430,25 @@ void Pipeline::cleanupRevision(qint64 revision)
439 const auto uid = Storage::getUidFromRevision(d->transaction, revision); 430 const auto uid = Storage::getUidFromRevision(d->transaction, revision);
440 const auto bufferType = Storage::getTypeFromRevision(d->transaction, revision); 431 const auto bufferType = Storage::getTypeFromRevision(d->transaction, revision);
441 Trace() << "Cleaning up revision " << revision << uid << bufferType; 432 Trace() << "Cleaning up revision " << revision << uid << bufferType;
442 Storage::mainDatabase(d->transaction, bufferType).scan(uid, [&](const QByteArray &key, const QByteArray &data) -> bool { 433 Storage::mainDatabase(d->transaction, bufferType)
443 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size()); 434 .scan(uid,
444 if (!buffer.isValid()) { 435 [&](const QByteArray &key, const QByteArray &data) -> bool {
445 Warning() << "Read invalid buffer from disk"; 436 EntityBuffer buffer(const_cast<const char *>(data.data()), data.size());
446 } else { 437 if (!buffer.isValid()) {
447 const auto metadata = flatbuffers::GetRoot<Metadata>(buffer.metadataBuffer()); 438 Warning() << "Read invalid buffer from disk";
448 const qint64 rev = metadata->revision(); 439 } else {
449 //Remove old revisions, and the current if the entity has already been removed 440 const auto metadata = flatbuffers::GetRoot<Metadata>(buffer.metadataBuffer());
450 if (rev < revision || metadata->operation() == Operation_Removal) { 441 const qint64 rev = metadata->revision();
451 Storage::removeRevision(d->transaction, rev); 442 // Remove old revisions, and the current if the entity has already been removed
452 Storage::mainDatabase(d->transaction, bufferType).remove(key); 443 if (rev < revision || metadata->operation() == Operation_Removal) {
453 } 444 Storage::removeRevision(d->transaction, rev);
454 } 445 Storage::mainDatabase(d->transaction, bufferType).remove(key);
455 446 }
456 return true; 447 }
457 }, [](const Storage::Error &error) { 448
458 Warning() << "Error while reading: " << error.message; 449 return true;
459 }, true); 450 },
451 [](const Storage::Error &error) { Warning() << "Error while reading: " << error.message; }, true);
460 Storage::setCleanedUpRevision(d->transaction, revision); 452 Storage::setCleanedUpRevision(d->transaction, revision);
461} 453}
462 454
@@ -465,8 +457,7 @@ qint64 Pipeline::cleanedUpRevision()
465 return Storage::cleanedUpRevision(d->transaction); 457 return Storage::cleanedUpRevision(d->transaction);
466} 458}
467 459
468Preprocessor::Preprocessor() 460Preprocessor::Preprocessor() : d(0)
469 : d(0)
470{ 461{
471} 462}
472 463
diff --git a/common/pipeline.h b/common/pipeline.h
index 0f989e4..dc2cc4d 100644
--- a/common/pipeline.h
+++ b/common/pipeline.h
@@ -32,8 +32,7 @@
32 32
33#include "domainadaptor.h" 33#include "domainadaptor.h"
34 34
35namespace Sink 35namespace Sink {
36{
37 36
38class Preprocessor; 37class Preprocessor;
39 38
@@ -74,7 +73,7 @@ signals:
74 73
75private: 74private:
76 class Private; 75 class Private;
77 Private * const d; 76 Private *const d;
78}; 77};
79 78
80class SINK_EXPORT Preprocessor 79class SINK_EXPORT Preprocessor
@@ -85,14 +84,14 @@ public:
85 84
86 virtual void startBatch(); 85 virtual void startBatch();
87 virtual void newEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) = 0; 86 virtual void newEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) = 0;
88 virtual void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) = 0; 87 virtual void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity,
88 const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) = 0;
89 virtual void deletedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::Storage::Transaction &transaction) = 0; 89 virtual void deletedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::Storage::Transaction &transaction) = 0;
90 virtual void finalize(); 90 virtual void finalize();
91 91
92private: 92private:
93 class Private; 93 class Private;
94 Private * const d; 94 Private *const d;
95}; 95};
96 96
97} // namespace Sink 97} // namespace Sink
98
diff --git a/common/propertymapper.cpp b/common/propertymapper.cpp
index 5348b11..ebe5cb3 100644
--- a/common/propertymapper.cpp
+++ b/common/propertymapper.cpp
@@ -51,7 +51,7 @@ template <>
51QVariant propertyToVariant<QString>(const flatbuffers::String *property) 51QVariant propertyToVariant<QString>(const flatbuffers::String *property)
52{ 52{
53 if (property) { 53 if (property) {
54 //We have to copy the memory, otherwise it would become eventually invalid 54 // We have to copy the memory, otherwise it would become eventually invalid
55 return QString::fromStdString(property->c_str()); 55 return QString::fromStdString(property->c_str());
56 } 56 }
57 return QVariant(); 57 return QVariant();
@@ -61,7 +61,7 @@ template <>
61QVariant propertyToVariant<QByteArray>(const flatbuffers::String *property) 61QVariant propertyToVariant<QByteArray>(const flatbuffers::String *property)
62{ 62{
63 if (property) { 63 if (property) {
64 //We have to copy the memory, otherwise it would become eventually invalid 64 // We have to copy the memory, otherwise it would become eventually invalid
65 return QString::fromStdString(property->c_str()).toUtf8(); 65 return QString::fromStdString(property->c_str()).toUtf8();
66 } 66 }
67 return QVariant(); 67 return QVariant();
@@ -71,7 +71,7 @@ template <>
71QVariant propertyToVariant<QByteArray>(const flatbuffers::Vector<uint8_t> *property) 71QVariant propertyToVariant<QByteArray>(const flatbuffers::Vector<uint8_t> *property)
72{ 72{
73 if (property) { 73 if (property) {
74 //We have to copy the memory, otherwise it would become eventually invalid 74 // We have to copy the memory, otherwise it would become eventually invalid
75 return QByteArray(reinterpret_cast<const char *>(property->Data()), property->Length()); 75 return QByteArray(reinterpret_cast<const char *>(property->Data()), property->Length());
76 } 76 }
77 return QVariant(); 77 return QVariant();
@@ -87,7 +87,7 @@ template <>
87QVariant propertyToVariant<QDateTime>(const flatbuffers::String *property) 87QVariant propertyToVariant<QDateTime>(const flatbuffers::String *property)
88{ 88{
89 if (property) { 89 if (property) {
90 //We have to copy the memory, otherwise it would become eventually invalid 90 // We have to copy the memory, otherwise it would become eventually invalid
91 return QDateTime::fromString(QString::fromStdString(property->c_str())); 91 return QDateTime::fromString(QString::fromStdString(property->c_str()));
92 } 92 }
93 return QVariant(); 93 return QVariant();
diff --git a/common/propertymapper.h b/common/propertymapper.h
index 57202ab..cf8ce7b 100644
--- a/common/propertymapper.h
+++ b/common/propertymapper.h
@@ -49,7 +49,7 @@ QVariant SINK_EXPORT propertyToVariant(const flatbuffers::Vector<uint8_t> *);
49 * a virtual method per property, the property mapper can be filled with accessors 49 * a virtual method per property, the property mapper can be filled with accessors
50 * that extract the properties from resource types. 50 * that extract the properties from resource types.
51 */ 51 */
52template<typename BufferType> 52template <typename BufferType>
53class ReadPropertyMapper 53class ReadPropertyMapper
54{ 54{
55public: 55public:
@@ -63,63 +63,66 @@ public:
63 } 63 }
64 return QVariant(); 64 return QVariant();
65 } 65 }
66 bool hasMapping(const QByteArray &key) const { return mReadAccessors.contains(key); } 66 bool hasMapping(const QByteArray &key) const
67 QList<QByteArray> availableProperties() const { return mReadAccessors.keys(); } 67 {
68 void addMapping(const QByteArray &property, const std::function<QVariant(BufferType const *)> &mapping) { 68 return mReadAccessors.contains(key);
69 }
70 QList<QByteArray> availableProperties() const
71 {
72 return mReadAccessors.keys();
73 }
74 void addMapping(const QByteArray &property, const std::function<QVariant(BufferType const *)> &mapping)
75 {
69 mReadAccessors.insert(property, mapping); 76 mReadAccessors.insert(property, mapping);
70 } 77 }
71 78
72 template <typename T, typename Buffer> 79 template <typename T, typename Buffer>
73 void addMapping(const QByteArray &name, const flatbuffers::String *(Buffer::*f)() const) 80 void addMapping(const QByteArray &name, const flatbuffers::String *(Buffer::*f)() const)
74 { 81 {
75 addMapping(name, [f](Buffer const *buffer) -> QVariant { 82 addMapping(name, [f](Buffer const *buffer) -> QVariant { return propertyToVariant<T>((buffer->*f)()); });
76 return propertyToVariant<T>((buffer->*f)());
77 });
78 } 83 }
79 84
80 template <typename T, typename Buffer> 85 template <typename T, typename Buffer>
81 void addMapping(const QByteArray &name, uint8_t (Buffer::*f)() const) 86 void addMapping(const QByteArray &name, uint8_t (Buffer::*f)() const)
82 { 87 {
83 addMapping(name, [f](Buffer const *buffer) -> QVariant { 88 addMapping(name, [f](Buffer const *buffer) -> QVariant { return propertyToVariant<T>((buffer->*f)()); });
84 return propertyToVariant<T>((buffer->*f)());
85 });
86 } 89 }
87 90
88 template <typename T, typename Buffer> 91 template <typename T, typename Buffer>
89 void addMapping(const QByteArray &name, bool (Buffer::*f)() const) 92 void addMapping(const QByteArray &name, bool (Buffer::*f)() const)
90 { 93 {
91 addMapping(name, [f](Buffer const *buffer) -> QVariant { 94 addMapping(name, [f](Buffer const *buffer) -> QVariant { return propertyToVariant<T>((buffer->*f)()); });
92 return propertyToVariant<T>((buffer->*f)());
93 });
94 } 95 }
95 96
96 template <typename T, typename Buffer> 97 template <typename T, typename Buffer>
97 void addMapping(const QByteArray &name, const flatbuffers::Vector<uint8_t> * (Buffer::*f)() const) 98 void addMapping(const QByteArray &name, const flatbuffers::Vector<uint8_t> *(Buffer::*f)() const)
98 { 99 {
99 addMapping(name, [f](Buffer const *buffer) -> QVariant { 100 addMapping(name, [f](Buffer const *buffer) -> QVariant { return propertyToVariant<T>((buffer->*f)()); });
100 return propertyToVariant<T>((buffer->*f)());
101 });
102 } 101 }
103 102
104private: 103private:
105 QHash<QByteArray, std::function<QVariant(BufferType const *)> > mReadAccessors; 104 QHash<QByteArray, std::function<QVariant(BufferType const *)>> mReadAccessors;
106}; 105};
107 106
108template<typename BufferBuilder> 107template <typename BufferBuilder>
109class WritePropertyMapper 108class WritePropertyMapper
110{ 109{
111public: 110public:
112 virtual ~WritePropertyMapper(){}; 111 virtual ~WritePropertyMapper(){};
113 112
114 virtual void setProperty(const QByteArray &key, const QVariant &value, QList<std::function<void(BufferBuilder &)> > &builderCalls, flatbuffers::FlatBufferBuilder &fbb) const 113 virtual void setProperty(const QByteArray &key, const QVariant &value, QList<std::function<void(BufferBuilder &)>> &builderCalls, flatbuffers::FlatBufferBuilder &fbb) const
115 { 114 {
116 if (mWriteAccessors.contains(key)) { 115 if (mWriteAccessors.contains(key)) {
117 auto accessor = mWriteAccessors.value(key); 116 auto accessor = mWriteAccessors.value(key);
118 builderCalls << accessor(value, fbb); 117 builderCalls << accessor(value, fbb);
119 } 118 }
120 } 119 }
121 bool hasMapping(const QByteArray &key) const { return mWriteAccessors.contains(key); } 120 bool hasMapping(const QByteArray &key) const
122 void addMapping(const QByteArray &property, const std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> &mapping) { 121 {
122 return mWriteAccessors.contains(key);
123 }
124 void addMapping(const QByteArray &property, const std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> &mapping)
125 {
123 mWriteAccessors.insert(property, mapping); 126 mWriteAccessors.insert(property, mapping);
124 } 127 }
125 128
@@ -127,9 +130,7 @@ public:
127 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(uint8_t)) 130 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(uint8_t))
128 { 131 {
129 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { 132 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> {
130 return [value, f](BufferBuilder &builder) { 133 return [value, f](BufferBuilder &builder) { (builder.*f)(value.value<T>()); };
131 (builder.*f)(value.value<T>());
132 };
133 }); 134 });
134 } 135 }
135 136
@@ -137,9 +138,7 @@ public:
137 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(bool)) 138 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(bool))
138 { 139 {
139 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { 140 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> {
140 return [value, f](BufferBuilder &builder) { 141 return [value, f](BufferBuilder &builder) { (builder.*f)(value.value<T>()); };
141 (builder.*f)(value.value<T>());
142 };
143 }); 142 });
144 } 143 }
145 144
@@ -148,23 +147,19 @@ public:
148 { 147 {
149 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { 148 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> {
150 auto offset = variantToProperty<T>(value, fbb); 149 auto offset = variantToProperty<T>(value, fbb);
151 return [offset, f](BufferBuilder &builder) { 150 return [offset, f](BufferBuilder &builder) { (builder.*f)(offset); };
152 (builder.*f)(offset);
153 };
154 }); 151 });
155 } 152 }
156 153
157 template <typename T> 154 template <typename T>
158 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(flatbuffers::Offset<flatbuffers::Vector<uint8_t> >)) 155 void addMapping(const QByteArray &name, void (BufferBuilder::*f)(flatbuffers::Offset<flatbuffers::Vector<uint8_t>>))
159 { 156 {
160 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> { 157 addMapping(name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(BufferBuilder &)> {
161 auto offset = variantToProperty<T>(value, fbb); 158 auto offset = variantToProperty<T>(value, fbb);
162 return [offset, f](BufferBuilder &builder) { 159 return [offset, f](BufferBuilder &builder) { (builder.*f)(offset); };
163 (builder.*f)(offset);
164 };
165 }); 160 });
166 } 161 }
162
167private: 163private:
168 QHash<QByteArray, std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> > mWriteAccessors; 164 QHash<QByteArray, std::function<std::function<void(BufferBuilder &)>(const QVariant &, flatbuffers::FlatBufferBuilder &)>> mWriteAccessors;
169}; 165};
170
diff --git a/common/query.h b/common/query.h
index 60c5630..3a56c9f 100644
--- a/common/query.h
+++ b/common/query.h
@@ -32,7 +32,8 @@ namespace Sink {
32class Query 32class Query
33{ 33{
34public: 34public:
35 enum Flag { 35 enum Flag
36 {
36 /** Leave the query running an contiously update the result set. */ 37 /** Leave the query running an contiously update the result set. */
37 LiveQuery 38 LiveQuery
38 }; 39 };
@@ -102,11 +103,11 @@ public:
102 return query; 103 return query;
103 } 104 }
104 105
105 Query(Flags flags = Flags()) 106 Query(Flags flags = Flags()) : limit(0)
106 : limit(0) 107 {
107 {} 108 }
108 109
109 Query& operator+=(const Query& rhs) 110 Query &operator+=(const Query &rhs)
110 { 111 {
111 resources += rhs.resources; 112 resources += rhs.resources;
112 ids += rhs.ids; 113 ids += rhs.ids;
@@ -121,7 +122,7 @@ public:
121 return *this; 122 return *this;
122 } 123 }
123 124
124 friend Query operator+(Query lhs, const Query& rhs) 125 friend Query operator+(Query lhs, const Query &rhs)
125 { 126 {
126 lhs += rhs; 127 lhs += rhs;
127 return lhs; 128 return lhs;
@@ -136,7 +137,6 @@ public:
136 bool liveQuery; 137 bool liveQuery;
137 int limit; 138 int limit;
138}; 139};
139
140} 140}
141 141
142Q_DECLARE_OPERATORS_FOR_FLAGS(Sink::Query::Flags) 142Q_DECLARE_OPERATORS_FOR_FLAGS(Sink::Query::Flags)
diff --git a/common/queryrunner.cpp b/common/queryrunner.cpp
index 5ac1344..c150159 100644
--- a/common/queryrunner.cpp
+++ b/common/queryrunner.cpp
@@ -39,11 +39,12 @@ using namespace Sink;
39 * This is a worker object that can be moved to a thread to execute the query. 39 * This is a worker object that can be moved to a thread to execute the query.
40 * The only interaction point is the ResultProvider, which handles the threadsafe reporting of the result. 40 * The only interaction point is the ResultProvider, which handles the threadsafe reporting of the result.
41 */ 41 */
42template<typename DomainType> 42template <typename DomainType>
43class QueryWorker : public QObject 43class QueryWorker : public QObject
44{ 44{
45public: 45public:
46 QueryWorker(const Sink::Query &query, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &, const QByteArray &bufferType, const QueryRunnerBase::ResultTransformation &transformation); 46 QueryWorker(const Sink::Query &query, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &, const QByteArray &bufferType,
47 const QueryRunnerBase::ResultTransformation &transformation);
47 virtual ~QueryWorker(); 48 virtual ~QueryWorker();
48 49
49 qint64 executeIncrementalQuery(const Sink::Query &query, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider); 50 qint64 executeIncrementalQuery(const Sink::Query &query, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider);
@@ -52,14 +53,17 @@ public:
52private: 53private:
53 void replaySet(ResultSet &resultSet, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, const QList<QByteArray> &properties, int offset, int batchSize); 54 void replaySet(ResultSet &resultSet, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, const QList<QByteArray> &properties, int offset, int batchSize);
54 55
55 void readEntity(const Sink::Storage::NamedDatabase &db, const QByteArray &key, const std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> &resultCallback); 56 void readEntity(const Sink::Storage::NamedDatabase &db, const QByteArray &key,
57 const std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> &resultCallback);
56 58
57 ResultSet loadInitialResultSet(const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters, QByteArray &remainingSorting); 59 ResultSet loadInitialResultSet(const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters, QByteArray &remainingSorting);
58 ResultSet loadIncrementalResultSet(qint64 baseRevision, const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters); 60 ResultSet loadIncrementalResultSet(qint64 baseRevision, const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters);
59 61
60 ResultSet filterAndSortSet(ResultSet &resultSet, const std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Sink::Storage::NamedDatabase &db, bool initialQuery, const QByteArray &sortProperty); 62 ResultSet filterAndSortSet(ResultSet &resultSet, const std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter,
63 const Sink::Storage::NamedDatabase &db, bool initialQuery, const QByteArray &sortProperty);
61 std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> getFilter(const QSet<QByteArray> remainingFilters, const Sink::Query &query); 64 std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> getFilter(const QSet<QByteArray> remainingFilters, const Sink::Query &query);
62 qint64 load(const Sink::Query &query, const std::function<ResultSet(Sink::Storage::Transaction &, QSet<QByteArray> &, QByteArray &)> &baseSetRetriever, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, bool initialQuery, int offset, int batchSize); 65 qint64 load(const Sink::Query &query, const std::function<ResultSet(Sink::Storage::Transaction &, QSet<QByteArray> &, QByteArray &)> &baseSetRetriever,
66 Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, bool initialQuery, int offset, int batchSize);
63 67
64private: 68private:
65 QueryRunnerBase::ResultTransformation mResultTransformation; 69 QueryRunnerBase::ResultTransformation mResultTransformation;
@@ -70,176 +74,171 @@ private:
70}; 74};
71 75
72 76
73template<class DomainType> 77template <class DomainType>
74QueryRunner<DomainType>::QueryRunner(const Sink::Query &query, const Sink::ResourceAccessInterface::Ptr &resourceAccess, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &factory, const QByteArray &bufferType) 78QueryRunner<DomainType>::QueryRunner(const Sink::Query &query, const Sink::ResourceAccessInterface::Ptr &resourceAccess, const QByteArray &instanceIdentifier,
75 : QueryRunnerBase(), 79 const DomainTypeAdaptorFactoryInterface::Ptr &factory, const QByteArray &bufferType)
76 mResourceAccess(resourceAccess), 80 : QueryRunnerBase(), mResourceAccess(resourceAccess), mResultProvider(new ResultProvider<typename DomainType::Ptr>), mOffset(0), mBatchSize(query.limit)
77 mResultProvider(new ResultProvider<typename DomainType::Ptr>),
78 mOffset(0),
79 mBatchSize(query.limit)
80{ 81{
81 Trace() << "Starting query"; 82 Trace() << "Starting query";
82 if (query.limit && query.sortProperty.isEmpty()) { 83 if (query.limit && query.sortProperty.isEmpty()) {
83 Warning() << "A limited query without sorting is typically a bad idea."; 84 Warning() << "A limited query without sorting is typically a bad idea.";
84 } 85 }
85 //We delegate loading of initial data to the result provider, os it can decide for itself what it needs to load. 86 // We delegate loading of initial data to the result provider, os it can decide for itself what it needs to load.
86 mResultProvider->setFetcher([=](const typename DomainType::Ptr &parent) { 87 mResultProvider->setFetcher([=](const typename DomainType::Ptr &parent) {
87 Trace() << "Running fetcher. Offset: " << mOffset << " Batchsize: " << mBatchSize; 88 Trace() << "Running fetcher. Offset: " << mOffset << " Batchsize: " << mBatchSize;
88 auto resultProvider = mResultProvider; 89 auto resultProvider = mResultProvider;
89 async::run<qint64>([=]() -> qint64 { 90 async::run<qint64>([=]() -> qint64 {
90 QueryWorker<DomainType> worker(query, instanceIdentifier, factory, bufferType, mResultTransformation); 91 QueryWorker<DomainType> worker(query, instanceIdentifier, factory, bufferType, mResultTransformation);
91 const qint64 newRevision = worker.executeInitialQuery(query, parent, *resultProvider, mOffset, mBatchSize); 92 const qint64 newRevision = worker.executeInitialQuery(query, parent, *resultProvider, mOffset, mBatchSize);
92 return newRevision; 93 return newRevision;
93 }) 94 })
94 .template then<void, qint64>([query, this](qint64 newRevision) { 95 .template then<void, qint64>([query, this](qint64 newRevision) {
95 mOffset += mBatchSize; 96 mOffset += mBatchSize;
96 //Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise. 97 // Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise.
97 if (query.liveQuery) { 98 if (query.liveQuery) {
98 mResourceAccess->sendRevisionReplayedCommand(newRevision); 99 mResourceAccess->sendRevisionReplayedCommand(newRevision);
99 } 100 }
100 }).exec(); 101 })
102 .exec();
101 }); 103 });
102 104
103 // In case of a live query we keep the runner for as long alive as the result provider exists 105 // In case of a live query we keep the runner for as long alive as the result provider exists
104 if (query.liveQuery) { 106 if (query.liveQuery) {
105 //Incremental updates are always loaded directly, leaving it up to the result to discard the changes if they are not interesting 107 // Incremental updates are always loaded directly, leaving it up to the result to discard the changes if they are not interesting
106 setQuery([=] () -> KAsync::Job<void> { 108 setQuery([=]() -> KAsync::Job<void> {
107 auto resultProvider = mResultProvider; 109 auto resultProvider = mResultProvider;
108 return async::run<qint64>([=]() -> qint64 { 110 return async::run<qint64>([=]() -> qint64 {
109 QueryWorker<DomainType> worker(query, instanceIdentifier, factory, bufferType, mResultTransformation); 111 QueryWorker<DomainType> worker(query, instanceIdentifier, factory, bufferType, mResultTransformation);
110 const qint64 newRevision = worker.executeIncrementalQuery(query, *resultProvider); 112 const qint64 newRevision = worker.executeIncrementalQuery(query, *resultProvider);
111 return newRevision; 113 return newRevision;
112 }) 114 })
113 .template then<void, qint64>([query, this](qint64 newRevision) { 115 .template then<void, qint64>([query, this](qint64 newRevision) {
114 //Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise. 116 // Only send the revision replayed information if we're connected to the resource, there's no need to start the resource otherwise.
115 mResourceAccess->sendRevisionReplayedCommand(newRevision); 117 mResourceAccess->sendRevisionReplayedCommand(newRevision);
116 }); 118 });
117 }); 119 });
118 //Ensure the connection is open, if it wasn't already opened 120 // Ensure the connection is open, if it wasn't already opened
119 //TODO If we are not connected already, we have to check for the latest revision once connected, otherwise we could miss some updates 121 // TODO If we are not connected already, we have to check for the latest revision once connected, otherwise we could miss some updates
120 mResourceAccess->open(); 122 mResourceAccess->open();
121 QObject::connect(mResourceAccess.data(), &Sink::ResourceAccess::revisionChanged, this, &QueryRunner::revisionChanged); 123 QObject::connect(mResourceAccess.data(), &Sink::ResourceAccess::revisionChanged, this, &QueryRunner::revisionChanged);
122 } 124 }
123} 125}
124 126
125template<class DomainType> 127template <class DomainType>
126QueryRunner<DomainType>::~QueryRunner() 128QueryRunner<DomainType>::~QueryRunner()
127{ 129{
128 Trace() << "Stopped query"; 130 Trace() << "Stopped query";
129} 131}
130 132
131template<class DomainType> 133template <class DomainType>
132void QueryRunner<DomainType>::setResultTransformation(const ResultTransformation &transformation) 134void QueryRunner<DomainType>::setResultTransformation(const ResultTransformation &transformation)
133{ 135{
134 mResultTransformation = transformation; 136 mResultTransformation = transformation;
135} 137}
136 138
137template<class DomainType> 139template <class DomainType>
138typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr QueryRunner<DomainType>::emitter() 140typename Sink::ResultEmitter<typename DomainType::Ptr>::Ptr QueryRunner<DomainType>::emitter()
139{ 141{
140 return mResultProvider->emitter(); 142 return mResultProvider->emitter();
141} 143}
142 144
143 145
144
145static inline ResultSet fullScan(const Sink::Storage::Transaction &transaction, const QByteArray &bufferType) 146static inline ResultSet fullScan(const Sink::Storage::Transaction &transaction, const QByteArray &bufferType)
146{ 147{
147 //TODO use a result set with an iterator, to read values on demand 148 // TODO use a result set with an iterator, to read values on demand
148 QVector<QByteArray> keys; 149 QVector<QByteArray> keys;
149 Storage::mainDatabase(transaction, bufferType).scan(QByteArray(), [&](const QByteArray &key, const QByteArray &value) -> bool { 150 Storage::mainDatabase(transaction, bufferType)
150 //Skip internals 151 .scan(QByteArray(),
151 if (Sink::Storage::isInternalKey(key)) { 152 [&](const QByteArray &key, const QByteArray &value) -> bool {
152 return true; 153 // Skip internals
153 } 154 if (Sink::Storage::isInternalKey(key)) {
154 keys << Sink::Storage::uidFromKey(key); 155 return true;
155 return true; 156 }
156 }, 157 keys << Sink::Storage::uidFromKey(key);
157 [](const Sink::Storage::Error &error) { 158 return true;
158 Warning() << "Error during query: " << error.message; 159 },
159 }); 160 [](const Sink::Storage::Error &error) { Warning() << "Error during query: " << error.message; });
160 161
161 Trace() << "Full scan retrieved " << keys.size() << " results."; 162 Trace() << "Full scan retrieved " << keys.size() << " results.";
162 return ResultSet(keys); 163 return ResultSet(keys);
163} 164}
164 165
165 166
166template<class DomainType> 167template <class DomainType>
167QueryWorker<DomainType>::QueryWorker(const Sink::Query &query, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &factory, const QByteArray &bufferType, const QueryRunnerBase::ResultTransformation &transformation) 168QueryWorker<DomainType>::QueryWorker(const Sink::Query &query, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &factory,
168 : QObject(), 169 const QByteArray &bufferType, const QueryRunnerBase::ResultTransformation &transformation)
169 mResultTransformation(transformation), 170 : QObject(), mResultTransformation(transformation), mDomainTypeAdaptorFactory(factory), mResourceInstanceIdentifier(instanceIdentifier), mBufferType(bufferType), mQuery(query)
170 mDomainTypeAdaptorFactory(factory),
171 mResourceInstanceIdentifier(instanceIdentifier),
172 mBufferType(bufferType),
173 mQuery(query)
174{ 171{
175 Trace() << "Starting query worker"; 172 Trace() << "Starting query worker";
176} 173}
177 174
178template<class DomainType> 175template <class DomainType>
179QueryWorker<DomainType>::~QueryWorker() 176QueryWorker<DomainType>::~QueryWorker()
180{ 177{
181 Trace() << "Stopped query worker"; 178 Trace() << "Stopped query worker";
182} 179}
183 180
184template<class DomainType> 181template <class DomainType>
185void QueryWorker<DomainType>::replaySet(ResultSet &resultSet, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, const QList<QByteArray> &properties, int offset, int batchSize) 182void QueryWorker<DomainType>::replaySet(ResultSet &resultSet, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, const QList<QByteArray> &properties, int offset, int batchSize)
186{ 183{
187 Trace() << "Skipping over " << offset << " results"; 184 Trace() << "Skipping over " << offset << " results";
188 resultSet.skip(offset); 185 resultSet.skip(offset);
189 int counter; 186 int counter;
190 for (counter = 0; !batchSize || (counter < batchSize); counter++) { 187 for (counter = 0; !batchSize || (counter < batchSize); counter++) {
191 const bool ret = resultSet.next([this, &resultProvider, &counter, &properties, batchSize](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation operation) -> bool { 188 const bool ret =
192 //FIXME allow maildir resource to set the mimeMessage property 189 resultSet.next([this, &resultProvider, &counter, &properties, batchSize](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation operation) -> bool {
193 auto valueCopy = Sink::ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<DomainType>(*value, properties).template staticCast<DomainType>(); 190 // FIXME allow maildir resource to set the mimeMessage property
194 if (mResultTransformation) { 191 auto valueCopy = Sink::ApplicationDomain::ApplicationDomainType::getInMemoryRepresentation<DomainType>(*value, properties).template staticCast<DomainType>();
195 mResultTransformation(*valueCopy); 192 if (mResultTransformation) {
196 } 193 mResultTransformation(*valueCopy);
197 switch (operation) { 194 }
198 case Sink::Operation_Creation: 195 switch (operation) {
199 // Trace() << "Got creation"; 196 case Sink::Operation_Creation:
200 resultProvider.add(valueCopy); 197 // Trace() << "Got creation";
201 break; 198 resultProvider.add(valueCopy);
202 case Sink::Operation_Modification: 199 break;
203 // Trace() << "Got modification"; 200 case Sink::Operation_Modification:
204 resultProvider.modify(valueCopy); 201 // Trace() << "Got modification";
205 break; 202 resultProvider.modify(valueCopy);
206 case Sink::Operation_Removal: 203 break;
207 // Trace() << "Got removal"; 204 case Sink::Operation_Removal:
208 resultProvider.remove(valueCopy); 205 // Trace() << "Got removal";
209 break; 206 resultProvider.remove(valueCopy);
210 } 207 break;
211 return true; 208 }
212 }); 209 return true;
210 });
213 if (!ret) { 211 if (!ret) {
214 break; 212 break;
215 } 213 }
216 }; 214 };
217 Trace() << "Replayed " << counter << " results." << "Limit " << batchSize; 215 Trace() << "Replayed " << counter << " results."
216 << "Limit " << batchSize;
218} 217}
219 218
220template<class DomainType> 219template <class DomainType>
221void QueryWorker<DomainType>::readEntity(const Sink::Storage::NamedDatabase &db, const QByteArray &key, const std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> &resultCallback) 220void QueryWorker<DomainType>::readEntity(const Sink::Storage::NamedDatabase &db, const QByteArray &key,
221 const std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> &resultCallback)
222{ 222{
223 //This only works for a 1:1 mapping of resource to domain types. 223 // This only works for a 1:1 mapping of resource to domain types.
224 //Not i.e. for tags that are stored as flags in each entity of an imap store. 224 // Not i.e. for tags that are stored as flags in each entity of an imap store.
225 //additional properties that don't have a 1:1 mapping (such as separately stored tags), 225 // additional properties that don't have a 1:1 mapping (such as separately stored tags),
226 //could be added to the adaptor. 226 // could be added to the adaptor.
227 db.findLatest(key, [=](const QByteArray &key, const QByteArray &value) -> bool { 227 db.findLatest(key,
228 Sink::EntityBuffer buffer(value.data(), value.size()); 228 [=](const QByteArray &key, const QByteArray &value) -> bool {
229 const Sink::Entity &entity = buffer.entity(); 229 Sink::EntityBuffer buffer(value.data(), value.size());
230 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata()); 230 const Sink::Entity &entity = buffer.entity();
231 const qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1; 231 const auto metadataBuffer = Sink::EntityBuffer::readBuffer<Sink::Metadata>(entity.metadata());
232 const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation; 232 const qint64 revision = metadataBuffer ? metadataBuffer->revision() : -1;
233 auto adaptor = mDomainTypeAdaptorFactory->createAdaptor(entity); 233 const auto operation = metadataBuffer ? metadataBuffer->operation() : Sink::Operation_Creation;
234 resultCallback(DomainType::Ptr::create(mResourceInstanceIdentifier, Sink::Storage::uidFromKey(key), revision, adaptor), operation); 234 auto adaptor = mDomainTypeAdaptorFactory->createAdaptor(entity);
235 return false; 235 resultCallback(DomainType::Ptr::create(mResourceInstanceIdentifier, Sink::Storage::uidFromKey(key), revision, adaptor), operation);
236 }, 236 return false;
237 [](const Sink::Storage::Error &error) { 237 },
238 Warning() << "Error during query: " << error.message; 238 [](const Sink::Storage::Error &error) { Warning() << "Error during query: " << error.message; });
239 });
240} 239}
241 240
242template<class DomainType> 241template <class DomainType>
243ResultSet QueryWorker<DomainType>::loadInitialResultSet(const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters, QByteArray &remainingSorting) 242ResultSet QueryWorker<DomainType>::loadInitialResultSet(const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters, QByteArray &remainingSorting)
244{ 243{
245 if (!query.ids.isEmpty()) { 244 if (!query.ids.isEmpty()) {
@@ -253,15 +252,15 @@ ResultSet QueryWorker<DomainType>::loadInitialResultSet(const Sink::Query &query
253 remainingSorting = query.sortProperty; 252 remainingSorting = query.sortProperty;
254 } 253 }
255 254
256 //We do a full scan if there were no indexes available to create the initial set. 255 // We do a full scan if there were no indexes available to create the initial set.
257 if (appliedFilters.isEmpty()) { 256 if (appliedFilters.isEmpty()) {
258 //TODO this should be replaced by an index lookup as well 257 // TODO this should be replaced by an index lookup as well
259 resultSet = fullScan(transaction, mBufferType); 258 resultSet = fullScan(transaction, mBufferType);
260 } 259 }
261 return resultSet; 260 return resultSet;
262} 261}
263 262
264template<class DomainType> 263template <class DomainType>
265ResultSet QueryWorker<DomainType>::loadIncrementalResultSet(qint64 baseRevision, const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters) 264ResultSet QueryWorker<DomainType>::loadIncrementalResultSet(qint64 baseRevision, const Sink::Query &query, Sink::Storage::Transaction &transaction, QSet<QByteArray> &remainingFilters)
266{ 265{
267 const auto bufferType = mBufferType; 266 const auto bufferType = mBufferType;
@@ -269,13 +268,13 @@ ResultSet QueryWorker<DomainType>::loadIncrementalResultSet(qint64 baseRevision,
269 remainingFilters = query.propertyFilter.keys().toSet(); 268 remainingFilters = query.propertyFilter.keys().toSet();
270 return ResultSet([bufferType, revisionCounter, &transaction]() -> QByteArray { 269 return ResultSet([bufferType, revisionCounter, &transaction]() -> QByteArray {
271 const qint64 topRevision = Sink::Storage::maxRevision(transaction); 270 const qint64 topRevision = Sink::Storage::maxRevision(transaction);
272 //Spit out the revision keys one by one. 271 // Spit out the revision keys one by one.
273 while (*revisionCounter <= topRevision) { 272 while (*revisionCounter <= topRevision) {
274 const auto uid = Sink::Storage::getUidFromRevision(transaction, *revisionCounter); 273 const auto uid = Sink::Storage::getUidFromRevision(transaction, *revisionCounter);
275 const auto type = Sink::Storage::getTypeFromRevision(transaction, *revisionCounter); 274 const auto type = Sink::Storage::getTypeFromRevision(transaction, *revisionCounter);
276 // Trace() << "Revision" << *revisionCounter << type << uid; 275 // Trace() << "Revision" << *revisionCounter << type << uid;
277 if (type != bufferType) { 276 if (type != bufferType) {
278 //Skip revision 277 // Skip revision
279 *revisionCounter += 1; 278 *revisionCounter += 1;
280 continue; 279 continue;
281 } 280 }
@@ -284,45 +283,47 @@ ResultSet QueryWorker<DomainType>::loadIncrementalResultSet(qint64 baseRevision,
284 return key; 283 return key;
285 } 284 }
286 Trace() << "Finished reading incremental result set:" << *revisionCounter; 285 Trace() << "Finished reading incremental result set:" << *revisionCounter;
287 //We're done 286 // We're done
288 return QByteArray(); 287 return QByteArray();
289 }); 288 });
290} 289}
291 290
292template<class DomainType> 291template <class DomainType>
293ResultSet QueryWorker<DomainType>::filterAndSortSet(ResultSet &resultSet, const std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter, const Sink::Storage::NamedDatabase &db, bool initialQuery, const QByteArray &sortProperty) 292ResultSet QueryWorker<DomainType>::filterAndSortSet(ResultSet &resultSet, const std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> &filter,
293 const Sink::Storage::NamedDatabase &db, bool initialQuery, const QByteArray &sortProperty)
294{ 294{
295 const bool sortingRequired = !sortProperty.isEmpty(); 295 const bool sortingRequired = !sortProperty.isEmpty();
296 if (initialQuery && sortingRequired) { 296 if (initialQuery && sortingRequired) {
297 Trace() << "Sorting the resultset in memory according to property: " << sortProperty; 297 Trace() << "Sorting the resultset in memory according to property: " << sortProperty;
298 //Sort the complete set by reading the sort property and filling into a sorted map 298 // Sort the complete set by reading the sort property and filling into a sorted map
299 auto sortedMap = QSharedPointer<QMap<QByteArray, QByteArray>>::create(); 299 auto sortedMap = QSharedPointer<QMap<QByteArray, QByteArray>>::create();
300 while (resultSet.next()) { 300 while (resultSet.next()) {
301 //readEntity is only necessary if we actually want to filter or know the operation type (but not a big deal if we do it always I guess) 301 // readEntity is only necessary if we actually want to filter or know the operation type (but not a big deal if we do it always I guess)
302 readEntity(db, resultSet.id(), [this, filter, initialQuery, sortedMap, sortProperty, &resultSet](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Sink::Operation operation) { 302 readEntity(db, resultSet.id(),
303 //We're not interested in removals during the initial query 303 [this, filter, initialQuery, sortedMap, sortProperty, &resultSet](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Sink::Operation operation) {
304 if ((operation != Sink::Operation_Removal) && filter(domainObject)) { 304 // We're not interested in removals during the initial query
305 if (!sortProperty.isEmpty()) { 305 if ((operation != Sink::Operation_Removal) && filter(domainObject)) {
306 const auto sortValue = domainObject->getProperty(sortProperty); 306 if (!sortProperty.isEmpty()) {
307 if (sortValue.type() == QVariant::DateTime) { 307 const auto sortValue = domainObject->getProperty(sortProperty);
308 sortedMap->insert(QByteArray::number(std::numeric_limits<unsigned int>::max() - sortValue.toDateTime().toTime_t()), domainObject->identifier()); 308 if (sortValue.type() == QVariant::DateTime) {
309 sortedMap->insert(QByteArray::number(std::numeric_limits<unsigned int>::max() - sortValue.toDateTime().toTime_t()), domainObject->identifier());
310 } else {
311 sortedMap->insert(sortValue.toString().toLatin1(), domainObject->identifier());
312 }
309 } else { 313 } else {
310 sortedMap->insert(sortValue.toString().toLatin1(), domainObject->identifier()); 314 sortedMap->insert(domainObject->identifier(), domainObject->identifier());
311 } 315 }
312 } else {
313 sortedMap->insert(domainObject->identifier(), domainObject->identifier());
314 } 316 }
315 } 317 });
316 });
317 } 318 }
318 319
319 Trace() << "Sorted " << sortedMap->size() << " values."; 320 Trace() << "Sorted " << sortedMap->size() << " values.";
320 auto iterator = QSharedPointer<QMapIterator<QByteArray, QByteArray> >::create(*sortedMap); 321 auto iterator = QSharedPointer<QMapIterator<QByteArray, QByteArray>>::create(*sortedMap);
321 ResultSet::ValueGenerator generator = [this, iterator, sortedMap, &db, filter, initialQuery](std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> callback) -> bool { 322 ResultSet::ValueGenerator generator = [this, iterator, sortedMap, &db, filter, initialQuery](
323 std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> callback) -> bool {
322 if (iterator->hasNext()) { 324 if (iterator->hasNext()) {
323 readEntity(db, iterator->next().value(), [this, filter, callback, initialQuery](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Sink::Operation operation) { 325 readEntity(db, iterator->next().value(), [this, filter, callback, initialQuery](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject,
324 callback(domainObject, Sink::Operation_Creation); 326 Sink::Operation operation) { callback(domainObject, Sink::Operation_Creation); });
325 });
326 return true; 327 return true;
327 } 328 }
328 return false; 329 return false;
@@ -336,19 +337,21 @@ ResultSet QueryWorker<DomainType>::filterAndSortSet(ResultSet &resultSet, const
336 return ResultSet(generator, skip); 337 return ResultSet(generator, skip);
337 } else { 338 } else {
338 auto resultSetPtr = QSharedPointer<ResultSet>::create(resultSet); 339 auto resultSetPtr = QSharedPointer<ResultSet>::create(resultSet);
339 ResultSet::ValueGenerator generator = [this, resultSetPtr, &db, filter, initialQuery](std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> callback) -> bool { 340 ResultSet::ValueGenerator generator = [this, resultSetPtr, &db, filter, initialQuery](
341 std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)> callback) -> bool {
340 if (resultSetPtr->next()) { 342 if (resultSetPtr->next()) {
341 //readEntity is only necessary if we actually want to filter or know the operation type (but not a big deal if we do it always I guess) 343 // readEntity is only necessary if we actually want to filter or know the operation type (but not a big deal if we do it always I guess)
342 readEntity(db, resultSetPtr->id(), [this, filter, callback, initialQuery](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Sink::Operation operation) { 344 readEntity(db, resultSetPtr->id(), [this, filter, callback, initialQuery](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject, Sink::Operation operation) {
343 if (initialQuery) { 345 if (initialQuery) {
344 //We're not interested in removals during the initial query 346 // We're not interested in removals during the initial query
345 if ((operation != Sink::Operation_Removal) && filter(domainObject)) { 347 if ((operation != Sink::Operation_Removal) && filter(domainObject)) {
346 //In the initial set every entity is new 348 // In the initial set every entity is new
347 callback(domainObject, Sink::Operation_Creation); 349 callback(domainObject, Sink::Operation_Creation);
348 } } else { 350 }
349 //Always remove removals, they probably don't match due to non-available properties 351 } else {
352 // Always remove removals, they probably don't match due to non-available properties
350 if ((operation == Sink::Operation_Removal) || filter(domainObject)) { 353 if ((operation == Sink::Operation_Removal) || filter(domainObject)) {
351 //TODO only replay if this is in the currently visible set (or just always replay, worst case we have a couple to many results) 354 // TODO only replay if this is in the currently visible set (or just always replay, worst case we have a couple to many results)
352 callback(domainObject, operation); 355 callback(domainObject, operation);
353 } 356 }
354 } 357 }
@@ -357,15 +360,14 @@ ResultSet QueryWorker<DomainType>::filterAndSortSet(ResultSet &resultSet, const
357 } 360 }
358 return false; 361 return false;
359 }; 362 };
360 auto skip = [resultSetPtr]() { 363 auto skip = [resultSetPtr]() { resultSetPtr->skip(1); };
361 resultSetPtr->skip(1);
362 };
363 return ResultSet(generator, skip); 364 return ResultSet(generator, skip);
364 } 365 }
365} 366}
366 367
367template<class DomainType> 368template <class DomainType>
368std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)> QueryWorker<DomainType>::getFilter(const QSet<QByteArray> remainingFilters, const Sink::Query &query) 369std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject)>
370QueryWorker<DomainType>::getFilter(const QSet<QByteArray> remainingFilters, const Sink::Query &query)
369{ 371{
370 return [remainingFilters, query](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool { 372 return [remainingFilters, query](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &domainObject) -> bool {
371 if (!query.ids.isEmpty()) { 373 if (!query.ids.isEmpty()) {
@@ -376,7 +378,7 @@ std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &do
376 for (const auto &filterProperty : remainingFilters) { 378 for (const auto &filterProperty : remainingFilters) {
377 const auto property = domainObject->getProperty(filterProperty); 379 const auto property = domainObject->getProperty(filterProperty);
378 if (property.isValid()) { 380 if (property.isValid()) {
379 //TODO implement other comparison operators than equality 381 // TODO implement other comparison operators than equality
380 if (property != query.propertyFilter.value(filterProperty)) { 382 if (property != query.propertyFilter.value(filterProperty)) {
381 Trace() << "Filtering entity due to property mismatch on filter: " << filterProperty << property << ":" << query.propertyFilter.value(filterProperty); 383 Trace() << "Filtering entity due to property mismatch on filter: " << filterProperty << property << ":" << query.propertyFilter.value(filterProperty);
382 return false; 384 return false;
@@ -389,16 +391,15 @@ std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &do
389 }; 391 };
390} 392}
391 393
392template<class DomainType> 394template <class DomainType>
393qint64 QueryWorker<DomainType>::load(const Sink::Query &query, const std::function<ResultSet(Sink::Storage::Transaction &, QSet<QByteArray> &, QByteArray &)> &baseSetRetriever, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, bool initialQuery, int offset, int batchSize) 395qint64 QueryWorker<DomainType>::load(const Sink::Query &query, const std::function<ResultSet(Sink::Storage::Transaction &, QSet<QByteArray> &, QByteArray &)> &baseSetRetriever,
396 Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, bool initialQuery, int offset, int batchSize)
394{ 397{
395 QTime time; 398 QTime time;
396 time.start(); 399 time.start();
397 400
398 Sink::Storage storage(Sink::storageLocation(), mResourceInstanceIdentifier); 401 Sink::Storage storage(Sink::storageLocation(), mResourceInstanceIdentifier);
399 storage.setDefaultErrorHandler([](const Sink::Storage::Error &error) { 402 storage.setDefaultErrorHandler([](const Sink::Storage::Error &error) { Warning() << "Error during query: " << error.store << error.message; });
400 Warning() << "Error during query: " << error.store << error.message;
401 });
402 auto transaction = storage.createTransaction(Sink::Storage::ReadOnly); 403 auto transaction = storage.createTransaction(Sink::Storage::ReadOnly);
403 auto db = Storage::mainDatabase(transaction, mBufferType); 404 auto db = Storage::mainDatabase(transaction, mBufferType);
404 405
@@ -414,7 +415,7 @@ qint64 QueryWorker<DomainType>::load(const Sink::Query &query, const std::functi
414 return Sink::Storage::maxRevision(transaction); 415 return Sink::Storage::maxRevision(transaction);
415} 416}
416 417
417template<class DomainType> 418template <class DomainType>
418qint64 QueryWorker<DomainType>::executeIncrementalQuery(const Sink::Query &query, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider) 419qint64 QueryWorker<DomainType>::executeIncrementalQuery(const Sink::Query &query, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider)
419{ 420{
420 QTime time; 421 QTime time;
@@ -429,8 +430,9 @@ qint64 QueryWorker<DomainType>::executeIncrementalQuery(const Sink::Query &query
429 return revision; 430 return revision;
430} 431}
431 432
432template<class DomainType> 433template <class DomainType>
433qint64 QueryWorker<DomainType>::executeInitialQuery(const Sink::Query &query, const typename DomainType::Ptr &parent, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, int offset, int batchsize) 434qint64 QueryWorker<DomainType>::executeInitialQuery(
435 const Sink::Query &query, const typename DomainType::Ptr &parent, Sink::ResultProviderInterface<typename DomainType::Ptr> &resultProvider, int offset, int batchsize)
434{ 436{
435 QTime time; 437 QTime time;
436 time.start(); 438 time.start();
diff --git a/common/queryrunner.h b/common/queryrunner.h
index 436e2e0..adaf297 100644
--- a/common/queryrunner.h
+++ b/common/queryrunner.h
@@ -70,18 +70,19 @@ private:
70 70
71/** 71/**
72 * A QueryRunner runs a query and updates the corresponding result set. 72 * A QueryRunner runs a query and updates the corresponding result set.
73 * 73 *
74 * The lifetime of the QueryRunner is defined by the resut set (otherwise it's doing useless work), 74 * The lifetime of the QueryRunner is defined by the resut set (otherwise it's doing useless work),
75 * and by how long a result set must be updated. If the query is one off the runner dies after the execution, 75 * and by how long a result set must be updated. If the query is one off the runner dies after the execution,
76 * otherwise it lives on the react to changes and updates the corresponding result set. 76 * otherwise it lives on the react to changes and updates the corresponding result set.
77 * 77 *
78 * QueryRunner has to keep ResourceAccess alive in order to keep getting updates. 78 * QueryRunner has to keep ResourceAccess alive in order to keep getting updates.
79 */ 79 */
80template<typename DomainType> 80template <typename DomainType>
81class QueryRunner : public QueryRunnerBase 81class QueryRunner : public QueryRunnerBase
82{ 82{
83public: 83public:
84 QueryRunner(const Sink::Query &query, const Sink::ResourceAccessInterface::Ptr &, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &, const QByteArray &bufferType); 84 QueryRunner(const Sink::Query &query, const Sink::ResourceAccessInterface::Ptr &, const QByteArray &instanceIdentifier, const DomainTypeAdaptorFactoryInterface::Ptr &,
85 const QByteArray &bufferType);
85 virtual ~QueryRunner(); 86 virtual ~QueryRunner();
86 87
87 /** 88 /**
@@ -94,9 +95,8 @@ public:
94 95
95private: 96private:
96 QSharedPointer<Sink::ResourceAccessInterface> mResourceAccess; 97 QSharedPointer<Sink::ResourceAccessInterface> mResourceAccess;
97 QSharedPointer<Sink::ResultProvider<typename DomainType::Ptr> > mResultProvider; 98 QSharedPointer<Sink::ResultProvider<typename DomainType::Ptr>> mResultProvider;
98 ResultTransformation mResultTransformation; 99 ResultTransformation mResultTransformation;
99 int mOffset; 100 int mOffset;
100 int mBatchSize; 101 int mBatchSize;
101}; 102};
102
diff --git a/common/resource.cpp b/common/resource.cpp
index 5cbb2f2..6713686 100644
--- a/common/resource.cpp
+++ b/common/resource.cpp
@@ -27,19 +27,16 @@
27 27
28#include "facadefactory.h" 28#include "facadefactory.h"
29 29
30namespace Sink 30namespace Sink {
31{
32 31
33Resource::Resource() 32Resource::Resource() : QObject(), d(0)
34 : QObject(),
35 d(0)
36{ 33{
37 Q_UNUSED(d); 34 Q_UNUSED(d);
38} 35}
39 36
40Resource::~Resource() 37Resource::~Resource()
41{ 38{
42 //delete d; 39 // delete d;
43} 40}
44 41
45void Resource::processCommand(int commandId, const QByteArray &data) 42void Resource::processCommand(int commandId, const QByteArray &data)
@@ -71,21 +68,19 @@ void Resource::removeDataFromDisk()
71class ResourceFactory::Private 68class ResourceFactory::Private
72{ 69{
73public: 70public:
74 static QHash<QString, QPointer<ResourceFactory> > s_loadedFactories; 71 static QHash<QString, QPointer<ResourceFactory>> s_loadedFactories;
75}; 72};
76 73
77QHash<QString, QPointer<ResourceFactory> > ResourceFactory::Private::s_loadedFactories; 74QHash<QString, QPointer<ResourceFactory>> ResourceFactory::Private::s_loadedFactories;
78 75
79ResourceFactory::ResourceFactory(QObject *parent) 76ResourceFactory::ResourceFactory(QObject *parent) : QObject(parent), d(0)
80 : QObject(parent),
81 d(0)
82{ 77{
83 Q_UNUSED(d); 78 Q_UNUSED(d);
84} 79}
85 80
86ResourceFactory::~ResourceFactory() 81ResourceFactory::~ResourceFactory()
87{ 82{
88 //delete d; 83 // delete d;
89} 84}
90 85
91ResourceFactory *ResourceFactory::load(const QString &resourceName) 86ResourceFactory *ResourceFactory::load(const QString &resourceName)
@@ -95,15 +90,15 @@ ResourceFactory *ResourceFactory::load(const QString &resourceName)
95 return factory; 90 return factory;
96 } 91 }
97 92
98 for (auto const &path: QCoreApplication::instance()->libraryPaths()) { 93 for (auto const &path : QCoreApplication::instance()->libraryPaths()) {
99 if (path.endsWith(QLatin1String("plugins"))) { 94 if (path.endsWith(QLatin1String("plugins"))) {
100 QDir pluginDir(path); 95 QDir pluginDir(path);
101 //TODO: centralize this so that it is easy to change centrally 96 // TODO: centralize this so that it is easy to change centrally
102 // also ref'd in cmake as ${SINK_RESOURCE_PLUGINS_PATH} 97 // also ref'd in cmake as ${SINK_RESOURCE_PLUGINS_PATH}
103 pluginDir.cd(QStringLiteral("sink")); 98 pluginDir.cd(QStringLiteral("sink"));
104 pluginDir.cd(QStringLiteral("resources")); 99 pluginDir.cd(QStringLiteral("resources"));
105 100
106 for (const QString &fileName: pluginDir.entryList(QDir::Files)) { 101 for (const QString &fileName : pluginDir.entryList(QDir::Files)) {
107 const QString path = pluginDir.absoluteFilePath(fileName); 102 const QString path = pluginDir.absoluteFilePath(fileName);
108 QPluginLoader loader(path); 103 QPluginLoader loader(path);
109 104
@@ -115,7 +110,7 @@ ResourceFactory *ResourceFactory::load(const QString &resourceName)
115 if (factory) { 110 if (factory) {
116 Private::s_loadedFactories.insert(resourceName, factory); 111 Private::s_loadedFactories.insert(resourceName, factory);
117 factory->registerFacades(FacadeFactory::instance()); 112 factory->registerFacades(FacadeFactory::instance());
118 //TODO: if we need more data on it const QJsonObject json = loader.metaData()[QStringLiteral("MetaData")].toObject(); 113 // TODO: if we need more data on it const QJsonObject json = loader.metaData()[QStringLiteral("MetaData")].toObject();
119 return factory; 114 return factory;
120 } else { 115 } else {
121 qWarning() << "Plugin for" << resourceName << "from plugin" << loader.fileName() << "produced the wrong object type:" << object; 116 qWarning() << "Plugin for" << resourceName << "from plugin" << loader.fileName() << "produced the wrong object type:" << object;
@@ -135,7 +130,7 @@ ResourceFactory *ResourceFactory::load(const QString &resourceName)
135 130
136} // namespace Sink 131} // namespace Sink
137 132
138//Ignore warning I don't know how to fix in a moc file 133// Ignore warning I don't know how to fix in a moc file
139#pragma clang diagnostic push 134#pragma clang diagnostic push
140#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast" 135#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
141#include "moc_resource.cpp" 136#include "moc_resource.cpp"
diff --git a/common/resource.h b/common/resource.h
index d0100f6..0e7cd11 100644
--- a/common/resource.h
+++ b/common/resource.h
@@ -24,8 +24,7 @@
24#include <Async/Async> 24#include <Async/Async>
25#include "notification.h" 25#include "notification.h"
26 26
27namespace Sink 27namespace Sink {
28{
29class FacadeFactory; 28class FacadeFactory;
30 29
31/** 30/**
@@ -66,7 +65,7 @@ signals:
66 65
67private: 66private:
68 class Private; 67 class Private;
69 Private * const d; 68 Private *const d;
70}; 69};
71 70
72/** 71/**
@@ -85,11 +84,9 @@ public:
85 84
86private: 85private:
87 class Private; 86 class Private;
88 Private * const d; 87 Private *const d;
89}; 88};
90 89
91} // namespace Sink 90} // namespace Sink
92 91
93Q_DECLARE_INTERFACE(Sink::ResourceFactory, "org.kde.sink.resourcefactory") 92Q_DECLARE_INTERFACE(Sink::ResourceFactory, "org.kde.sink.resourcefactory")
94
95
diff --git a/common/resourceaccess.cpp b/common/resourceaccess.cpp
index 0716ae2..c8c8189 100644
--- a/common/resourceaccess.cpp
+++ b/common/resourceaccess.cpp
@@ -53,27 +53,20 @@ static void queuedInvoke(const std::function<void()> &f, QObject *context = 0)
53{ 53{
54 auto timer = QSharedPointer<QTimer>::create(); 54 auto timer = QSharedPointer<QTimer>::create();
55 timer->setSingleShot(true); 55 timer->setSingleShot(true);
56 QObject::connect(timer.data(), &QTimer::timeout, context, [f, timer]() { 56 QObject::connect(timer.data(), &QTimer::timeout, context, [f, timer]() { f(); });
57 f();
58 });
59 timer->start(0); 57 timer->start(0);
60} 58}
61 59
62namespace Sink 60namespace Sink {
63{
64 61
65struct QueuedCommand 62struct QueuedCommand
66{ 63{
67public: 64public:
68 QueuedCommand(int commandId, const std::function<void(int, const QString &)> &callback) 65 QueuedCommand(int commandId, const std::function<void(int, const QString &)> &callback) : commandId(commandId), callback(callback)
69 : commandId(commandId), 66 {
70 callback(callback) 67 }
71 {} 68
72 69 QueuedCommand(int commandId, const QByteArray &b, const std::function<void(int, const QString &)> &callback) : commandId(commandId), buffer(b), callback(callback)
73 QueuedCommand(int commandId, const QByteArray &b, const std::function<void(int, const QString &)> &callback)
74 : commandId(commandId),
75 buffer(b),
76 callback(callback)
77 { 70 {
78 } 71 }
79 72
@@ -102,17 +95,14 @@ public:
102 QByteArray partialMessageBuffer; 95 QByteArray partialMessageBuffer;
103 QVector<QSharedPointer<QueuedCommand>> commandQueue; 96 QVector<QSharedPointer<QueuedCommand>> commandQueue;
104 QMap<uint, QSharedPointer<QueuedCommand>> pendingCommands; 97 QMap<uint, QSharedPointer<QueuedCommand>> pendingCommands;
105 QMultiMap<uint, std::function<void(int error, const QString &errorMessage)> > resultHandler; 98 QMultiMap<uint, std::function<void(int error, const QString &errorMessage)>> resultHandler;
106 QSet<uint> completeCommands; 99 QSet<uint> completeCommands;
107 uint messageId; 100 uint messageId;
108 bool openingSocket; 101 bool openingSocket;
109}; 102};
110 103
111ResourceAccess::Private::Private(const QByteArray &name, const QByteArray &instanceIdentifier, ResourceAccess *q) 104ResourceAccess::Private::Private(const QByteArray &name, const QByteArray &instanceIdentifier, ResourceAccess *q)
112 : resourceName(name), 105 : resourceName(name), resourceInstanceIdentifier(instanceIdentifier), messageId(0), openingSocket(false)
113 resourceInstanceIdentifier(instanceIdentifier),
114 messageId(0),
115 openingSocket(false)
116{ 106{
117} 107}
118 108
@@ -124,7 +114,7 @@ void ResourceAccess::Private::abortPendingOperations()
124 } 114 }
125 auto handlers = resultHandler.values(); 115 auto handlers = resultHandler.values();
126 resultHandler.clear(); 116 resultHandler.clear();
127 for(auto handler : handlers) { 117 for (auto handler : handlers) {
128 handler(1, "The resource closed unexpectedly"); 118 handler(1, "The resource closed unexpectedly");
129 } 119 }
130} 120}
@@ -132,20 +122,20 @@ void ResourceAccess::Private::abortPendingOperations()
132void ResourceAccess::Private::callCallbacks() 122void ResourceAccess::Private::callCallbacks()
133{ 123{
134 for (auto id : completeCommands) { 124 for (auto id : completeCommands) {
135 //We remove the callbacks first because the handler can kill resourceaccess directly 125 // We remove the callbacks first because the handler can kill resourceaccess directly
136 const auto callbacks = resultHandler.values(id); 126 const auto callbacks = resultHandler.values(id);
137 resultHandler.remove(id); 127 resultHandler.remove(id);
138 for(auto handler : callbacks) { 128 for (auto handler : callbacks) {
139 handler(0, QString()); 129 handler(0, QString());
140 } 130 }
141 } 131 }
142} 132}
143 133
144//Connects to server and returns connected socket on success 134// Connects to server and returns connected socket on success
145KAsync::Job<QSharedPointer<QLocalSocket> > ResourceAccess::connectToServer(const QByteArray &identifier) 135KAsync::Job<QSharedPointer<QLocalSocket>> ResourceAccess::connectToServer(const QByteArray &identifier)
146{ 136{
147 auto s = QSharedPointer<QLocalSocket>::create(); 137 auto s = QSharedPointer<QLocalSocket>::create();
148 return KAsync::start<QSharedPointer<QLocalSocket> >([identifier, s](KAsync::Future<QSharedPointer<QLocalSocket> > &future) { 138 return KAsync::start<QSharedPointer<QLocalSocket>>([identifier, s](KAsync::Future<QSharedPointer<QLocalSocket>> &future) {
149 s->setServerName(identifier); 139 s->setServerName(identifier);
150 auto context = new QObject; 140 auto context = new QObject;
151 QObject::connect(s.data(), &QLocalSocket::connected, context, [&future, &s, context]() { 141 QObject::connect(s.data(), &QLocalSocket::connected, context, [&future, &s, context]() {
@@ -154,7 +144,7 @@ KAsync::Job<QSharedPointer<QLocalSocket> > ResourceAccess::connectToServer(const
154 future.setValue(s); 144 future.setValue(s);
155 future.setFinished(); 145 future.setFinished();
156 }); 146 });
157 QObject::connect(s.data(), static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), context, [&future, context](QLocalSocket::LocalSocketError) { 147 QObject::connect(s.data(), static_cast<void (QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error), context, [&future, context](QLocalSocket::LocalSocketError) {
158 delete context; 148 delete context;
159 future.setError(-1, "Failed to connect to server."); 149 future.setError(-1, "Failed to connect to server.");
160 }); 150 });
@@ -164,66 +154,67 @@ KAsync::Job<QSharedPointer<QLocalSocket> > ResourceAccess::connectToServer(const
164 154
165KAsync::Job<void> ResourceAccess::Private::tryToConnect() 155KAsync::Job<void> ResourceAccess::Private::tryToConnect()
166{ 156{
167 //We may have a socket from the last connection leftover 157 // We may have a socket from the last connection leftover
168 socket.reset(); 158 socket.reset();
169 auto counter = QSharedPointer<int>::create(0); 159 auto counter = QSharedPointer<int>::create(0);
170 return KAsync::dowhile([this]() -> bool { 160 return KAsync::dowhile([this]() -> bool { return !socket; },
171 return !socket; 161 [this, counter](KAsync::Future<void> &future) {
172 }, 162 TracePrivate() << "Loop";
173 [this, counter](KAsync::Future<void> &future) { 163 connectToServer(resourceInstanceIdentifier)
174 TracePrivate() << "Loop"; 164 .then<void, QSharedPointer<QLocalSocket>>(
175 connectToServer(resourceInstanceIdentifier) 165 [this, &future](const QSharedPointer<QLocalSocket> &s) {
176 .then<void, QSharedPointer<QLocalSocket> >([this, &future](const QSharedPointer<QLocalSocket> &s) { 166 Q_ASSERT(s);
177 Q_ASSERT(s); 167 socket = s;
178 socket = s; 168 future.setFinished();
179 future.setFinished(); 169 },
180 }, [&future, counter, this](int errorCode, const QString &errorString) { 170 [&future, counter, this](int errorCode, const QString &errorString) {
181 static int waitTime = 10; 171 static int waitTime = 10;
182 static int timeout = 500; 172 static int timeout = 500;
183 static int maxRetries = timeout / waitTime; 173 static int maxRetries = timeout / waitTime;
184 if (*counter > maxRetries) { 174 if (*counter > maxRetries) {
185 TracePrivate() << "Giving up"; 175 TracePrivate() << "Giving up";
186 future.setError(-1, "Failed to connect to socket"); 176 future.setError(-1, "Failed to connect to socket");
187 } else { 177 } else {
188 KAsync::wait(waitTime).then<void>([&future]() { 178 KAsync::wait(waitTime).then<void>([&future]() { future.setFinished(); }).exec();
189 future.setFinished(); 179 }
190 }).exec(); 180 *counter = *counter + 1;
191 } 181 })
192 *counter = *counter + 1; 182 .exec();
193 }) 183 });
194 .exec();
195 });
196} 184}
197 185
198KAsync::Job<void> ResourceAccess::Private::initializeSocket() 186KAsync::Job<void> ResourceAccess::Private::initializeSocket()
199{ 187{
200 return KAsync::start<void>([this](KAsync::Future<void> &future) { 188 return KAsync::start<void>([this](KAsync::Future<void> &future) {
201 TracePrivate() << "Trying to connect"; 189 TracePrivate() << "Trying to connect";
202 connectToServer(resourceInstanceIdentifier).then<void, QSharedPointer<QLocalSocket> >([this, &future](const QSharedPointer<QLocalSocket> &s) { 190 connectToServer(resourceInstanceIdentifier)
203 TracePrivate() << "Connected to resource, without having to start it."; 191 .then<void, QSharedPointer<QLocalSocket>>(
204 Q_ASSERT(s); 192 [this, &future](const QSharedPointer<QLocalSocket> &s) {
205 socket = s; 193 TracePrivate() << "Connected to resource, without having to start it.";
206 future.setFinished(); 194 Q_ASSERT(s);
207 }, 195 socket = s;
208 [this, &future](int errorCode, const QString &errorString) {
209 TracePrivate() << "Failed to connect, starting resource";
210 //We failed to connect, so let's start the resource
211 QStringList args;
212 args << resourceInstanceIdentifier;
213 qint64 pid = 0;
214 if (QProcess::startDetached("sink_synchronizer", args, QDir::homePath(), &pid)) {
215 TracePrivate() << "Started resource " << pid;
216 tryToConnect()
217 .then<void>([&future]() {
218 future.setFinished(); 196 future.setFinished();
219 }, [this, &future](int errorCode, const QString &errorString) { 197 },
220 Warning() << "Failed to connect to started resource"; 198 [this, &future](int errorCode, const QString &errorString) {
221 future.setError(errorCode, errorString); 199 TracePrivate() << "Failed to connect, starting resource";
222 }).exec(); 200 // We failed to connect, so let's start the resource
223 } else { 201 QStringList args;
224 Warning() << "Failed to start resource"; 202 args << resourceInstanceIdentifier;
225 } 203 qint64 pid = 0;
226 }).exec(); 204 if (QProcess::startDetached("sink_synchronizer", args, QDir::homePath(), &pid)) {
205 TracePrivate() << "Started resource " << pid;
206 tryToConnect()
207 .then<void>([&future]() { future.setFinished(); },
208 [this, &future](int errorCode, const QString &errorString) {
209 Warning() << "Failed to connect to started resource";
210 future.setError(errorCode, errorString);
211 })
212 .exec();
213 } else {
214 Warning() << "Failed to start resource";
215 }
216 })
217 .exec();
227 }); 218 });
228} 219}
229 220
@@ -235,8 +226,7 @@ static QByteArray getResourceName(const QByteArray &instanceIdentifier)
235} 226}
236 227
237ResourceAccess::ResourceAccess(const QByteArray &resourceInstanceIdentifier) 228ResourceAccess::ResourceAccess(const QByteArray &resourceInstanceIdentifier)
238 : ResourceAccessInterface(), 229 : ResourceAccessInterface(), d(new Private(getResourceName(resourceInstanceIdentifier), resourceInstanceIdentifier, this))
239 d(new Private(getResourceName(resourceInstanceIdentifier), resourceInstanceIdentifier, this))
240{ 230{
241 Log() << "Starting access"; 231 Log() << "Starting access";
242} 232}
@@ -280,10 +270,10 @@ KAsync::Job<void> ResourceAccess::sendCommand(int commandId)
280 }); 270 });
281} 271}
282 272
283KAsync::Job<void> ResourceAccess::sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) 273KAsync::Job<void> ResourceAccess::sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb)
284{ 274{
285 //The flatbuffer is transient, but we want to store it until the job is executed 275 // The flatbuffer is transient, but we want to store it until the job is executed
286 QByteArray buffer(reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()); 276 QByteArray buffer(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
287 return KAsync::start<void>([commandId, buffer, this](KAsync::Future<void> &f) { 277 return KAsync::start<void>([commandId, buffer, this](KAsync::Future<void> &f) {
288 auto callback = [&f](int error, const QString &errorMessage) { 278 auto callback = [&f](int error, const QString &errorMessage) {
289 if (error) { 279 if (error) {
@@ -313,7 +303,7 @@ KAsync::Job<void> ResourceAccess::synchronizeResource(bool sourceSync, bool loca
313KAsync::Job<void> ResourceAccess::sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer) 303KAsync::Job<void> ResourceAccess::sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer)
314{ 304{
315 flatbuffers::FlatBufferBuilder fbb; 305 flatbuffers::FlatBufferBuilder fbb;
316 //This is the resource buffer type and not the domain type 306 // This is the resource buffer type and not the domain type
317 auto type = fbb.CreateString(resourceBufferType.constData()); 307 auto type = fbb.CreateString(resourceBufferType.constData());
318 auto delta = Sink::EntityBuffer::appendAsVector(fbb, buffer.constData(), buffer.size()); 308 auto delta = Sink::EntityBuffer::appendAsVector(fbb, buffer.constData(), buffer.size());
319 auto location = Sink::Commands::CreateCreateEntity(fbb, 0, type, delta); 309 auto location = Sink::Commands::CreateCreateEntity(fbb, 0, type, delta);
@@ -322,13 +312,14 @@ KAsync::Job<void> ResourceAccess::sendCreateCommand(const QByteArray &resourceBu
322 return sendCommand(Sink::Commands::CreateEntityCommand, fbb); 312 return sendCommand(Sink::Commands::CreateEntityCommand, fbb);
323} 313}
324 314
325KAsync::Job<void> ResourceAccess::sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer) 315KAsync::Job<void>
316ResourceAccess::sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer)
326{ 317{
327 flatbuffers::FlatBufferBuilder fbb; 318 flatbuffers::FlatBufferBuilder fbb;
328 auto entityId = fbb.CreateString(uid.constData()); 319 auto entityId = fbb.CreateString(uid.constData());
329 //This is the resource buffer type and not the domain type 320 // This is the resource buffer type and not the domain type
330 auto type = fbb.CreateString(resourceBufferType.constData()); 321 auto type = fbb.CreateString(resourceBufferType.constData());
331 //FIXME 322 // FIXME
332 auto deletions = 0; 323 auto deletions = 0;
333 auto delta = Sink::EntityBuffer::appendAsVector(fbb, buffer.constData(), buffer.size()); 324 auto delta = Sink::EntityBuffer::appendAsVector(fbb, buffer.constData(), buffer.size());
334 auto location = Sink::Commands::CreateModifyEntity(fbb, revision, entityId, deletions, type, delta); 325 auto location = Sink::Commands::CreateModifyEntity(fbb, revision, entityId, deletions, type, delta);
@@ -341,7 +332,7 @@ KAsync::Job<void> ResourceAccess::sendDeleteCommand(const QByteArray &uid, qint6
341{ 332{
342 flatbuffers::FlatBufferBuilder fbb; 333 flatbuffers::FlatBufferBuilder fbb;
343 auto entityId = fbb.CreateString(uid.constData()); 334 auto entityId = fbb.CreateString(uid.constData());
344 //This is the resource buffer type and not the domain type 335 // This is the resource buffer type and not the domain type
345 auto type = fbb.CreateString(resourceBufferType.constData()); 336 auto type = fbb.CreateString(resourceBufferType.constData());
346 auto location = Sink::Commands::CreateDeleteEntity(fbb, revision, entityId, type); 337 auto location = Sink::Commands::CreateDeleteEntity(fbb, revision, entityId, type);
347 Sink::Commands::FinishDeleteEntityBuffer(fbb, location); 338 Sink::Commands::FinishDeleteEntityBuffer(fbb, location);
@@ -358,7 +349,8 @@ KAsync::Job<void> ResourceAccess::sendRevisionReplayedCommand(qint64 revision)
358 return sendCommand(Sink::Commands::RevisionReplayedCommand, fbb); 349 return sendCommand(Sink::Commands::RevisionReplayedCommand, fbb);
359} 350}
360 351
361KAsync::Job<void> ResourceAccess::sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue) 352KAsync::Job<void>
353ResourceAccess::sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expectedValue)
362{ 354{
363 flatbuffers::FlatBufferBuilder fbb; 355 flatbuffers::FlatBufferBuilder fbb;
364 auto id = fbb.CreateString(inspectionId.toStdString()); 356 auto id = fbb.CreateString(inspectionId.toStdString());
@@ -371,7 +363,7 @@ KAsync::Job<void> ResourceAccess::sendInspectionCommand(const QByteArray &inspec
371 s << expectedValue; 363 s << expectedValue;
372 364
373 auto expected = fbb.CreateString(array.toStdString()); 365 auto expected = fbb.CreateString(array.toStdString());
374 auto location = Sink::Commands::CreateInspection (fbb, id, 0, entity, domain, prop, expected); 366 auto location = Sink::Commands::CreateInspection(fbb, id, 0, entity, domain, prop, expected);
375 Sink::Commands::FinishInspectionBuffer(fbb, location); 367 Sink::Commands::FinishInspectionBuffer(fbb, location);
376 open(); 368 open();
377 return sendCommand(Sink::Commands::InspectionCommand, fbb); 369 return sendCommand(Sink::Commands::InspectionCommand, fbb);
@@ -389,21 +381,21 @@ void ResourceAccess::open()
389 auto time = QSharedPointer<QTime>::create(); 381 auto time = QSharedPointer<QTime>::create();
390 time->start(); 382 time->start();
391 d->openingSocket = true; 383 d->openingSocket = true;
392 d->initializeSocket().then<void>([this, time]() { 384 d->initializeSocket()
393 Trace() << "Socket is initialized." << Log::TraceTime(time->elapsed()); 385 .then<void>(
394 d->openingSocket = false; 386 [this, time]() {
395 QObject::connect(d->socket.data(), &QLocalSocket::disconnected, 387 Trace() << "Socket is initialized." << Log::TraceTime(time->elapsed());
396 this, &ResourceAccess::disconnected); 388 d->openingSocket = false;
397 QObject::connect(d->socket.data(), SIGNAL(error(QLocalSocket::LocalSocketError)), 389 QObject::connect(d->socket.data(), &QLocalSocket::disconnected, this, &ResourceAccess::disconnected);
398 this, SLOT(connectionError(QLocalSocket::LocalSocketError))); 390 QObject::connect(d->socket.data(), SIGNAL(error(QLocalSocket::LocalSocketError)), this, SLOT(connectionError(QLocalSocket::LocalSocketError)));
399 QObject::connect(d->socket.data(), &QIODevice::readyRead, 391 QObject::connect(d->socket.data(), &QIODevice::readyRead, this, &ResourceAccess::readResourceMessage);
400 this, &ResourceAccess::readResourceMessage); 392 connected();
401 connected(); 393 },
402 }, 394 [this](int error, const QString &errorString) {
403 [this](int error, const QString &errorString) { 395 d->openingSocket = false;
404 d->openingSocket = false; 396 Warning() << "Failed to initialize socket " << errorString;
405 Warning() << "Failed to initialize socket " << errorString; 397 })
406 }).exec(); 398 .exec();
407} 399}
408 400
409void ResourceAccess::close() 401void ResourceAccess::close()
@@ -417,7 +409,7 @@ void ResourceAccess::close()
417void ResourceAccess::sendCommand(const QSharedPointer<QueuedCommand> &command) 409void ResourceAccess::sendCommand(const QSharedPointer<QueuedCommand> &command)
418{ 410{
419 Q_ASSERT(isReady()); 411 Q_ASSERT(isReady());
420 //TODO: we should have a timeout for commands 412 // TODO: we should have a timeout for commands
421 d->messageId++; 413 d->messageId++;
422 const auto messageId = d->messageId; 414 const auto messageId = d->messageId;
423 Log() << QString("Sending command \"%1\" with messageId %2").arg(QString(Sink::Commands::name(command->commandId))).arg(d->messageId); 415 Log() << QString("Sending command \"%1\" with messageId %2").arg(QString(Sink::Commands::name(command->commandId))).arg(d->messageId);
@@ -427,17 +419,17 @@ void ResourceAccess::sendCommand(const QSharedPointer<QueuedCommand> &command)
427 d->pendingCommands.remove(messageId); 419 d->pendingCommands.remove(messageId);
428 command->callback(errorCode, errorMessage); 420 command->callback(errorCode, errorMessage);
429 }); 421 });
430 //Keep track of the command until we're sure it arrived 422 // Keep track of the command until we're sure it arrived
431 d->pendingCommands.insert(d->messageId, command); 423 d->pendingCommands.insert(d->messageId, command);
432 Commands::write(d->socket.data(), d->messageId, command->commandId, command->buffer.constData(), command->buffer.size()); 424 Commands::write(d->socket.data(), d->messageId, command->commandId, command->buffer.constData(), command->buffer.size());
433} 425}
434 426
435void ResourceAccess::processCommandQueue() 427void ResourceAccess::processCommandQueue()
436{ 428{
437 //TODO: serialize instead of blast them all through the socket? 429 // TODO: serialize instead of blast them all through the socket?
438 Trace() << "We have " << d->commandQueue.size() << " queued commands"; 430 Trace() << "We have " << d->commandQueue.size() << " queued commands";
439 Trace() << "Pending commands: " << d->pendingCommands.size(); 431 Trace() << "Pending commands: " << d->pendingCommands.size();
440 for (auto command: d->commandQueue) { 432 for (auto command : d->commandQueue) {
441 sendCommand(command); 433 sendCommand(command);
442 } 434 }
443 d->commandQueue.clear(); 435 d->commandQueue.clear();
@@ -446,7 +438,7 @@ void ResourceAccess::processCommandQueue()
446void ResourceAccess::processPendingCommandQueue() 438void ResourceAccess::processPendingCommandQueue()
447{ 439{
448 Trace() << "We have " << d->pendingCommands.size() << " pending commands"; 440 Trace() << "We have " << d->pendingCommands.size() << " pending commands";
449 for (auto command: d->pendingCommands) { 441 for (auto command : d->pendingCommands) {
450 Trace() << "Reenquing command " << command->commandId; 442 Trace() << "Reenquing command " << command->commandId;
451 d->commandQueue << command; 443 d->commandQueue << command;
452 } 444 }
@@ -471,9 +463,9 @@ void ResourceAccess::connected()
471 Commands::write(d->socket.data(), ++d->messageId, Commands::HandshakeCommand, fbb); 463 Commands::write(d->socket.data(), ++d->messageId, Commands::HandshakeCommand, fbb);
472 } 464 }
473 465
474 //Reenqueue pending commands, we failed to send them 466 // Reenqueue pending commands, we failed to send them
475 processPendingCommandQueue(); 467 processPendingCommandQueue();
476 //Send queued commands 468 // Send queued commands
477 processCommandQueue(); 469 processCommandQueue();
478 470
479 emit ready(true); 471 emit ready(true);
@@ -510,7 +502,8 @@ void ResourceAccess::readResourceMessage()
510 d->partialMessageBuffer += d->socket->readAll(); 502 d->partialMessageBuffer += d->socket->readAll();
511 503
512 // should be scheduled rather than processed all at once 504 // should be scheduled rather than processed all at once
513 while (processMessageBuffer()) {} 505 while (processMessageBuffer()) {
506 }
514} 507}
515 508
516bool ResourceAccess::processMessageBuffer() 509bool ResourceAccess::processMessageBuffer()
@@ -521,9 +514,9 @@ bool ResourceAccess::processMessageBuffer()
521 return false; 514 return false;
522 } 515 }
523 516
524 //const uint messageId = *(int*)(d->partialMessageBuffer.constData()); 517 // const uint messageId = *(int*)(d->partialMessageBuffer.constData());
525 const int commandId = *(int*)(d->partialMessageBuffer.constData() + sizeof(uint)); 518 const int commandId = *(int *)(d->partialMessageBuffer.constData() + sizeof(uint));
526 const uint size = *(int*)(d->partialMessageBuffer.constData() + sizeof(int) + sizeof(uint)); 519 const uint size = *(int *)(d->partialMessageBuffer.constData() + sizeof(int) + sizeof(uint));
527 520
528 if (size > (uint)(d->partialMessageBuffer.size() - headerSize)) { 521 if (size > (uint)(d->partialMessageBuffer.size() - headerSize)) {
529 Warning() << "command too small"; 522 Warning() << "command too small";
@@ -546,10 +539,8 @@ bool ResourceAccess::processMessageBuffer()
546 Log() << QString("Command with messageId %1 completed %2").arg(buffer->id()).arg(buffer->success() ? "sucessfully" : "unsuccessfully"); 539 Log() << QString("Command with messageId %1 completed %2").arg(buffer->id()).arg(buffer->success() ? "sucessfully" : "unsuccessfully");
547 540
548 d->completeCommands << buffer->id(); 541 d->completeCommands << buffer->id();
549 //The callbacks can result in this object getting destroyed directly, so we need to ensure we finish our work first 542 // The callbacks can result in this object getting destroyed directly, so we need to ensure we finish our work first
550 queuedInvoke([=]() { 543 queuedInvoke([=]() { d->callCallbacks(); }, this);
551 d->callCallbacks();
552 }, this);
553 break; 544 break;
554 } 545 }
555 case Commands::NotificationCommand: { 546 case Commands::NotificationCommand: {
@@ -563,21 +554,18 @@ bool ResourceAccess::processMessageBuffer()
563 Log() << "Received inspection notification."; 554 Log() << "Received inspection notification.";
564 Notification n; 555 Notification n;
565 if (buffer->identifier()) { 556 if (buffer->identifier()) {
566 //Don't use fromRawData, the buffer is gone once we invoke emit notification 557 // Don't use fromRawData, the buffer is gone once we invoke emit notification
567 n.id = BufferUtils::extractBufferCopy(buffer->identifier()); 558 n.id = BufferUtils::extractBufferCopy(buffer->identifier());
568 } 559 }
569 if (buffer->message()) { 560 if (buffer->message()) {
570 //Don't use fromRawData, the buffer is gone once we invoke emit notification 561 // Don't use fromRawData, the buffer is gone once we invoke emit notification
571 n.message = BufferUtils::extractBufferCopy(buffer->message()); 562 n.message = BufferUtils::extractBufferCopy(buffer->message());
572 } 563 }
573 n.type = buffer->type(); 564 n.type = buffer->type();
574 n.code = buffer->code(); 565 n.code = buffer->code();
575 //The callbacks can result in this object getting destroyed directly, so we need to ensure we finish our work first 566 // The callbacks can result in this object getting destroyed directly, so we need to ensure we finish our work first
576 queuedInvoke([=]() { 567 queuedInvoke([=]() { emit notification(n); }, this);
577 emit notification(n); 568 } break;
578 }, this);
579 }
580 break;
581 case Sink::Commands::NotificationType::NotificationType_Status: 569 case Sink::Commands::NotificationType::NotificationType_Status:
582 case Sink::Commands::NotificationType::NotificationType_Warning: 570 case Sink::Commands::NotificationType::NotificationType_Warning:
583 case Sink::Commands::NotificationType::NotificationType_Progress: 571 case Sink::Commands::NotificationType::NotificationType_Progress:
@@ -608,7 +596,7 @@ ResourceAccessFactory &ResourceAccessFactory::instance()
608Sink::ResourceAccess::Ptr ResourceAccessFactory::getAccess(const QByteArray &instanceIdentifier) 596Sink::ResourceAccess::Ptr ResourceAccessFactory::getAccess(const QByteArray &instanceIdentifier)
609{ 597{
610 if (!mCache.contains(instanceIdentifier)) { 598 if (!mCache.contains(instanceIdentifier)) {
611 //Reuse the pointer if something else kept the resourceaccess alive 599 // Reuse the pointer if something else kept the resourceaccess alive
612 if (mWeakCache.contains(instanceIdentifier)) { 600 if (mWeakCache.contains(instanceIdentifier)) {
613 auto sharedPointer = mWeakCache.value(instanceIdentifier).toStrongRef(); 601 auto sharedPointer = mWeakCache.value(instanceIdentifier).toStrongRef();
614 if (sharedPointer) { 602 if (sharedPointer) {
@@ -616,7 +604,7 @@ Sink::ResourceAccess::Ptr ResourceAccessFactory::getAccess(const QByteArray &ins
616 } 604 }
617 } 605 }
618 if (!mCache.contains(instanceIdentifier)) { 606 if (!mCache.contains(instanceIdentifier)) {
619 //Create a new instance if necessary 607 // Create a new instance if necessary
620 auto sharedPointer = Sink::ResourceAccess::Ptr::create(instanceIdentifier); 608 auto sharedPointer = Sink::ResourceAccess::Ptr::create(instanceIdentifier);
621 QObject::connect(sharedPointer.data(), &Sink::ResourceAccess::ready, sharedPointer.data(), [this, instanceIdentifier](bool ready) { 609 QObject::connect(sharedPointer.data(), &Sink::ResourceAccess::ready, sharedPointer.data(), [this, instanceIdentifier](bool ready) {
622 if (!ready) { 610 if (!ready) {
@@ -629,10 +617,8 @@ Sink::ResourceAccess::Ptr ResourceAccessFactory::getAccess(const QByteArray &ins
629 } 617 }
630 if (!mTimer.contains(instanceIdentifier)) { 618 if (!mTimer.contains(instanceIdentifier)) {
631 auto timer = new QTimer; 619 auto timer = new QTimer;
632 //Drop connection after 3 seconds (which is a random value) 620 // Drop connection after 3 seconds (which is a random value)
633 QObject::connect(timer, &QTimer::timeout, timer, [this, instanceIdentifier]() { 621 QObject::connect(timer, &QTimer::timeout, timer, [this, instanceIdentifier]() { mCache.remove(instanceIdentifier); });
634 mCache.remove(instanceIdentifier);
635 });
636 timer->setInterval(3000); 622 timer->setInterval(3000);
637 mTimer.insert(instanceIdentifier, timer); 623 mTimer.insert(instanceIdentifier, timer);
638 } 624 }
@@ -640,7 +626,6 @@ Sink::ResourceAccess::Ptr ResourceAccessFactory::getAccess(const QByteArray &ins
640 timer->start(); 626 timer->start();
641 return mCache.value(instanceIdentifier); 627 return mCache.value(instanceIdentifier);
642} 628}
643
644} 629}
645 630
646#pragma clang diagnostic push 631#pragma clang diagnostic push
diff --git a/common/resourceaccess.h b/common/resourceaccess.h
index ce7e174..bd9af65 100644
--- a/common/resourceaccess.h
+++ b/common/resourceaccess.h
@@ -30,8 +30,7 @@
30#include <flatbuffers/flatbuffers.h> 30#include <flatbuffers/flatbuffers.h>
31#include "notification.h" 31#include "notification.h"
32 32
33namespace Sink 33namespace Sink {
34{
35 34
36struct QueuedCommand; 35struct QueuedCommand;
37 36
@@ -41,17 +40,37 @@ class SINK_EXPORT ResourceAccessInterface : public QObject
41public: 40public:
42 typedef QSharedPointer<ResourceAccessInterface> Ptr; 41 typedef QSharedPointer<ResourceAccessInterface> Ptr;
43 42
44 ResourceAccessInterface() {} 43 ResourceAccessInterface()
45 virtual ~ResourceAccessInterface() {} 44 {
45 }
46 virtual ~ResourceAccessInterface()
47 {
48 }
46 virtual KAsync::Job<void> sendCommand(int commandId) = 0; 49 virtual KAsync::Job<void> sendCommand(int commandId) = 0;
47 virtual KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) = 0; 50 virtual KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) = 0;
48 virtual KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) = 0; 51 virtual KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) = 0;
49 52
50 virtual KAsync::Job<void> sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer) { return KAsync::null<void>(); }; 53 virtual KAsync::Job<void> sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer)
51 virtual KAsync::Job<void> sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer) { return KAsync::null<void>(); }; 54 {
52 virtual KAsync::Job<void> sendDeleteCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType) { return KAsync::null<void>(); }; 55 return KAsync::null<void>();
53 virtual KAsync::Job<void> sendRevisionReplayedCommand(qint64 revision) {return KAsync::null<void>(); }; 56 };
54 virtual KAsync::Job<void> sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expecedValue) {return KAsync::null<void>(); }; 57 virtual KAsync::Job<void> sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer)
58 {
59 return KAsync::null<void>();
60 };
61 virtual KAsync::Job<void> sendDeleteCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType)
62 {
63 return KAsync::null<void>();
64 };
65 virtual KAsync::Job<void> sendRevisionReplayedCommand(qint64 revision)
66 {
67 return KAsync::null<void>();
68 };
69 virtual KAsync::Job<void>
70 sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expecedValue)
71 {
72 return KAsync::null<void>();
73 };
55 74
56signals: 75signals:
57 void ready(bool isReady); 76 void ready(bool isReady);
@@ -79,21 +98,23 @@ public:
79 KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) Q_DECL_OVERRIDE; 98 KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) Q_DECL_OVERRIDE;
80 KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) Q_DECL_OVERRIDE; 99 KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) Q_DECL_OVERRIDE;
81 KAsync::Job<void> sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer) Q_DECL_OVERRIDE; 100 KAsync::Job<void> sendCreateCommand(const QByteArray &resourceBufferType, const QByteArray &buffer) Q_DECL_OVERRIDE;
82 KAsync::Job<void> sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer) Q_DECL_OVERRIDE; 101 KAsync::Job<void>
102 sendModifyCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType, const QByteArrayList &deletedProperties, const QByteArray &buffer) Q_DECL_OVERRIDE;
83 KAsync::Job<void> sendDeleteCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType) Q_DECL_OVERRIDE; 103 KAsync::Job<void> sendDeleteCommand(const QByteArray &uid, qint64 revision, const QByteArray &resourceBufferType) Q_DECL_OVERRIDE;
84 KAsync::Job<void> sendRevisionReplayedCommand(qint64 revision) Q_DECL_OVERRIDE; 104 KAsync::Job<void> sendRevisionReplayedCommand(qint64 revision) Q_DECL_OVERRIDE;
85 KAsync::Job<void> sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expecedValue) Q_DECL_OVERRIDE; 105 KAsync::Job<void>
106 sendInspectionCommand(const QByteArray &inspectionId, const QByteArray &domainType, const QByteArray &entityId, const QByteArray &property, const QVariant &expecedValue) Q_DECL_OVERRIDE;
86 /** 107 /**
87 * Tries to connect to server, and returns a connected socket on success. 108 * Tries to connect to server, and returns a connected socket on success.
88 */ 109 */
89 static KAsync::Job<QSharedPointer<QLocalSocket> > connectToServer(const QByteArray &identifier); 110 static KAsync::Job<QSharedPointer<QLocalSocket>> connectToServer(const QByteArray &identifier);
90 111
91public slots: 112public slots:
92 void open() Q_DECL_OVERRIDE; 113 void open() Q_DECL_OVERRIDE;
93 void close() Q_DECL_OVERRIDE; 114 void close() Q_DECL_OVERRIDE;
94 115
95private slots: 116private slots:
96 //TODO: move these to the Private class 117 // TODO: move these to the Private class
97 void disconnected(); 118 void disconnected();
98 void connectionError(QLocalSocket::LocalSocketError error); 119 void connectionError(QLocalSocket::LocalSocketError error);
99 void readResourceMessage(); 120 void readResourceMessage();
@@ -108,23 +129,22 @@ private:
108 void processPendingCommandQueue(); 129 void processPendingCommandQueue();
109 130
110 class Private; 131 class Private;
111 Private * const d; 132 Private *const d;
112}; 133};
113 134
114/** 135/**
115 * A factory for resource access instances that caches the instance for some time. 136 * A factory for resource access instances that caches the instance for some time.
116 * 137 *
117 * This avoids constantly recreating connections, and should allow a single process to have one connection per resource. 138 * This avoids constantly recreating connections, and should allow a single process to have one connection per resource.
118 */ 139 */
119class ResourceAccessFactory { 140class ResourceAccessFactory
141{
120public: 142public:
121 static ResourceAccessFactory &instance(); 143 static ResourceAccessFactory &instance();
122 Sink::ResourceAccess::Ptr getAccess(const QByteArray &instanceIdentifier); 144 Sink::ResourceAccess::Ptr getAccess(const QByteArray &instanceIdentifier);
123 145
124 QHash<QByteArray, QWeakPointer<Sink::ResourceAccess> > mWeakCache; 146 QHash<QByteArray, QWeakPointer<Sink::ResourceAccess>> mWeakCache;
125 QHash<QByteArray, Sink::ResourceAccess::Ptr> mCache; 147 QHash<QByteArray, Sink::ResourceAccess::Ptr> mCache;
126 QHash<QByteArray, QTimer*> mTimer; 148 QHash<QByteArray, QTimer *> mTimer;
127}; 149};
128
129
130} 150}
diff --git a/common/resourceconfig.cpp b/common/resourceconfig.cpp
index a34340b..b988718 100644
--- a/common/resourceconfig.cpp
+++ b/common/resourceconfig.cpp
@@ -101,4 +101,3 @@ QMap<QByteArray, QVariant> ResourceConfig::getConfiguration(const QByteArray &id
101 } 101 }
102 return configuration; 102 return configuration;
103} 103}
104
diff --git a/common/resourcecontrol.cpp b/common/resourcecontrol.cpp
index 20125ac..d8b0972 100644
--- a/common/resourcecontrol.cpp
+++ b/common/resourcecontrol.cpp
@@ -32,28 +32,31 @@
32#undef DEBUG_AREA 32#undef DEBUG_AREA
33#define DEBUG_AREA "client.resourcecontrol" 33#define DEBUG_AREA "client.resourcecontrol"
34 34
35namespace Sink 35namespace Sink {
36{
37 36
38KAsync::Job<void> ResourceControl::shutdown(const QByteArray &identifier) 37KAsync::Job<void> ResourceControl::shutdown(const QByteArray &identifier)
39{ 38{
40 Trace() << "shutdown " << identifier; 39 Trace() << "shutdown " << identifier;
41 auto time = QSharedPointer<QTime>::create(); 40 auto time = QSharedPointer<QTime>::create();
42 time->start(); 41 time->start();
43 return ResourceAccess::connectToServer(identifier).then<void, QSharedPointer<QLocalSocket>>([identifier, time](QSharedPointer<QLocalSocket> socket, KAsync::Future<void> &future) { 42 return ResourceAccess::connectToServer(identifier)
44 //We can't currently reuse the socket 43 .then<void, QSharedPointer<QLocalSocket>>(
45 socket->close(); 44 [identifier, time](QSharedPointer<QLocalSocket> socket, KAsync::Future<void> &future) {
46 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier); 45 // We can't currently reuse the socket
47 resourceAccess->open(); 46 socket->close();
48 resourceAccess->sendCommand(Sink::Commands::ShutdownCommand).then<void>([&future, resourceAccess, time]() { 47 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier);
49 Trace() << "Shutdown complete." << Log::TraceTime(time->elapsed()); 48 resourceAccess->open();
50 future.setFinished(); 49 resourceAccess->sendCommand(Sink::Commands::ShutdownCommand)
51 }).exec(); 50 .then<void>([&future, resourceAccess, time]() {
52 }, 51 Trace() << "Shutdown complete." << Log::TraceTime(time->elapsed());
53 [](int, const QString &) { 52 future.setFinished();
54 Trace() << "Resource is already closed."; 53 })
55 //Resource isn't started, nothing to shutdown 54 .exec();
56 }); 55 },
56 [](int, const QString &) {
57 Trace() << "Resource is already closed.";
58 // Resource isn't started, nothing to shutdown
59 });
57} 60}
58 61
59KAsync::Job<void> ResourceControl::start(const QByteArray &identifier) 62KAsync::Job<void> ResourceControl::start(const QByteArray &identifier)
@@ -63,23 +66,19 @@ KAsync::Job<void> ResourceControl::start(const QByteArray &identifier)
63 time->start(); 66 time->start();
64 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier); 67 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier);
65 resourceAccess->open(); 68 resourceAccess->open();
66 return resourceAccess->sendCommand(Sink::Commands::PingCommand).then<void>([resourceAccess, time]() { 69 return resourceAccess->sendCommand(Sink::Commands::PingCommand).then<void>([resourceAccess, time]() { Trace() << "Start complete." << Log::TraceTime(time->elapsed()); });
67 Trace() << "Start complete." << Log::TraceTime(time->elapsed());
68 });
69} 70}
70 71
71KAsync::Job<void> ResourceControl::flushMessageQueue(const QByteArrayList &resourceIdentifier) 72KAsync::Job<void> ResourceControl::flushMessageQueue(const QByteArrayList &resourceIdentifier)
72{ 73{
73 Trace() << "flushMessageQueue" << resourceIdentifier; 74 Trace() << "flushMessageQueue" << resourceIdentifier;
74 return KAsync::iterate(resourceIdentifier) 75 return KAsync::iterate(resourceIdentifier)
75 .template each<void, QByteArray>([](const QByteArray &resource, KAsync::Future<void> &future) { 76 .template each<void, QByteArray>([](const QByteArray &resource, KAsync::Future<void> &future) {
76 Trace() << "Flushing message queue " << resource; 77 Trace() << "Flushing message queue " << resource;
77 auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource); 78 auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource);
78 resourceAccess->open(); 79 resourceAccess->open();
79 resourceAccess->synchronizeResource(false, true).then<void>([&future, resourceAccess]() { 80 resourceAccess->synchronizeResource(false, true).then<void>([&future, resourceAccess]() { future.setFinished(); }).exec();
80 future.setFinished(); 81 });
81 }).exec();
82 });
83} 82}
84 83
85KAsync::Job<void> ResourceControl::flushReplayQueue(const QByteArrayList &resourceIdentifier) 84KAsync::Job<void> ResourceControl::flushReplayQueue(const QByteArrayList &resourceIdentifier)
@@ -114,7 +113,7 @@ KAsync::Job<void> ResourceControl::inspect(const Inspection &inspectionCommand)
114 }); 113 });
115} 114}
116 115
117#define REGISTER_TYPE(T) template KAsync::Job<void> ResourceControl::inspect<T>(const Inspection &); \ 116#define REGISTER_TYPE(T) template KAsync::Job<void> ResourceControl::inspect<T>(const Inspection &);
118 117
119REGISTER_TYPE(ApplicationDomain::Event); 118REGISTER_TYPE(ApplicationDomain::Event);
120REGISTER_TYPE(ApplicationDomain::Mail); 119REGISTER_TYPE(ApplicationDomain::Mail);
@@ -122,4 +121,3 @@ REGISTER_TYPE(ApplicationDomain::Folder);
122REGISTER_TYPE(ApplicationDomain::SinkResource); 121REGISTER_TYPE(ApplicationDomain::SinkResource);
123 122
124} // namespace Sink 123} // namespace Sink
125
diff --git a/common/resourcecontrol.h b/common/resourcecontrol.h
index 5bfa67f..d483153 100644
--- a/common/resourcecontrol.h
+++ b/common/resourcecontrol.h
@@ -40,7 +40,7 @@ KAsync::Job<void> SINK_EXPORT shutdown(const QByteArray &resourceIdentifier);
40 40
41/** 41/**
42 * Start resource. 42 * Start resource.
43 * 43 *
44 * The resource is ready for operation once this command completes. 44 * The resource is ready for operation once this command completes.
45 * This command is only necessary if a resource was shutdown previously, 45 * This command is only necessary if a resource was shutdown previously,
46 * otherwise the resource process will automatically start as necessary. 46 * otherwise the resource process will automatically start as necessary.
@@ -56,7 +56,5 @@ KAsync::Job<void> SINK_EXPORT flushMessageQueue(const QByteArrayList &resourceId
56 * Flushes any pending messages that haven't been replayed to the source. 56 * Flushes any pending messages that haven't been replayed to the source.
57 */ 57 */
58KAsync::Job<void> SINK_EXPORT flushReplayQueue(const QByteArrayList &resourceIdentifier); 58KAsync::Job<void> SINK_EXPORT flushReplayQueue(const QByteArrayList &resourceIdentifier);
59
60 }
61} 59}
62 60}
diff --git a/common/resourcefacade.cpp b/common/resourcefacade.cpp
index 414e390..9294926 100644
--- a/common/resourcefacade.cpp
+++ b/common/resourcefacade.cpp
@@ -24,15 +24,12 @@
24#include "storage.h" 24#include "storage.h"
25#include <QDir> 25#include <QDir>
26 26
27ResourceFacade::ResourceFacade(const QByteArray &) 27ResourceFacade::ResourceFacade(const QByteArray &) : Sink::StoreFacade<Sink::ApplicationDomain::SinkResource>()
28 : Sink::StoreFacade<Sink::ApplicationDomain::SinkResource>()
29{ 28{
30
31} 29}
32 30
33ResourceFacade::~ResourceFacade() 31ResourceFacade::~ResourceFacade()
34{ 32{
35
36} 33}
37 34
38KAsync::Job<void> ResourceFacade::create(const Sink::ApplicationDomain::SinkResource &resource) 35KAsync::Job<void> ResourceFacade::create(const Sink::ApplicationDomain::SinkResource &resource)
@@ -40,14 +37,14 @@ KAsync::Job<void> ResourceFacade::create(const Sink::ApplicationDomain::SinkReso
40 return KAsync::start<void>([resource, this]() { 37 return KAsync::start<void>([resource, this]() {
41 const QByteArray type = resource.getProperty("type").toByteArray(); 38 const QByteArray type = resource.getProperty("type").toByteArray();
42 const QByteArray providedIdentifier = resource.getProperty("identifier").toByteArray(); 39 const QByteArray providedIdentifier = resource.getProperty("identifier").toByteArray();
43 //It is currently a requirement that the resource starts with the type 40 // It is currently a requirement that the resource starts with the type
44 const QByteArray identifier = providedIdentifier.isEmpty() ? ResourceConfig::newIdentifier(type) : providedIdentifier; 41 const QByteArray identifier = providedIdentifier.isEmpty() ? ResourceConfig::newIdentifier(type) : providedIdentifier;
45 ResourceConfig::addResource(identifier, type); 42 ResourceConfig::addResource(identifier, type);
46 auto changedProperties = resource.changedProperties(); 43 auto changedProperties = resource.changedProperties();
47 changedProperties.removeOne("identifier"); 44 changedProperties.removeOne("identifier");
48 changedProperties.removeOne("type"); 45 changedProperties.removeOne("type");
49 if (!changedProperties.isEmpty()) { 46 if (!changedProperties.isEmpty()) {
50 //We have some configuration values 47 // We have some configuration values
51 QMap<QByteArray, QVariant> configurationValues; 48 QMap<QByteArray, QVariant> configurationValues;
52 for (const auto &property : changedProperties) { 49 for (const auto &property : changedProperties) {
53 configurationValues.insert(property, resource.getProperty(property)); 50 configurationValues.insert(property, resource.getProperty(property));
@@ -69,7 +66,7 @@ KAsync::Job<void> ResourceFacade::modify(const Sink::ApplicationDomain::SinkReso
69 changedProperties.removeOne("identifier"); 66 changedProperties.removeOne("identifier");
70 changedProperties.removeOne("type"); 67 changedProperties.removeOne("type");
71 if (!changedProperties.isEmpty()) { 68 if (!changedProperties.isEmpty()) {
72 //We have some configuration values 69 // We have some configuration values
73 QMap<QByteArray, QVariant> configurationValues; 70 QMap<QByteArray, QVariant> configurationValues;
74 for (const auto &property : changedProperties) { 71 for (const auto &property : changedProperties) {
75 configurationValues.insert(property, resource.getProperty(property)); 72 configurationValues.insert(property, resource.getProperty(property));
@@ -88,7 +85,7 @@ KAsync::Job<void> ResourceFacade::remove(const Sink::ApplicationDomain::SinkReso
88 return; 85 return;
89 } 86 }
90 ResourceConfig::removeResource(identifier); 87 ResourceConfig::removeResource(identifier);
91 //TODO shutdown resource, or use the resource process with a --remove option to cleanup (so we can take advantage of the file locking) 88 // TODO shutdown resource, or use the resource process with a --remove option to cleanup (so we can take advantage of the file locking)
92 QDir dir(Sink::storageLocation()); 89 QDir dir(Sink::storageLocation());
93 for (const auto &folder : dir.entryList(QStringList() << identifier + "*")) { 90 for (const auto &folder : dir.entryList(QStringList() << identifier + "*")) {
94 Sink::Storage(Sink::storageLocation(), folder, Sink::Storage::ReadWrite).removeFromDisk(); 91 Sink::Storage(Sink::storageLocation(), folder, Sink::Storage::ReadWrite).removeFromDisk();
@@ -96,14 +93,12 @@ KAsync::Job<void> ResourceFacade::remove(const Sink::ApplicationDomain::SinkReso
96 }); 93 });
97} 94}
98 95
99QPair<KAsync::Job<void>, typename Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>::Ptr > ResourceFacade::load(const Sink::Query &query) 96QPair<KAsync::Job<void>, typename Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>::Ptr> ResourceFacade::load(const Sink::Query &query)
100{ 97{
101 auto resultProvider = new Sink::ResultProvider<typename Sink::ApplicationDomain::SinkResource::Ptr>(); 98 auto resultProvider = new Sink::ResultProvider<typename Sink::ApplicationDomain::SinkResource::Ptr>();
102 auto emitter = resultProvider->emitter(); 99 auto emitter = resultProvider->emitter();
103 resultProvider->setFetcher([](const QSharedPointer<Sink::ApplicationDomain::SinkResource> &) {}); 100 resultProvider->setFetcher([](const QSharedPointer<Sink::ApplicationDomain::SinkResource> &) {});
104 resultProvider->onDone([resultProvider]() { 101 resultProvider->onDone([resultProvider]() { delete resultProvider; });
105 delete resultProvider;
106 });
107 auto job = KAsync::start<void>([query, resultProvider]() { 102 auto job = KAsync::start<void>([query, resultProvider]() {
108 const auto configuredResources = ResourceConfig::getResources(); 103 const auto configuredResources = ResourceConfig::getResources();
109 for (const auto &res : configuredResources.keys()) { 104 for (const auto &res : configuredResources.keys()) {
@@ -114,10 +109,9 @@ QPair<KAsync::Job<void>, typename Sink::ResultEmitter<Sink::ApplicationDomain::S
114 resultProvider->add(resource); 109 resultProvider->add(resource);
115 } 110 }
116 } 111 }
117 //TODO initialResultSetComplete should be implicit 112 // TODO initialResultSetComplete should be implicit
118 resultProvider->initialResultSetComplete(Sink::ApplicationDomain::SinkResource::Ptr()); 113 resultProvider->initialResultSetComplete(Sink::ApplicationDomain::SinkResource::Ptr());
119 resultProvider->complete(); 114 resultProvider->complete();
120 }); 115 });
121 return qMakePair(job, emitter); 116 return qMakePair(job, emitter);
122} 117}
123
diff --git a/common/resourcefacade.h b/common/resourcefacade.h
index 5ddaa79..3de0e25 100644
--- a/common/resourcefacade.h
+++ b/common/resourcefacade.h
@@ -26,8 +26,8 @@
26#include "common/domain/applicationdomaintype.h" 26#include "common/domain/applicationdomaintype.h"
27 27
28namespace Sink { 28namespace Sink {
29 class Query; 29class Query;
30 class Inspection; 30class Inspection;
31} 31}
32 32
33class ResourceFacade : public Sink::StoreFacade<Sink::ApplicationDomain::SinkResource> 33class ResourceFacade : public Sink::StoreFacade<Sink::ApplicationDomain::SinkResource>
@@ -38,6 +38,5 @@ public:
38 KAsync::Job<void> create(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE; 38 KAsync::Job<void> create(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE;
39 KAsync::Job<void> modify(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE; 39 KAsync::Job<void> modify(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE;
40 KAsync::Job<void> remove(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE; 40 KAsync::Job<void> remove(const Sink::ApplicationDomain::SinkResource &resource) Q_DECL_OVERRIDE;
41 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>::Ptr > load(const Sink::Query &query) Q_DECL_OVERRIDE; 41 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<Sink::ApplicationDomain::SinkResource::Ptr>::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE;
42}; 42};
43
diff --git a/common/resultprovider.h b/common/resultprovider.h
index 2d6efbe..5561ff2 100644
--- a/common/resultprovider.h
+++ b/common/resultprovider.h
@@ -32,22 +32,19 @@ namespace Sink {
32/** 32/**
33* Query result set 33* Query result set
34*/ 34*/
35template<class T> 35template <class T>
36class ResultEmitter; 36class ResultEmitter;
37 37
38template<class T> 38template <class T>
39class ResultProviderInterface 39class ResultProviderInterface
40{ 40{
41public: 41public:
42 ResultProviderInterface() 42 ResultProviderInterface() : mRevision(0)
43 : mRevision(0)
44 { 43 {
45
46 } 44 }
47 45
48 virtual ~ResultProviderInterface() 46 virtual ~ResultProviderInterface()
49 { 47 {
50
51 } 48 }
52 49
53 virtual void add(const T &value) = 0; 50 virtual void add(const T &value) = 0;
@@ -75,17 +72,18 @@ private:
75/* 72/*
76* The promise side for the result emitter 73* The promise side for the result emitter
77*/ 74*/
78template<class T> 75template <class T>
79class ResultProvider : public ResultProviderInterface<T> { 76class ResultProvider : public ResultProviderInterface<T>
77{
80private: 78private:
81 void callInMainThreadOnEmitter(void (ResultEmitter<T>::*f)()) 79 void callInMainThreadOnEmitter(void (ResultEmitter<T>::*f)())
82 { 80 {
83 //We use the eventloop to call the addHandler directly from the main eventloop. 81 // We use the eventloop to call the addHandler directly from the main eventloop.
84 //That way the result emitter implementation doesn't have to care about threadsafety at all. 82 // That way the result emitter implementation doesn't have to care about threadsafety at all.
85 //The alternative would be to make all handlers of the emitter threadsafe. 83 // The alternative would be to make all handlers of the emitter threadsafe.
86 if (auto emitter = mResultEmitter.toStrongRef()) { 84 if (auto emitter = mResultEmitter.toStrongRef()) {
87 auto weakEmitter = mResultEmitter; 85 auto weakEmitter = mResultEmitter;
88 //We don't want to keep the emitter alive here, so we only capture a weak reference 86 // We don't want to keep the emitter alive here, so we only capture a weak reference
89 emitter->mThreadBoundary.callInMainThread([weakEmitter, f]() { 87 emitter->mThreadBoundary.callInMainThread([weakEmitter, f]() {
90 if (auto strongRef = weakEmitter.toStrongRef()) { 88 if (auto strongRef = weakEmitter.toStrongRef()) {
91 (strongRef.data()->*f)(); 89 (strongRef.data()->*f)();
@@ -96,27 +94,27 @@ private:
96 94
97 void callInMainThreadOnEmitter(const std::function<void()> &f) 95 void callInMainThreadOnEmitter(const std::function<void()> &f)
98 { 96 {
99 //We use the eventloop to call the addHandler directly from the main eventloop. 97 // We use the eventloop to call the addHandler directly from the main eventloop.
100 //That way the result emitter implementation doesn't have to care about threadsafety at all. 98 // That way the result emitter implementation doesn't have to care about threadsafety at all.
101 //The alternative would be to make all handlers of the emitter threadsafe. 99 // The alternative would be to make all handlers of the emitter threadsafe.
102 if (auto emitter = mResultEmitter.toStrongRef()) { 100 if (auto emitter = mResultEmitter.toStrongRef()) {
103 emitter->mThreadBoundary.callInMainThread(f); 101 emitter->mThreadBoundary.callInMainThread(f);
104 } 102 }
105 } 103 }
106 104
107public: 105public:
108 typedef QSharedPointer<ResultProvider<T> > Ptr; 106 typedef QSharedPointer<ResultProvider<T>> Ptr;
109 107
110 virtual ~ResultProvider() 108 virtual ~ResultProvider()
111 { 109 {
112 } 110 }
113 111
114 //Called from worker thread 112 // Called from worker thread
115 void add(const T &value) 113 void add(const T &value)
116 { 114 {
117 //Because I don't know how to use bind 115 // Because I don't know how to use bind
118 auto weakEmitter = mResultEmitter; 116 auto weakEmitter = mResultEmitter;
119 callInMainThreadOnEmitter([weakEmitter, value](){ 117 callInMainThreadOnEmitter([weakEmitter, value]() {
120 if (auto strongRef = weakEmitter.toStrongRef()) { 118 if (auto strongRef = weakEmitter.toStrongRef()) {
121 strongRef->addHandler(value); 119 strongRef->addHandler(value);
122 } 120 }
@@ -125,9 +123,9 @@ public:
125 123
126 void modify(const T &value) 124 void modify(const T &value)
127 { 125 {
128 //Because I don't know how to use bind 126 // Because I don't know how to use bind
129 auto weakEmitter = mResultEmitter; 127 auto weakEmitter = mResultEmitter;
130 callInMainThreadOnEmitter([weakEmitter, value](){ 128 callInMainThreadOnEmitter([weakEmitter, value]() {
131 if (auto strongRef = weakEmitter.toStrongRef()) { 129 if (auto strongRef = weakEmitter.toStrongRef()) {
132 strongRef->modifyHandler(value); 130 strongRef->modifyHandler(value);
133 } 131 }
@@ -136,9 +134,9 @@ public:
136 134
137 void remove(const T &value) 135 void remove(const T &value)
138 { 136 {
139 //Because I don't know how to use bind 137 // Because I don't know how to use bind
140 auto weakEmitter = mResultEmitter; 138 auto weakEmitter = mResultEmitter;
141 callInMainThreadOnEmitter([weakEmitter, value](){ 139 callInMainThreadOnEmitter([weakEmitter, value]() {
142 if (auto strongRef = weakEmitter.toStrongRef()) { 140 if (auto strongRef = weakEmitter.toStrongRef()) {
143 strongRef->removeHandler(value); 141 strongRef->removeHandler(value);
144 } 142 }
@@ -147,16 +145,16 @@ public:
147 145
148 void initialResultSetComplete(const T &parent) 146 void initialResultSetComplete(const T &parent)
149 { 147 {
150 //Because I don't know how to use bind 148 // Because I don't know how to use bind
151 auto weakEmitter = mResultEmitter; 149 auto weakEmitter = mResultEmitter;
152 callInMainThreadOnEmitter([weakEmitter, parent](){ 150 callInMainThreadOnEmitter([weakEmitter, parent]() {
153 if (auto strongRef = weakEmitter.toStrongRef()) { 151 if (auto strongRef = weakEmitter.toStrongRef()) {
154 strongRef->initialResultSetComplete(parent); 152 strongRef->initialResultSetComplete(parent);
155 } 153 }
156 }); 154 });
157 } 155 }
158 156
159 //Called from worker thread 157 // Called from worker thread
160 void complete() 158 void complete()
161 { 159 {
162 callInMainThreadOnEmitter(&ResultEmitter<T>::complete); 160 callInMainThreadOnEmitter(&ResultEmitter<T>::complete);
@@ -168,11 +166,14 @@ public:
168 } 166 }
169 167
170 168
171 QSharedPointer<ResultEmitter<T> > emitter() 169 QSharedPointer<ResultEmitter<T>> emitter()
172 { 170 {
173 if (!mResultEmitter) { 171 if (!mResultEmitter) {
174 //We have to go over a separate var and return that, otherwise we'd delete the emitter immediately again 172 // We have to go over a separate var and return that, otherwise we'd delete the emitter immediately again
175 auto sharedPtr = QSharedPointer<ResultEmitter<T> >(new ResultEmitter<T>, [this](ResultEmitter<T> *emitter){ mThreadBoundary->callInMainThread([this]() {done();}); delete emitter; }); 173 auto sharedPtr = QSharedPointer<ResultEmitter<T>>(new ResultEmitter<T>, [this](ResultEmitter<T> *emitter) {
174 mThreadBoundary->callInMainThread([this]() { done(); });
175 delete emitter;
176 });
176 mResultEmitter = sharedPtr; 177 mResultEmitter = sharedPtr;
177 sharedPtr->setFetcher([this](const T &parent) { 178 sharedPtr->setFetcher([this](const T &parent) {
178 Q_ASSERT(mFetcher); 179 Q_ASSERT(mFetcher);
@@ -192,7 +193,7 @@ public:
192 193
193 bool isDone() const 194 bool isDone() const
194 { 195 {
195 //The existance of the emitter currently defines wether we're done or not. 196 // The existance of the emitter currently defines wether we're done or not.
196 return mResultEmitter.toStrongRef().isNull(); 197 return mResultEmitter.toStrongRef().isNull();
197 } 198 }
198 199
@@ -208,12 +209,12 @@ private:
208 if (mOnDoneCallback) { 209 if (mOnDoneCallback) {
209 auto callback = mOnDoneCallback; 210 auto callback = mOnDoneCallback;
210 mOnDoneCallback = std::function<void()>(); 211 mOnDoneCallback = std::function<void()>();
211 //This may delete this object 212 // This may delete this object
212 callback(); 213 callback();
213 } 214 }
214 } 215 }
215 216
216 QWeakPointer<ResultEmitter<T> > mResultEmitter; 217 QWeakPointer<ResultEmitter<T>> mResultEmitter;
217 std::function<void()> mOnDoneCallback; 218 std::function<void()> mOnDoneCallback;
218 QSharedPointer<async::ThreadBoundary> mThreadBoundary; 219 QSharedPointer<async::ThreadBoundary> mThreadBoundary;
219 std::function<void(const T &parent)> mFetcher; 220 std::function<void(const T &parent)> mFetcher;
@@ -231,32 +232,32 @@ private:
231* * build sync interfaces that block when accessing the value 232* * build sync interfaces that block when accessing the value
232* 233*
233*/ 234*/
234template<class DomainType> 235template <class DomainType>
235class ResultEmitter { 236class ResultEmitter
237{
236public: 238public:
237 typedef QSharedPointer<ResultEmitter<DomainType> > Ptr; 239 typedef QSharedPointer<ResultEmitter<DomainType>> Ptr;
238 240
239 virtual ~ResultEmitter() 241 virtual ~ResultEmitter()
240 { 242 {
241
242 } 243 }
243 244
244 void onAdded(const std::function<void(const DomainType&)> &handler) 245 void onAdded(const std::function<void(const DomainType &)> &handler)
245 { 246 {
246 addHandler = handler; 247 addHandler = handler;
247 } 248 }
248 249
249 void onModified(const std::function<void(const DomainType&)> &handler) 250 void onModified(const std::function<void(const DomainType &)> &handler)
250 { 251 {
251 modifyHandler = handler; 252 modifyHandler = handler;
252 } 253 }
253 254
254 void onRemoved(const std::function<void(const DomainType&)> &handler) 255 void onRemoved(const std::function<void(const DomainType &)> &handler)
255 { 256 {
256 removeHandler = handler; 257 removeHandler = handler;
257 } 258 }
258 259
259 void onInitialResultSetComplete(const std::function<void(const DomainType&)> &handler) 260 void onInitialResultSetComplete(const std::function<void(const DomainType &)> &handler)
260 { 261 {
261 initialResultSetCompleteHandler = handler; 262 initialResultSetCompleteHandler = handler;
262 } 263 }
@@ -322,10 +323,10 @@ public:
322private: 323private:
323 friend class ResultProvider<DomainType>; 324 friend class ResultProvider<DomainType>;
324 325
325 std::function<void(const DomainType&)> addHandler; 326 std::function<void(const DomainType &)> addHandler;
326 std::function<void(const DomainType&)> modifyHandler; 327 std::function<void(const DomainType &)> modifyHandler;
327 std::function<void(const DomainType&)> removeHandler; 328 std::function<void(const DomainType &)> removeHandler;
328 std::function<void(const DomainType&)> initialResultSetCompleteHandler; 329 std::function<void(const DomainType &)> initialResultSetCompleteHandler;
329 std::function<void(void)> completeHandler; 330 std::function<void(void)> completeHandler;
330 std::function<void(void)> clearHandler; 331 std::function<void(void)> clearHandler;
331 332
@@ -333,37 +334,28 @@ private:
333 async::ThreadBoundary mThreadBoundary; 334 async::ThreadBoundary mThreadBoundary;
334}; 335};
335 336
336template<class DomainType> 337template <class DomainType>
337class AggregatingResultEmitter : public ResultEmitter<DomainType> { 338class AggregatingResultEmitter : public ResultEmitter<DomainType>
339{
338public: 340public:
339 typedef QSharedPointer<AggregatingResultEmitter<DomainType> > Ptr; 341 typedef QSharedPointer<AggregatingResultEmitter<DomainType>> Ptr;
340 342
341 void addEmitter(const typename ResultEmitter<DomainType>::Ptr &emitter) 343 void addEmitter(const typename ResultEmitter<DomainType>::Ptr &emitter)
342 { 344 {
343 emitter->onAdded([this](const DomainType &value) { 345 emitter->onAdded([this](const DomainType &value) { this->add(value); });
344 this->add(value); 346 emitter->onModified([this](const DomainType &value) { this->modify(value); });
345 }); 347 emitter->onRemoved([this](const DomainType &value) { this->remove(value); });
346 emitter->onModified([this](const DomainType &value) {
347 this->modify(value);
348 });
349 emitter->onRemoved([this](const DomainType &value) {
350 this->remove(value);
351 });
352 auto ptr = emitter.data(); 348 auto ptr = emitter.data();
353 emitter->onInitialResultSetComplete([this, ptr](const DomainType &parent) { 349 emitter->onInitialResultSetComplete([this, ptr](const DomainType &parent) {
354 auto hashValue = qHash(parent); 350 auto hashValue = qHash(parent);
355 mInitialResultSetInProgress.remove(hashValue, ptr); 351 mInitialResultSetInProgress.remove(hashValue, ptr);
356 //Normally a parent is only in a single resource, except the toplevel (invalid) parent 352 // Normally a parent is only in a single resource, except the toplevel (invalid) parent
357 if (!mInitialResultSetInProgress.contains(hashValue)) { 353 if (!mInitialResultSetInProgress.contains(hashValue)) {
358 this->initialResultSetComplete(parent); 354 this->initialResultSetComplete(parent);
359 } 355 }
360 }); 356 });
361 emitter->onComplete([this]() { 357 emitter->onComplete([this]() { this->complete(); });
362 this->complete(); 358 emitter->onClear([this]() { this->clear(); });
363 });
364 emitter->onClear([this]() {
365 this->clear();
366 });
367 mEmitter << emitter; 359 mEmitter << emitter;
368 } 360 }
369 361
@@ -382,10 +374,6 @@ public:
382 374
383private: 375private:
384 QList<typename ResultEmitter<DomainType>::Ptr> mEmitter; 376 QList<typename ResultEmitter<DomainType>::Ptr> mEmitter;
385 QMultiMap<qint64, ResultEmitter<DomainType>*> mInitialResultSetInProgress; 377 QMultiMap<qint64, ResultEmitter<DomainType> *> mInitialResultSetInProgress;
386}; 378};
387
388
389
390} 379}
391
diff --git a/common/resultset.cpp b/common/resultset.cpp
index 6e1479a..293035b 100644
--- a/common/resultset.cpp
+++ b/common/resultset.cpp
@@ -20,56 +20,38 @@
20 20
21#include "common/log.h" 21#include "common/log.h"
22 22
23ResultSet::ResultSet() 23ResultSet::ResultSet() : mIt(nullptr)
24 : mIt(nullptr)
25{ 24{
26
27} 25}
28 26
29ResultSet::ResultSet(const ValueGenerator &generator, const SkipValue &skip) 27ResultSet::ResultSet(const ValueGenerator &generator, const SkipValue &skip) : mIt(nullptr), mValueGenerator(generator), mSkip(skip)
30 : mIt(nullptr),
31 mValueGenerator(generator),
32 mSkip(skip)
33{ 28{
34
35} 29}
36 30
37ResultSet::ResultSet(const IdGenerator &generator) 31ResultSet::ResultSet(const IdGenerator &generator) : mIt(nullptr), mGenerator(generator), mSkip([this]() { next(); })
38 : mIt(nullptr),
39 mGenerator(generator),
40 mSkip([this]() {
41 next();
42 })
43{ 32{
44
45} 33}
46 34
47ResultSet::ResultSet(const QVector<QByteArray> &resultSet) 35ResultSet::ResultSet(const QVector<QByteArray> &resultSet)
48 : mResultSet(resultSet), 36 : mResultSet(resultSet),
49 mIt(mResultSet.constBegin()), 37 mIt(mResultSet.constBegin()),
50 mSkip([this]() { 38 mSkip([this]() {
51 if (mIt != mResultSet.constEnd()) { 39 if (mIt != mResultSet.constEnd()) {
52 mIt++; 40 mIt++;
53 } 41 }
54 }), 42 }),
55 mFirst(true) 43 mFirst(true)
56{ 44{
57
58} 45}
59 46
60ResultSet::ResultSet(const ResultSet &other) 47ResultSet::ResultSet(const ResultSet &other) : mResultSet(other.mResultSet), mIt(nullptr), mFirst(true)
61 : mResultSet(other.mResultSet),
62 mIt(nullptr),
63 mFirst(true)
64{ 48{
65 if (other.mValueGenerator) { 49 if (other.mValueGenerator) {
66 mValueGenerator = other.mValueGenerator; 50 mValueGenerator = other.mValueGenerator;
67 mSkip = other.mSkip; 51 mSkip = other.mSkip;
68 } else if (other.mGenerator) { 52 } else if (other.mGenerator) {
69 mGenerator = other.mGenerator; 53 mGenerator = other.mGenerator;
70 mSkip = [this]() { 54 mSkip = [this]() { next(); };
71 next();
72 };
73 } else { 55 } else {
74 mResultSet = other.mResultSet; 56 mResultSet = other.mResultSet;
75 mIt = mResultSet.constBegin(); 57 mIt = mResultSet.constBegin();
@@ -96,7 +78,7 @@ bool ResultSet::next()
96 return true; 78 return true;
97 } 79 }
98 } else { 80 } else {
99 next([](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation){ return false; }); 81 next([](const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation) { return false; });
100 } 82 }
101 return false; 83 return false;
102} 84}
diff --git a/common/resultset.h b/common/resultset.h
index e513460..88f7055 100644
--- a/common/resultset.h
+++ b/common/resultset.h
@@ -28,34 +28,34 @@
28 * 28 *
29 * We'll eventually want to lazy load results in next(). 29 * We'll eventually want to lazy load results in next().
30 */ 30 */
31class ResultSet { 31class ResultSet
32 public: 32{
33 typedef std::function<bool(std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)>)> ValueGenerator; 33public:
34 typedef std::function<QByteArray()> IdGenerator; 34 typedef std::function<bool(std::function<void(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &, Sink::Operation)>)> ValueGenerator;
35 typedef std::function<void()> SkipValue; 35 typedef std::function<QByteArray()> IdGenerator;
36 36 typedef std::function<void()> SkipValue;
37 ResultSet(); 37
38 ResultSet(const ValueGenerator &generator, const SkipValue &skip); 38 ResultSet();
39 ResultSet(const IdGenerator &generator); 39 ResultSet(const ValueGenerator &generator, const SkipValue &skip);
40 ResultSet(const QVector<QByteArray> &resultSet); 40 ResultSet(const IdGenerator &generator);
41 ResultSet(const ResultSet &other); 41 ResultSet(const QVector<QByteArray> &resultSet);
42 42 ResultSet(const ResultSet &other);
43 bool next(); 43
44 bool next(std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation)> callback); 44 bool next();
45 45 bool next(std::function<bool(const Sink::ApplicationDomain::ApplicationDomainType::Ptr &value, Sink::Operation)> callback);
46 void skip(int number); 46
47 47 void skip(int number);
48 QByteArray id(); 48
49 49 QByteArray id();
50 bool isEmpty(); 50
51 51 bool isEmpty();
52 private: 52
53 QVector<QByteArray> mResultSet; 53private:
54 QVector<QByteArray>::ConstIterator mIt; 54 QVector<QByteArray> mResultSet;
55 QByteArray mCurrentValue; 55 QVector<QByteArray>::ConstIterator mIt;
56 IdGenerator mGenerator; 56 QByteArray mCurrentValue;
57 ValueGenerator mValueGenerator; 57 IdGenerator mGenerator;
58 SkipValue mSkip; 58 ValueGenerator mValueGenerator;
59 bool mFirst; 59 SkipValue mSkip;
60 bool mFirst;
60}; 61};
61
diff --git a/common/storage.h b/common/storage.h
index 663d192..b051daa 100644
--- a/common/storage.h
+++ b/common/storage.h
@@ -26,14 +26,19 @@
26#include <functional> 26#include <functional>
27#include <QString> 27#include <QString>
28 28
29namespace Sink 29namespace Sink {
30{
31 30
32class SINK_EXPORT Storage { 31class SINK_EXPORT Storage
32{
33public: 33public:
34 enum AccessMode { ReadOnly, ReadWrite }; 34 enum AccessMode
35 {
36 ReadOnly,
37 ReadWrite
38 };
35 39
36 enum ErrorCodes { 40 enum ErrorCodes
41 {
37 GenericError, 42 GenericError,
38 NotOpen, 43 NotOpen,
39 ReadOnlyError, 44 ReadOnlyError,
@@ -44,8 +49,9 @@ public:
44 class Error 49 class Error
45 { 50 {
46 public: 51 public:
47 Error(const QByteArray &s, int c, const QByteArray &m) 52 Error(const QByteArray &s, int c, const QByteArray &m) : store(s), message(m), code(c)
48 : store(s), message(m), code(c) {} 53 {
54 }
49 QByteArray store; 55 QByteArray store;
50 QByteArray message; 56 QByteArray message;
51 int code; 57 int code;
@@ -65,13 +71,11 @@ public:
65 /** 71 /**
66 * Remove a key 72 * Remove a key
67 */ 73 */
68 void remove(const QByteArray &key, 74 void remove(const QByteArray &key, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
69 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
70 /** 75 /**
71 * Remove a key-value pair 76 * Remove a key-value pair
72 */ 77 */
73 void remove(const QByteArray &key, const QByteArray &value, 78 void remove(const QByteArray &key, const QByteArray &value, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
74 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
75 79
76 /** 80 /**
77 * Read values with a given key. 81 * Read values with a given key.
@@ -82,9 +86,8 @@ public:
82 * 86 *
83 * @return The number of values retrieved. 87 * @return The number of values retrieved.
84 */ 88 */
85 int scan(const QByteArray &key, 89 int scan(const QByteArray &key, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler,
86 const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler, 90 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool findSubstringKeys = false) const;
87 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool findSubstringKeys = false) const;
88 91
89 /** 92 /**
90 * Finds the last value in a series matched by prefix. 93 * Finds the last value in a series matched by prefix.
@@ -92,28 +95,29 @@ public:
92 * This is used to match by uid prefix and find the highest revision. 95 * This is used to match by uid prefix and find the highest revision.
93 * Note that this relies on a key scheme like $uid$revision. 96 * Note that this relies on a key scheme like $uid$revision.
94 */ 97 */
95 void findLatest(const QByteArray &uid, 98 void findLatest(const QByteArray &uid, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler,
96 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 99 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>()) const;
97 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>()) const;
98 100
99 /** 101 /**
100 * Returns true if the database contains the substring key. 102 * Returns true if the database contains the substring key.
101 */ 103 */
102 bool contains(const QByteArray &uid); 104 bool contains(const QByteArray &uid);
103 105
104 NamedDatabase(NamedDatabase&& other) : d(other.d) 106 NamedDatabase(NamedDatabase &&other) : d(other.d)
105 { 107 {
106 d = other.d; 108 d = other.d;
107 other.d = nullptr; 109 other.d = nullptr;
108 } 110 }
109 111
110 NamedDatabase& operator=(NamedDatabase&& other) { 112 NamedDatabase &operator=(NamedDatabase &&other)
113 {
111 d = other.d; 114 d = other.d;
112 other.d = nullptr; 115 other.d = nullptr;
113 return *this; 116 return *this;
114 } 117 }
115 118
116 operator bool() const { 119 operator bool() const
120 {
117 return (d != nullptr); 121 return (d != nullptr);
118 } 122 }
119 123
@@ -121,10 +125,10 @@ public:
121 125
122 private: 126 private:
123 friend Transaction; 127 friend Transaction;
124 NamedDatabase(NamedDatabase& other); 128 NamedDatabase(NamedDatabase &other);
125 NamedDatabase& operator=(NamedDatabase& other); 129 NamedDatabase &operator=(NamedDatabase &other);
126 class Private; 130 class Private;
127 NamedDatabase(Private*); 131 NamedDatabase(Private *);
128 Private *d; 132 Private *d;
129 }; 133 };
130 134
@@ -138,37 +142,39 @@ public:
138 142
139 QList<QByteArray> getDatabaseNames() const; 143 QList<QByteArray> getDatabaseNames() const;
140 144
141 NamedDatabase openDatabase(const QByteArray &name = QByteArray("default"), const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool allowDuplicates = false) const; 145 NamedDatabase openDatabase(const QByteArray &name = QByteArray("default"),
146 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>(), bool allowDuplicates = false) const;
142 147
143 Transaction(Transaction&& other) : d(other.d) 148 Transaction(Transaction &&other) : d(other.d)
144 { 149 {
145 d = other.d; 150 d = other.d;
146 other.d = nullptr; 151 other.d = nullptr;
147 } 152 }
148 Transaction& operator=(Transaction&& other) { 153 Transaction &operator=(Transaction &&other)
154 {
149 d = other.d; 155 d = other.d;
150 other.d = nullptr; 156 other.d = nullptr;
151 return *this; 157 return *this;
152 } 158 }
153 159
154 operator bool() const { 160 operator bool() const
161 {
155 return (d != nullptr); 162 return (d != nullptr);
156 } 163 }
157 164
158 private: 165 private:
159 Transaction(Transaction& other); 166 Transaction(Transaction &other);
160 Transaction& operator=(Transaction& other); 167 Transaction &operator=(Transaction &other);
161 friend Storage; 168 friend Storage;
162 class Private; 169 class Private;
163 Transaction(Private*); 170 Transaction(Private *);
164 Private *d; 171 Private *d;
165 }; 172 };
166 173
167 Storage(const QString &storageRoot, const QString &name, AccessMode mode = ReadOnly); 174 Storage(const QString &storageRoot, const QString &name, AccessMode mode = ReadOnly);
168 ~Storage(); 175 ~Storage();
169 176
170 Transaction createTransaction(AccessMode mode = ReadWrite, 177 Transaction createTransaction(AccessMode mode = ReadWrite, const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
171 const std::function<void(const Storage::Error &error)> &errorHandler = std::function<void(const Storage::Error &error)>());
172 178
173 /** 179 /**
174 * Set the default error handler. 180 * Set the default error handler.
@@ -178,7 +184,7 @@ public:
178 184
179 /** 185 /**
180 * A basic error handler that writes to std::cerr. 186 * A basic error handler that writes to std::cerr.
181 * 187 *
182 * Used if nothing else is configured. 188 * Used if nothing else is configured.
183 */ 189 */
184 static std::function<void(const Storage::Error &error)> basicErrorHandler(); 190 static std::function<void(const Storage::Error &error)> basicErrorHandler();
@@ -188,7 +194,7 @@ public:
188 194
189 /** 195 /**
190 * Clears all cached environments. 196 * Clears all cached environments.
191 * 197 *
192 * This only ever has to be called if a database was removed from another process. 198 * This only ever has to be called if a database was removed from another process.
193 */ 199 */
194 static void clearEnv(); 200 static void clearEnv();
@@ -220,8 +226,7 @@ private:
220 226
221private: 227private:
222 class Private; 228 class Private;
223 Private * const d; 229 Private *const d;
224}; 230};
225 231
226} // namespace Sink 232} // namespace Sink
227
diff --git a/common/storage_common.cpp b/common/storage_common.cpp
index 0b842d1..2873f5f 100644
--- a/common/storage_common.cpp
+++ b/common/storage_common.cpp
@@ -23,8 +23,7 @@
23 23
24#include "log.h" 24#include "log.h"
25 25
26namespace Sink 26namespace Sink {
27{
28 27
29static const char *s_internalPrefix = "__internal"; 28static const char *s_internalPrefix = "__internal";
30static const int s_internalPrefixSize = strlen(s_internalPrefix); 29static const int s_internalPrefixSize = strlen(s_internalPrefix);
@@ -60,14 +59,16 @@ void Storage::setMaxRevision(Sink::Storage::Transaction &transaction, qint64 rev
60qint64 Storage::maxRevision(const Sink::Storage::Transaction &transaction) 59qint64 Storage::maxRevision(const Sink::Storage::Transaction &transaction)
61{ 60{
62 qint64 r = 0; 61 qint64 r = 0;
63 transaction.openDatabase().scan("__internal_maxRevision", [&](const QByteArray &, const QByteArray &revision) -> bool { 62 transaction.openDatabase().scan("__internal_maxRevision",
64 r = revision.toLongLong(); 63 [&](const QByteArray &, const QByteArray &revision) -> bool {
65 return false; 64 r = revision.toLongLong();
66 }, [](const Error &error){ 65 return false;
67 if (error.code != Sink::Storage::NotFound) { 66 },
68 Warning() << "Coultn'd find the maximum revision."; 67 [](const Error &error) {
69 } 68 if (error.code != Sink::Storage::NotFound) {
70 }); 69 Warning() << "Coultn'd find the maximum revision.";
70 }
71 });
71 return r; 72 return r;
72} 73}
73 74
@@ -79,44 +80,48 @@ void Storage::setCleanedUpRevision(Sink::Storage::Transaction &transaction, qint
79qint64 Storage::cleanedUpRevision(const Sink::Storage::Transaction &transaction) 80qint64 Storage::cleanedUpRevision(const Sink::Storage::Transaction &transaction)
80{ 81{
81 qint64 r = 0; 82 qint64 r = 0;
82 transaction.openDatabase().scan("__internal_cleanedUpRevision", [&](const QByteArray &, const QByteArray &revision) -> bool { 83 transaction.openDatabase().scan("__internal_cleanedUpRevision",
83 r = revision.toLongLong(); 84 [&](const QByteArray &, const QByteArray &revision) -> bool {
84 return false; 85 r = revision.toLongLong();
85 }, [](const Error &error){ 86 return false;
86 if (error.code != Sink::Storage::NotFound) { 87 },
87 Warning() << "Coultn'd find the maximum revision."; 88 [](const Error &error) {
88 } 89 if (error.code != Sink::Storage::NotFound) {
89 }); 90 Warning() << "Coultn'd find the maximum revision.";
91 }
92 });
90 return r; 93 return r;
91} 94}
92 95
93QByteArray Storage::getUidFromRevision(const Sink::Storage::Transaction &transaction, qint64 revision) 96QByteArray Storage::getUidFromRevision(const Sink::Storage::Transaction &transaction, qint64 revision)
94{ 97{
95 QByteArray uid; 98 QByteArray uid;
96 transaction.openDatabase("revisions").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { 99 transaction.openDatabase("revisions")
97 uid = value; 100 .scan(QByteArray::number(revision),
98 return false; 101 [&](const QByteArray &, const QByteArray &value) -> bool {
99 }, [revision](const Error &error){ 102 uid = value;
100 Warning() << "Coultn'd find uid for revision " << revision; 103 return false;
101 }); 104 },
105 [revision](const Error &error) { Warning() << "Coultn'd find uid for revision " << revision; });
102 return uid; 106 return uid;
103} 107}
104 108
105QByteArray Storage::getTypeFromRevision(const Sink::Storage::Transaction &transaction, qint64 revision) 109QByteArray Storage::getTypeFromRevision(const Sink::Storage::Transaction &transaction, qint64 revision)
106{ 110{
107 QByteArray type; 111 QByteArray type;
108 transaction.openDatabase("revisionType").scan(QByteArray::number(revision), [&](const QByteArray &, const QByteArray &value) -> bool { 112 transaction.openDatabase("revisionType")
109 type = value; 113 .scan(QByteArray::number(revision),
110 return false; 114 [&](const QByteArray &, const QByteArray &value) -> bool {
111 }, [revision](const Error &error){ 115 type = value;
112 Warning() << "Coultn'd find type for revision " << revision; 116 return false;
113 }); 117 },
118 [revision](const Error &error) { Warning() << "Coultn'd find type for revision " << revision; });
114 return type; 119 return type;
115} 120}
116 121
117void Storage::recordRevision(Sink::Storage::Transaction &transaction, qint64 revision, const QByteArray &uid, const QByteArray &type) 122void Storage::recordRevision(Sink::Storage::Transaction &transaction, qint64 revision, const QByteArray &uid, const QByteArray &type)
118{ 123{
119 //TODO use integerkeys 124 // TODO use integerkeys
120 transaction.openDatabase("revisions").write(QByteArray::number(revision), uid); 125 transaction.openDatabase("revisions").write(QByteArray::number(revision), uid);
121 transaction.openDatabase("revisionType").write(QByteArray::number(revision), type); 126 transaction.openDatabase("revisionType").write(QByteArray::number(revision), type);
122} 127}
@@ -164,11 +169,12 @@ Storage::NamedDatabase Storage::mainDatabase(const Sink::Storage::Transaction &t
164bool Storage::NamedDatabase::contains(const QByteArray &uid) 169bool Storage::NamedDatabase::contains(const QByteArray &uid)
165{ 170{
166 bool found = false; 171 bool found = false;
167 scan(uid, [&found](const QByteArray &, const QByteArray &) -> bool { 172 scan(uid,
168 found = true; 173 [&found](const QByteArray &, const QByteArray &) -> bool {
169 return false; 174 found = true;
170 }, [this](const Sink::Storage::Error &error) { 175 return false;
171 }, true); 176 },
177 [this](const Sink::Storage::Error &error) {}, true);
172 return found; 178 return found;
173} 179}
174 180
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp
index 2d8b187..878a5d9 100644
--- a/common/storage_lmdb.cpp
+++ b/common/storage_lmdb.cpp
@@ -56,17 +56,12 @@ class Storage::NamedDatabase::Private
56{ 56{
57public: 57public:
58 Private(const QByteArray &_db, bool _allowDuplicates, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_txn *_txn) 58 Private(const QByteArray &_db, bool _allowDuplicates, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_txn *_txn)
59 : db(_db), 59 : db(_db), transaction(_txn), allowDuplicates(_allowDuplicates), defaultErrorHandler(_defaultErrorHandler), name(_name)
60 transaction(_txn),
61 allowDuplicates(_allowDuplicates),
62 defaultErrorHandler(_defaultErrorHandler),
63 name(_name)
64 { 60 {
65 } 61 }
66 62
67 ~Private() 63 ~Private()
68 { 64 {
69
70 } 65 }
71 66
72 QByteArray db; 67 QByteArray db;
@@ -88,7 +83,7 @@ public:
88 if (const int rc = mdb_dbi_open(transaction, db.constData(), flags, &dbi)) { 83 if (const int rc = mdb_dbi_open(transaction, db.constData(), flags, &dbi)) {
89 dbi = 0; 84 dbi = 0;
90 transaction = 0; 85 transaction = 0;
91 //The database is not existing, ignore in read-only mode 86 // The database is not existing, ignore in read-only mode
92 if (!(readOnly && rc == MDB_NOTFOUND)) { 87 if (!(readOnly && rc == MDB_NOTFOUND)) {
93 Error error(name.toLatin1(), ErrorCodes::GenericError, "Error while opening database: " + QByteArray(mdb_strerror(rc))); 88 Error error(name.toLatin1(), ErrorCodes::GenericError, "Error while opening database: " + QByteArray(mdb_strerror(rc)));
94 errorHandler ? errorHandler(error) : defaultErrorHandler(error); 89 errorHandler ? errorHandler(error) : defaultErrorHandler(error);
@@ -99,14 +94,11 @@ public:
99 } 94 }
100}; 95};
101 96
102Storage::NamedDatabase::NamedDatabase() 97Storage::NamedDatabase::NamedDatabase() : d(nullptr)
103 : d(nullptr)
104{ 98{
105
106} 99}
107 100
108Storage::NamedDatabase::NamedDatabase(NamedDatabase::Private *prv) 101Storage::NamedDatabase::NamedDatabase(NamedDatabase::Private *prv) : d(prv)
109 : d(prv)
110{ 102{
111} 103}
112 104
@@ -138,9 +130,9 @@ bool Storage::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sVa
138 int rc; 130 int rc;
139 MDB_val key, data; 131 MDB_val key, data;
140 key.mv_size = keySize; 132 key.mv_size = keySize;
141 key.mv_data = const_cast<void*>(keyPtr); 133 key.mv_data = const_cast<void *>(keyPtr);
142 data.mv_size = valueSize; 134 data.mv_size = valueSize;
143 data.mv_data = const_cast<void*>(valuePtr); 135 data.mv_data = const_cast<void *>(valuePtr);
144 rc = mdb_put(d->transaction, d->dbi, &key, &data, 0); 136 rc = mdb_put(d->transaction, d->dbi, &key, &data, 0);
145 137
146 if (rc) { 138 if (rc) {
@@ -151,14 +143,12 @@ bool Storage::NamedDatabase::write(const QByteArray &sKey, const QByteArray &sVa
151 return !rc; 143 return !rc;
152} 144}
153 145
154void Storage::NamedDatabase::remove(const QByteArray &k, 146void Storage::NamedDatabase::remove(const QByteArray &k, const std::function<void(const Storage::Error &error)> &errorHandler)
155 const std::function<void(const Storage::Error &error)> &errorHandler)
156{ 147{
157 remove(k, QByteArray(), errorHandler); 148 remove(k, QByteArray(), errorHandler);
158} 149}
159 150
160void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, 151void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value, const std::function<void(const Storage::Error &error)> &errorHandler)
161 const std::function<void(const Storage::Error &error)> &errorHandler)
162{ 152{
163 if (!d || !d->transaction) { 153 if (!d || !d->transaction) {
164 if (d) { 154 if (d) {
@@ -171,13 +161,13 @@ void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value
171 int rc; 161 int rc;
172 MDB_val key; 162 MDB_val key;
173 key.mv_size = k.size(); 163 key.mv_size = k.size();
174 key.mv_data = const_cast<void*>(static_cast<const void*>(k.data())); 164 key.mv_data = const_cast<void *>(static_cast<const void *>(k.data()));
175 if (value.isEmpty()) { 165 if (value.isEmpty()) {
176 rc = mdb_del(d->transaction, d->dbi, &key, 0); 166 rc = mdb_del(d->transaction, d->dbi, &key, 0);
177 } else { 167 } else {
178 MDB_val data; 168 MDB_val data;
179 data.mv_size = value.size(); 169 data.mv_size = value.size();
180 data.mv_data = const_cast<void*>(static_cast<const void*>(value.data())); 170 data.mv_data = const_cast<void *>(static_cast<const void *>(value.data()));
181 rc = mdb_del(d->transaction, d->dbi, &key, &data); 171 rc = mdb_del(d->transaction, d->dbi, &key, &data);
182 } 172 }
183 173
@@ -187,13 +177,11 @@ void Storage::NamedDatabase::remove(const QByteArray &k, const QByteArray &value
187 } 177 }
188} 178}
189 179
190int Storage::NamedDatabase::scan(const QByteArray &k, 180int Storage::NamedDatabase::scan(const QByteArray &k, const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler,
191 const std::function<bool(const QByteArray &key, const QByteArray &value)> &resultHandler, 181 const std::function<void(const Storage::Error &error)> &errorHandler, bool findSubstringKeys) const
192 const std::function<void(const Storage::Error &error)> &errorHandler,
193 bool findSubstringKeys) const
194{ 182{
195 if (!d || !d->transaction) { 183 if (!d || !d->transaction) {
196 //Not an error. We rely on this to read nothing from non-existing databases. 184 // Not an error. We rely on this to read nothing from non-existing databases.
197 return 0; 185 return 0;
198 } 186 }
199 187
@@ -202,7 +190,7 @@ int Storage::NamedDatabase::scan(const QByteArray &k,
202 MDB_val data; 190 MDB_val data;
203 MDB_cursor *cursor; 191 MDB_cursor *cursor;
204 192
205 key.mv_data = (void*)k.constData(); 193 key.mv_data = (void *)k.constData();
206 key.mv_size = k.size(); 194 key.mv_size = k.size();
207 195
208 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor); 196 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor);
@@ -220,21 +208,21 @@ int Storage::NamedDatabase::scan(const QByteArray &k,
220 op = MDB_SET_RANGE; 208 op = MDB_SET_RANGE;
221 } 209 }
222 if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) { 210 if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) {
223 //The first lookup will find a key that is equal or greather than our key 211 // The first lookup will find a key that is equal or greather than our key
224 if (QByteArray::fromRawData((char*)key.mv_data, key.mv_size).startsWith(k)) { 212 if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) {
225 numberOfRetrievedValues++; 213 numberOfRetrievedValues++;
226 if (resultHandler(QByteArray::fromRawData((char*)key.mv_data, key.mv_size), QByteArray::fromRawData((char*)data.mv_data, data.mv_size))) { 214 if (resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size))) {
227 if (findSubstringKeys) { 215 if (findSubstringKeys) {
228 //Reset the key to what we search for 216 // Reset the key to what we search for
229 key.mv_data = (void*)k.constData(); 217 key.mv_data = (void *)k.constData();
230 key.mv_size = k.size(); 218 key.mv_size = k.size();
231 } 219 }
232 MDB_cursor_op nextOp = (d->allowDuplicates && !findSubstringKeys) ? MDB_NEXT_DUP : MDB_NEXT; 220 MDB_cursor_op nextOp = (d->allowDuplicates && !findSubstringKeys) ? MDB_NEXT_DUP : MDB_NEXT;
233 while ((rc = mdb_cursor_get(cursor, &key, &data, nextOp)) == 0) { 221 while ((rc = mdb_cursor_get(cursor, &key, &data, nextOp)) == 0) {
234 //Every consequent lookup simply iterates through the list 222 // Every consequent lookup simply iterates through the list
235 if (QByteArray::fromRawData((char*)key.mv_data, key.mv_size).startsWith(k)) { 223 if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) {
236 numberOfRetrievedValues++; 224 numberOfRetrievedValues++;
237 if (!resultHandler(QByteArray::fromRawData((char*)key.mv_data, key.mv_size), QByteArray::fromRawData((char*)data.mv_data, data.mv_size))) { 225 if (!resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size))) {
238 break; 226 break;
239 } 227 }
240 } 228 }
@@ -243,14 +231,14 @@ int Storage::NamedDatabase::scan(const QByteArray &k,
243 } 231 }
244 } 232 }
245 233
246 //We never find the last value 234 // We never find the last value
247 if (rc == MDB_NOTFOUND) { 235 if (rc == MDB_NOTFOUND) {
248 rc = 0; 236 rc = 0;
249 } 237 }
250 } else { 238 } else {
251 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_SET)) == 0) { 239 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_SET)) == 0) {
252 numberOfRetrievedValues++; 240 numberOfRetrievedValues++;
253 resultHandler(QByteArray::fromRawData((char*)key.mv_data, key.mv_size), QByteArray::fromRawData((char*)data.mv_data, data.mv_size)); 241 resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size));
254 } 242 }
255 } 243 }
256 244
@@ -264,12 +252,11 @@ int Storage::NamedDatabase::scan(const QByteArray &k,
264 return numberOfRetrievedValues; 252 return numberOfRetrievedValues;
265} 253}
266 254
267void Storage::NamedDatabase::findLatest(const QByteArray &k, 255void Storage::NamedDatabase::findLatest(const QByteArray &k, const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler,
268 const std::function<void(const QByteArray &key, const QByteArray &value)> &resultHandler, 256 const std::function<void(const Storage::Error &error)> &errorHandler) const
269 const std::function<void(const Storage::Error &error)> &errorHandler) const
270{ 257{
271 if (!d || !d->transaction) { 258 if (!d || !d->transaction) {
272 //Not an error. We rely on this to read nothing from non-existing databases. 259 // Not an error. We rely on this to read nothing from non-existing databases.
273 return; 260 return;
274 } 261 }
275 262
@@ -278,7 +265,7 @@ void Storage::NamedDatabase::findLatest(const QByteArray &k,
278 MDB_val data; 265 MDB_val data;
279 MDB_cursor *cursor; 266 MDB_cursor *cursor;
280 267
281 key.mv_data = (void*)k.constData(); 268 key.mv_data = (void *)k.constData();
282 key.mv_size = k.size(); 269 key.mv_size = k.size();
283 270
284 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor); 271 rc = mdb_cursor_open(d->transaction, d->dbi, &cursor);
@@ -290,10 +277,10 @@ void Storage::NamedDatabase::findLatest(const QByteArray &k,
290 277
291 MDB_cursor_op op = MDB_SET_RANGE; 278 MDB_cursor_op op = MDB_SET_RANGE;
292 if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) { 279 if ((rc = mdb_cursor_get(cursor, &key, &data, op)) == 0) {
293 //The first lookup will find a key that is equal or greather than our key 280 // The first lookup will find a key that is equal or greather than our key
294 if (QByteArray::fromRawData((char*)key.mv_data, key.mv_size).startsWith(k)) { 281 if (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) {
295 bool advanced = false; 282 bool advanced = false;
296 while (QByteArray::fromRawData((char*)key.mv_data, key.mv_size).startsWith(k)) { 283 while (QByteArray::fromRawData((char *)key.mv_data, key.mv_size).startsWith(k)) {
297 advanced = true; 284 advanced = true;
298 MDB_cursor_op nextOp = MDB_NEXT; 285 MDB_cursor_op nextOp = MDB_NEXT;
299 rc = mdb_cursor_get(cursor, &key, &data, nextOp); 286 rc = mdb_cursor_get(cursor, &key, &data, nextOp);
@@ -303,17 +290,17 @@ void Storage::NamedDatabase::findLatest(const QByteArray &k,
303 } 290 }
304 if (advanced) { 291 if (advanced) {
305 MDB_cursor_op prefOp = MDB_PREV; 292 MDB_cursor_op prefOp = MDB_PREV;
306 //We read past the end above, just take the last value 293 // We read past the end above, just take the last value
307 if (rc == MDB_NOTFOUND) { 294 if (rc == MDB_NOTFOUND) {
308 prefOp = MDB_LAST; 295 prefOp = MDB_LAST;
309 } 296 }
310 rc = mdb_cursor_get(cursor, &key, &data, prefOp); 297 rc = mdb_cursor_get(cursor, &key, &data, prefOp);
311 resultHandler(QByteArray::fromRawData((char*)key.mv_data, key.mv_size), QByteArray::fromRawData((char*)data.mv_data, data.mv_size)); 298 resultHandler(QByteArray::fromRawData((char *)key.mv_data, key.mv_size), QByteArray::fromRawData((char *)data.mv_data, data.mv_size));
312 } 299 }
313 } 300 }
314 } 301 }
315 302
316 //We never find the last value 303 // We never find the last value
317 if (rc == MDB_NOTFOUND) { 304 if (rc == MDB_NOTFOUND) {
318 rc = 0; 305 rc = 0;
319 } 306 }
@@ -350,25 +337,15 @@ qint64 Storage::NamedDatabase::getSize()
350} 337}
351 338
352 339
353
354
355class Storage::Transaction::Private 340class Storage::Transaction::Private
356{ 341{
357public: 342public:
358 Private(bool _requestRead, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_env *_env) 343 Private(bool _requestRead, const std::function<void(const Storage::Error &error)> &_defaultErrorHandler, const QString &_name, MDB_env *_env)
359 : env(_env), 344 : env(_env), requestedRead(_requestRead), defaultErrorHandler(_defaultErrorHandler), name(_name), implicitCommit(false), error(false), modificationCounter(0)
360 requestedRead(_requestRead),
361 defaultErrorHandler(_defaultErrorHandler),
362 name(_name),
363 implicitCommit(false),
364 error(false),
365 modificationCounter(0)
366 { 345 {
367
368 } 346 }
369 ~Private() 347 ~Private()
370 { 348 {
371
372 } 349 }
373 350
374 MDB_env *env; 351 MDB_env *env;
@@ -391,14 +368,11 @@ public:
391 } 368 }
392}; 369};
393 370
394Storage::Transaction::Transaction() 371Storage::Transaction::Transaction() : d(nullptr)
395 : d(nullptr)
396{ 372{
397
398} 373}
399 374
400Storage::Transaction::Transaction(Transaction::Private *prv) 375Storage::Transaction::Transaction(Transaction::Private *prv) : d(prv)
401 : d(prv)
402{ 376{
403 d->startTransaction(); 377 d->startTransaction();
404} 378}
@@ -449,7 +423,7 @@ Storage::NamedDatabase Storage::Transaction::openDatabase(const QByteArray &db,
449 if (!d) { 423 if (!d) {
450 return Storage::NamedDatabase(); 424 return Storage::NamedDatabase();
451 } 425 }
452 //We don't now if anything changed 426 // We don't now if anything changed
453 d->implicitCommit = true; 427 d->implicitCommit = true;
454 auto p = new Storage::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction); 428 auto p = new Storage::NamedDatabase::Private(db, allowDuplicates, d->defaultErrorHandler, d->name, d->transaction);
455 if (!p->openDatabase(d->requestedRead, errorHandler)) { 429 if (!p->openDatabase(d->requestedRead, errorHandler)) {
@@ -475,9 +449,9 @@ QList<QByteArray> Storage::Transaction::getDatabaseNames() const
475 449
476 mdb_cursor_open(d->transaction, d->dbi, &cursor); 450 mdb_cursor_open(d->transaction, d->dbi, &cursor);
477 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST)) == 0) { 451 if ((rc = mdb_cursor_get(cursor, &key, &data, MDB_FIRST)) == 0) {
478 list << QByteArray::fromRawData((char*)key.mv_data, key.mv_size); 452 list << QByteArray::fromRawData((char *)key.mv_data, key.mv_size);
479 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { 453 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
480 list << QByteArray::fromRawData((char*)key.mv_data, key.mv_size); 454 list << QByteArray::fromRawData((char *)key.mv_data, key.mv_size);
481 } 455 }
482 } else { 456 } else {
483 Warning() << "Failed to get a value" << rc; 457 Warning() << "Failed to get a value" << rc;
@@ -489,9 +463,6 @@ QList<QByteArray> Storage::Transaction::getDatabaseNames() const
489} 463}
490 464
491 465
492
493
494
495class Storage::Private 466class Storage::Private
496{ 467{
497public: 468public:
@@ -504,17 +475,13 @@ public:
504 MDB_env *env; 475 MDB_env *env;
505 AccessMode mode; 476 AccessMode mode;
506 static QMutex sMutex; 477 static QMutex sMutex;
507 static QHash<QString, MDB_env*> sEnvironments; 478 static QHash<QString, MDB_env *> sEnvironments;
508}; 479};
509 480
510QMutex Storage::Private::sMutex; 481QMutex Storage::Private::sMutex;
511QHash<QString, MDB_env*> Storage::Private::sEnvironments; 482QHash<QString, MDB_env *> Storage::Private::sEnvironments;
512 483
513Storage::Private::Private(const QString &s, const QString &n, AccessMode m) 484Storage::Private::Private(const QString &s, const QString &n, AccessMode m) : storageRoot(s), name(n), env(0), mode(m)
514 : storageRoot(s),
515 name(n),
516 env(0),
517 mode(m)
518{ 485{
519 const QString fullPath(storageRoot + '/' + name); 486 const QString fullPath(storageRoot + '/' + name);
520 QFileInfo dirInfo(fullPath); 487 QFileInfo dirInfo(fullPath);
@@ -525,11 +492,11 @@ Storage::Private::Private(const QString &s, const QString &n, AccessMode m)
525 if (mode == ReadWrite && !dirInfo.permission(QFile::WriteOwner)) { 492 if (mode == ReadWrite && !dirInfo.permission(QFile::WriteOwner)) {
526 qCritical() << fullPath << "does not have write permissions. Aborting"; 493 qCritical() << fullPath << "does not have write permissions. Aborting";
527 } else if (dirInfo.exists()) { 494 } else if (dirInfo.exists()) {
528 //Ensure the environment is only created once 495 // Ensure the environment is only created once
529 QMutexLocker locker(&sMutex); 496 QMutexLocker locker(&sMutex);
530 497
531 /* 498 /*
532 * It seems we can only ever have one environment open in the process. 499 * It seems we can only ever have one environment open in the process.
533 * Otherwise multi-threading breaks. 500 * Otherwise multi-threading breaks.
534 */ 501 */
535 env = sEnvironments.value(fullPath); 502 env = sEnvironments.value(fullPath);
@@ -549,8 +516,8 @@ Storage::Private::Private(const QString &s, const QString &n, AccessMode m)
549 mdb_env_close(env); 516 mdb_env_close(env);
550 env = 0; 517 env = 0;
551 } else { 518 } else {
552 //FIXME: dynamic resize 519 // FIXME: dynamic resize
553 const size_t dbSize = (size_t)10485760 * (size_t)8000; //1MB * 8000 520 const size_t dbSize = (size_t)10485760 * (size_t)8000; // 1MB * 8000
554 mdb_env_set_mapsize(env, dbSize); 521 mdb_env_set_mapsize(env, dbSize);
555 sEnvironments.insert(fullPath, env); 522 sEnvironments.insert(fullPath, env);
556 } 523 }
@@ -561,7 +528,7 @@ Storage::Private::Private(const QString &s, const QString &n, AccessMode m)
561 528
562Storage::Private::~Private() 529Storage::Private::~Private()
563{ 530{
564 //Since we can have only one environment open per process, we currently leak the environments. 531 // Since we can have only one environment open per process, we currently leak the environments.
565 // if (env) { 532 // if (env) {
566 // //mdb_dbi_close should not be necessary and is potentially dangerous (see docs) 533 // //mdb_dbi_close should not be necessary and is potentially dangerous (see docs)
567 // mdb_dbi_close(env, dbi); 534 // mdb_dbi_close(env, dbi);
@@ -569,8 +536,7 @@ Storage::Private::~Private()
569 // } 536 // }
570} 537}
571 538
572Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode) 539Storage::Storage(const QString &storageRoot, const QString &name, AccessMode mode) : d(new Private(storageRoot, name, mode))
573 : d(new Private(storageRoot, name, mode))
574{ 540{
575} 541}
576 542
diff --git a/common/store.cpp b/common/store.cpp
index 6847d22..68f73c8 100644
--- a/common/store.cpp
+++ b/common/store.cpp
@@ -38,8 +38,7 @@
38#undef DEBUG_AREA 38#undef DEBUG_AREA
39#define DEBUG_AREA "client.store" 39#define DEBUG_AREA "client.store"
40 40
41namespace Sink 41namespace Sink {
42{
43 42
44QString Store::storageLocation() 43QString Store::storageLocation()
45{ 44{
@@ -48,7 +47,7 @@ QString Store::storageLocation()
48 47
49static QList<QByteArray> getResources(const QList<QByteArray> &resourceFilter, const QByteArray &type) 48static QList<QByteArray> getResources(const QList<QByteArray> &resourceFilter, const QByteArray &type)
50{ 49{
51 //Return the global resource (signified by an empty name) for types that don't eblong to a specific resource 50 // Return the global resource (signified by an empty name) for types that don't eblong to a specific resource
52 if (type == "sinkresource") { 51 if (type == "sinkresource") {
53 return QList<QByteArray>() << ""; 52 return QList<QByteArray>() << "";
54 } 53 }
@@ -56,7 +55,7 @@ static QList<QByteArray> getResources(const QList<QByteArray> &resourceFilter, c
56 const auto configuredResources = ResourceConfig::getResources(); 55 const auto configuredResources = ResourceConfig::getResources();
57 if (resourceFilter.isEmpty()) { 56 if (resourceFilter.isEmpty()) {
58 for (const auto &res : configuredResources.keys()) { 57 for (const auto &res : configuredResources.keys()) {
59 //TODO filter by entity type 58 // TODO filter by entity type
60 resources << res; 59 resources << res;
61 } 60 }
62 } else { 61 } else {
@@ -82,7 +81,7 @@ QSharedPointer<QAbstractItemModel> Store::loadModel(Query query)
82 Trace() << " Ids: " << query.ids; 81 Trace() << " Ids: " << query.ids;
83 Trace() << " IsLive: " << query.liveQuery; 82 Trace() << " IsLive: " << query.liveQuery;
84 Trace() << " Sorting: " << query.sortProperty; 83 Trace() << " Sorting: " << query.sortProperty;
85 auto model = QSharedPointer<ModelResult<DomainType, typename DomainType::Ptr> >::create(query, query.requestedProperties); 84 auto model = QSharedPointer<ModelResult<DomainType, typename DomainType::Ptr>>::create(query, query.requestedProperties);
86 85
87 //* Client defines lifetime of model 86 //* Client defines lifetime of model
88 //* The model lifetime defines the duration of live-queries 87 //* The model lifetime defines the duration of live-queries
@@ -95,120 +94,117 @@ QSharedPointer<QAbstractItemModel> Store::loadModel(Query query)
95 auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create(); 94 auto aggregatingEmitter = AggregatingResultEmitter<typename DomainType::Ptr>::Ptr::create();
96 model->setEmitter(aggregatingEmitter); 95 model->setEmitter(aggregatingEmitter);
97 KAsync::iterate(resources) 96 KAsync::iterate(resources)
98 .template each<void, QByteArray>([query, aggregatingEmitter](const QByteArray &resource, KAsync::Future<void> &future) { 97 .template each<void, QByteArray>([query, aggregatingEmitter](const QByteArray &resource, KAsync::Future<void> &future) {
99 auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resource), resource); 98 auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resource), resource);
100 if (facade) { 99 if (facade) {
101 Trace() << "Trying to fetch from resource " << resource; 100 Trace() << "Trying to fetch from resource " << resource;
102 auto result = facade->load(query); 101 auto result = facade->load(query);
103 aggregatingEmitter->addEmitter(result.second); 102 aggregatingEmitter->addEmitter(result.second);
104 result.first.template then<void>([&future](){future.setFinished();}).exec(); 103 result.first.template then<void>([&future]() { future.setFinished(); }).exec();
105 } else { 104 } else {
106 Trace() << "Couldn' find a facade for " << resource; 105 Trace() << "Couldn' find a facade for " << resource;
107 //Ignore the error and carry on 106 // Ignore the error and carry on
108 future.setFinished(); 107 future.setFinished();
109 } 108 }
110 }).exec(); 109 })
110 .exec();
111 model->fetchMore(QModelIndex()); 111 model->fetchMore(QModelIndex());
112 112
113 return model; 113 return model;
114} 114}
115 115
116template <class DomainType> 116template <class DomainType>
117static std::shared_ptr<StoreFacade<DomainType> > getFacade(const QByteArray &resourceInstanceIdentifier) 117static std::shared_ptr<StoreFacade<DomainType>> getFacade(const QByteArray &resourceInstanceIdentifier)
118{ 118{
119 if (auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resourceInstanceIdentifier), resourceInstanceIdentifier)) { 119 if (auto facade = FacadeFactory::instance().getFacade<DomainType>(resourceName(resourceInstanceIdentifier), resourceInstanceIdentifier)) {
120 return facade; 120 return facade;
121 } 121 }
122 return std::make_shared<NullFacade<DomainType> >(); 122 return std::make_shared<NullFacade<DomainType>>();
123} 123}
124 124
125template <class DomainType> 125template <class DomainType>
126KAsync::Job<void> Store::create(const DomainType &domainObject) { 126KAsync::Job<void> Store::create(const DomainType &domainObject)
127 //Potentially move to separate thread as well 127{
128 // Potentially move to separate thread as well
128 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier()); 129 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
129 return facade->create(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) { 130 return facade->create(domainObject).template then<void>([facade]() {}, [](int errorCode, const QString &error) { Warning() << "Failed to create"; });
130 Warning() << "Failed to create";
131 });
132} 131}
133 132
134template <class DomainType> 133template <class DomainType>
135KAsync::Job<void> Store::modify(const DomainType &domainObject) 134KAsync::Job<void> Store::modify(const DomainType &domainObject)
136{ 135{
137 //Potentially move to separate thread as well 136 // Potentially move to separate thread as well
138 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier()); 137 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
139 return facade->modify(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) { 138 return facade->modify(domainObject).template then<void>([facade]() {}, [](int errorCode, const QString &error) { Warning() << "Failed to modify"; });
140 Warning() << "Failed to modify";
141 });
142} 139}
143 140
144template <class DomainType> 141template <class DomainType>
145KAsync::Job<void> Store::remove(const DomainType &domainObject) 142KAsync::Job<void> Store::remove(const DomainType &domainObject)
146{ 143{
147 //Potentially move to separate thread as well 144 // Potentially move to separate thread as well
148 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier()); 145 auto facade = getFacade<DomainType>(domainObject.resourceInstanceIdentifier());
149 return facade->remove(domainObject).template then<void>([facade](){}, [](int errorCode, const QString &error) { 146 return facade->remove(domainObject).template then<void>([facade]() {}, [](int errorCode, const QString &error) { Warning() << "Failed to remove"; });
150 Warning() << "Failed to remove";
151 });
152} 147}
153 148
154KAsync::Job<void> Store::removeDataFromDisk(const QByteArray &identifier) 149KAsync::Job<void> Store::removeDataFromDisk(const QByteArray &identifier)
155{ 150{
156 //All databases are going to become invalid, nuke the environments 151 // All databases are going to become invalid, nuke the environments
157 //TODO: all clients should react to a notification the resource 152 // TODO: all clients should react to a notification the resource
158 Sink::Storage::clearEnv(); 153 Sink::Storage::clearEnv();
159 Trace() << "Remove data from disk " << identifier; 154 Trace() << "Remove data from disk " << identifier;
160 auto time = QSharedPointer<QTime>::create(); 155 auto time = QSharedPointer<QTime>::create();
161 time->start(); 156 time->start();
162 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier); 157 auto resourceAccess = ResourceAccessFactory::instance().getAccess(identifier);
163 resourceAccess->open(); 158 resourceAccess->open();
164 return resourceAccess->sendCommand(Sink::Commands::RemoveFromDiskCommand).then<void>([resourceAccess, time]() { 159 return resourceAccess->sendCommand(Sink::Commands::RemoveFromDiskCommand)
165 Trace() << "Remove from disk complete." << Log::TraceTime(time->elapsed()); 160 .then<void>([resourceAccess, time]() { Trace() << "Remove from disk complete." << Log::TraceTime(time->elapsed()); });
166 });
167} 161}
168 162
169KAsync::Job<void> Store::synchronize(const Sink::Query &query) 163KAsync::Job<void> Store::synchronize(const Sink::Query &query)
170{ 164{
171 Trace() << "synchronize" << query.resources; 165 Trace() << "synchronize" << query.resources;
172 return KAsync::iterate(query.resources) 166 return KAsync::iterate(query.resources)
173 .template each<void, QByteArray>([query](const QByteArray &resource, KAsync::Future<void> &future) { 167 .template each<void, QByteArray>([query](const QByteArray &resource, KAsync::Future<void> &future) {
174 Trace() << "Synchronizing " << resource; 168 Trace() << "Synchronizing " << resource;
175 auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource); 169 auto resourceAccess = ResourceAccessFactory::instance().getAccess(resource);
176 resourceAccess->open(); 170 resourceAccess->open();
177 resourceAccess->synchronizeResource(true, false).then<void>([&future, resourceAccess]() { 171 resourceAccess->synchronizeResource(true, false).then<void>([&future, resourceAccess]() { future.setFinished(); }).exec();
178 future.setFinished(); 172 });
179 }).exec();
180 });
181} 173}
182 174
183template <class DomainType> 175template <class DomainType>
184KAsync::Job<DomainType> Store::fetchOne(const Sink::Query &query) 176KAsync::Job<DomainType> Store::fetchOne(const Sink::Query &query)
185{ 177{
186 return KAsync::start<DomainType>([query](KAsync::Future<DomainType> &future) { 178 return KAsync::start<DomainType>([query](KAsync::Future<DomainType> &future) {
187 //FIXME We could do this more elegantly if composed jobs would have the correct type (In that case we'd simply return the value from then continuation, and could avoid the outer job entirely) 179 // FIXME We could do this more elegantly if composed jobs would have the correct type (In that case we'd simply return the value from then continuation, and could avoid the
180 // outer job entirely)
188 fetch<DomainType>(query, 1) 181 fetch<DomainType>(query, 1)
189 .template then<void, QList<typename DomainType::Ptr> >([&future](const QList<typename DomainType::Ptr> &list){ 182 .template then<void, QList<typename DomainType::Ptr>>(
190 future.setValue(*list.first()); 183 [&future](const QList<typename DomainType::Ptr> &list) {
191 future.setFinished(); 184 future.setValue(*list.first());
192 }, [&future](int errorCode, const QString &errorMessage) { 185 future.setFinished();
193 future.setError(errorCode, errorMessage); 186 },
194 future.setFinished(); 187 [&future](int errorCode, const QString &errorMessage) {
195 }).exec(); 188 future.setError(errorCode, errorMessage);
189 future.setFinished();
190 })
191 .exec();
196 }); 192 });
197} 193}
198 194
199template <class DomainType> 195template <class DomainType>
200KAsync::Job<QList<typename DomainType::Ptr> > Store::fetchAll(const Sink::Query &query) 196KAsync::Job<QList<typename DomainType::Ptr>> Store::fetchAll(const Sink::Query &query)
201{ 197{
202 return fetch<DomainType>(query); 198 return fetch<DomainType>(query);
203} 199}
204 200
205template <class DomainType> 201template <class DomainType>
206KAsync::Job<QList<typename DomainType::Ptr> > Store::fetch(const Sink::Query &query, int minimumAmount) 202KAsync::Job<QList<typename DomainType::Ptr>> Store::fetch(const Sink::Query &query, int minimumAmount)
207{ 203{
208 auto model = loadModel<DomainType>(query); 204 auto model = loadModel<DomainType>(query);
209 auto list = QSharedPointer<QList<typename DomainType::Ptr> >::create(); 205 auto list = QSharedPointer<QList<typename DomainType::Ptr>>::create();
210 auto context = QSharedPointer<QObject>::create(); 206 auto context = QSharedPointer<QObject>::create();
211 return KAsync::start<QList<typename DomainType::Ptr> >([model, list, context, minimumAmount](KAsync::Future<QList<typename DomainType::Ptr> > &future) { 207 return KAsync::start<QList<typename DomainType::Ptr>>([model, list, context, minimumAmount](KAsync::Future<QList<typename DomainType::Ptr>> &future) {
212 if (model->rowCount() >= 1) { 208 if (model->rowCount() >= 1) {
213 for (int i = 0; i < model->rowCount(); i++) { 209 for (int i = 0; i < model->rowCount(); i++) {
214 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>()); 210 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>());
@@ -219,16 +215,17 @@ KAsync::Job<QList<typename DomainType::Ptr> > Store::fetch(const Sink::Query &qu
219 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>()); 215 list->append(model->index(i, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).template value<typename DomainType::Ptr>());
220 } 216 }
221 }); 217 });
222 QObject::connect(model.data(), &QAbstractItemModel::dataChanged, context.data(), [model, &future, list, minimumAmount](const QModelIndex &, const QModelIndex &, const QVector<int> &roles) { 218 QObject::connect(model.data(), &QAbstractItemModel::dataChanged, context.data(),
223 if (roles.contains(ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole)) { 219 [model, &future, list, minimumAmount](const QModelIndex &, const QModelIndex &, const QVector<int> &roles) {
224 if (list->size() < minimumAmount) { 220 if (roles.contains(ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole)) {
225 future.setError(1, "Not enough values."); 221 if (list->size() < minimumAmount) {
226 } else { 222 future.setError(1, "Not enough values.");
227 future.setValue(*list); 223 } else {
224 future.setValue(*list);
225 }
226 future.setFinished();
228 } 227 }
229 future.setFinished(); 228 });
230 }
231 });
232 } 229 }
233 if (model->data(QModelIndex(), ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole).toBool()) { 230 if (model->data(QModelIndex(), ModelResult<DomainType, typename DomainType::Ptr>::ChildrenFetchedRole).toBool()) {
234 if (list->size() < minimumAmount) { 231 if (list->size() < minimumAmount) {
@@ -241,13 +238,14 @@ KAsync::Job<QList<typename DomainType::Ptr> > Store::fetch(const Sink::Query &qu
241 }); 238 });
242} 239}
243 240
244#define REGISTER_TYPE(T) template KAsync::Job<void> Store::remove<T>(const T &domainObject); \ 241#define REGISTER_TYPE(T) \
245 template KAsync::Job<void> Store::create<T>(const T &domainObject); \ 242 template KAsync::Job<void> Store::remove<T>(const T &domainObject); \
246 template KAsync::Job<void> Store::modify<T>(const T &domainObject); \ 243 template KAsync::Job<void> Store::create<T>(const T &domainObject); \
244 template KAsync::Job<void> Store::modify<T>(const T &domainObject); \
247 template QSharedPointer<QAbstractItemModel> Store::loadModel<T>(Query query); \ 245 template QSharedPointer<QAbstractItemModel> Store::loadModel<T>(Query query); \
248 template KAsync::Job<T> Store::fetchOne<T>(const Query &); \ 246 template KAsync::Job<T> Store::fetchOne<T>(const Query &); \
249 template KAsync::Job<QList<T::Ptr> > Store::fetchAll<T>(const Query &); \ 247 template KAsync::Job<QList<T::Ptr>> Store::fetchAll<T>(const Query &); \
250 template KAsync::Job<QList<T::Ptr> > Store::fetch<T>(const Query &, int); \ 248 template KAsync::Job<QList<T::Ptr>> Store::fetch<T>(const Query &, int);
251 249
252REGISTER_TYPE(ApplicationDomain::Event); 250REGISTER_TYPE(ApplicationDomain::Event);
253REGISTER_TYPE(ApplicationDomain::Mail); 251REGISTER_TYPE(ApplicationDomain::Mail);
@@ -255,4 +253,3 @@ REGISTER_TYPE(ApplicationDomain::Folder);
255REGISTER_TYPE(ApplicationDomain::SinkResource); 253REGISTER_TYPE(ApplicationDomain::SinkResource);
256 254
257} // namespace Sink 255} // namespace Sink
258
diff --git a/common/store.h b/common/store.h
index 6696833..af8e971 100644
--- a/common/store.h
+++ b/common/store.h
@@ -35,7 +35,7 @@ namespace Sink {
35 35
36/** 36/**
37 * The unified Sink Store. 37 * The unified Sink Store.
38 * 38 *
39 * This is the primary interface for clients to interact with Sink. 39 * This is the primary interface for clients to interact with Sink.
40 * It provides a unified store where all data provided by various resources can be accessed and modified. 40 * It provides a unified store where all data provided by various resources can be accessed and modified.
41 */ 41 */
@@ -43,8 +43,9 @@ namespace Store {
43 43
44QString SINK_EXPORT storageLocation(); 44QString SINK_EXPORT storageLocation();
45 45
46enum Roles { 46enum Roles
47 DomainObjectRole = Qt::UserRole + 1, //Must be the same as in ModelResult 47{
48 DomainObjectRole = Qt::UserRole + 1, // Must be the same as in ModelResult
48 ChildrenFetchedRole, 49 ChildrenFetchedRole,
49 DomainObjectBaseRole 50 DomainObjectBaseRole
50}; 51};
@@ -63,7 +64,7 @@ KAsync::Job<void> SINK_EXPORT create(const DomainType &domainObject);
63 64
64/** 65/**
65 * Modify an entity. 66 * Modify an entity.
66 * 67 *
67 * This includes moving etc. since these are also simple settings on a property. 68 * This includes moving etc. since these are also simple settings on a property.
68 */ 69 */
69template <class DomainType> 70template <class DomainType>
@@ -82,7 +83,7 @@ KAsync::Job<void> SINK_EXPORT synchronize(const Sink::Query &query);
82 83
83/** 84/**
84 * Removes all resource data from disk. 85 * Removes all resource data from disk.
85 * 86 *
86 * This will not touch the configuration. All commands that that arrived at the resource before this command will be dropped. All commands that arrived later will be executed. 87 * This will not touch the configuration. All commands that that arrived at the resource before this command will be dropped. All commands that arrived later will be executed.
87 */ 88 */
88KAsync::Job<void> SINK_EXPORT removeDataFromDisk(const QByteArray &resourceIdentifier); 89KAsync::Job<void> SINK_EXPORT removeDataFromDisk(const QByteArray &resourceIdentifier);
@@ -91,11 +92,9 @@ template <class DomainType>
91KAsync::Job<DomainType> SINK_EXPORT fetchOne(const Sink::Query &query); 92KAsync::Job<DomainType> SINK_EXPORT fetchOne(const Sink::Query &query);
92 93
93template <class DomainType> 94template <class DomainType>
94KAsync::Job<QList<typename DomainType::Ptr> > SINK_EXPORT fetchAll(const Sink::Query &query); 95KAsync::Job<QList<typename DomainType::Ptr>> SINK_EXPORT fetchAll(const Sink::Query &query);
95 96
96template <class DomainType> 97template <class DomainType>
97KAsync::Job<QList<typename DomainType::Ptr> > SINK_EXPORT fetch(const Sink::Query &query, int minimumAmount = 0); 98KAsync::Job<QList<typename DomainType::Ptr>> SINK_EXPORT fetch(const Sink::Query &query, int minimumAmount = 0);
98 99}
99 }
100} 100}
101
diff --git a/common/synclistresult.h b/common/synclistresult.h
index 055714f..344c0ef 100644
--- a/common/synclistresult.h
+++ b/common/synclistresult.h
@@ -16,16 +16,13 @@ namespace async {
16* 16*
17* WARNING: The nested eventloop can cause all sorts of trouble. Use only in testing code. 17* WARNING: The nested eventloop can cause all sorts of trouble. Use only in testing code.
18*/ 18*/
19template<class T> 19template <class T>
20class SyncListResult : public QList<T> { 20class SyncListResult : public QList<T>
21{
21public: 22public:
22 SyncListResult(const QSharedPointer<Sink::ResultEmitter<T> > &emitter) 23 SyncListResult(const QSharedPointer<Sink::ResultEmitter<T>> &emitter) : QList<T>(), mEmitter(emitter)
23 :QList<T>(),
24 mEmitter(emitter)
25 { 24 {
26 emitter->onAdded([this](const T &value) { 25 emitter->onAdded([this](const T &value) { this->append(value); });
27 this->append(value);
28 });
29 emitter->onModified([this](const T &value) { 26 emitter->onModified([this](const T &value) {
30 for (auto it = this->begin(); it != this->end(); it++) { 27 for (auto it = this->begin(); it != this->end(); it++) {
31 if (**it == *value) { 28 if (**it == *value) {
@@ -46,16 +43,12 @@ public:
46 emitter->onInitialResultSetComplete([this]() { 43 emitter->onInitialResultSetComplete([this]() {
47 if (eventLoopAborter) { 44 if (eventLoopAborter) {
48 eventLoopAborter(); 45 eventLoopAborter();
49 //Be safe in case of a second invocation of the complete handler 46 // Be safe in case of a second invocation of the complete handler
50 eventLoopAborter = std::function<void()>(); 47 eventLoopAborter = std::function<void()>();
51 } 48 }
52 }); 49 });
53 emitter->onComplete([this]() { 50 emitter->onComplete([this]() { mEmitter.clear(); });
54 mEmitter.clear(); 51 emitter->onClear([this]() { this->clear(); });
55 });
56 emitter->onClear([this]() {
57 this->clear();
58 });
59 } 52 }
60 53
61 void exec() 54 void exec()
@@ -66,8 +59,7 @@ public:
66 } 59 }
67 60
68private: 61private:
69 QSharedPointer<Sink::ResultEmitter<T> > mEmitter; 62 QSharedPointer<Sink::ResultEmitter<T>> mEmitter;
70 std::function<void()> eventLoopAborter; 63 std::function<void()> eventLoopAborter;
71}; 64};
72
73} 65}
diff --git a/common/threadboundary.cpp b/common/threadboundary.cpp
index 238f5b4..705009b 100644
--- a/common/threadboundary.cpp
+++ b/common/threadboundary.cpp
@@ -23,13 +23,12 @@
23Q_DECLARE_METATYPE(std::function<void()>); 23Q_DECLARE_METATYPE(std::function<void()>);
24 24
25namespace async { 25namespace async {
26ThreadBoundary::ThreadBoundary() 26ThreadBoundary::ThreadBoundary() : QObject()
27 : QObject()
28{ 27{
29 qRegisterMetaType<std::function<void()> >("std::function<void()>"); 28 qRegisterMetaType<std::function<void()>>("std::function<void()>");
30} 29}
31 30
32ThreadBoundary:: ~ThreadBoundary() 31ThreadBoundary::~ThreadBoundary()
33{ 32{
34} 33}
35 34
@@ -47,6 +46,4 @@ void ThreadBoundary::runInMainThread(std::function<void()> f)
47{ 46{
48 f(); 47 f();
49} 48}
50
51} 49}
52
diff --git a/common/threadboundary.h b/common/threadboundary.h
index 7bea4ea..dd86b20 100644
--- a/common/threadboundary.h
+++ b/common/threadboundary.h
@@ -31,17 +31,17 @@ namespace async {
31* A helper class to invoke a method in a different thread using the event loop. 31* A helper class to invoke a method in a different thread using the event loop.
32* The ThreadBoundary object must live in the thread where the function should be called. 32* The ThreadBoundary object must live in the thread where the function should be called.
33*/ 33*/
34class SINK_EXPORT ThreadBoundary : public QObject { 34class SINK_EXPORT ThreadBoundary : public QObject
35{
35 Q_OBJECT 36 Q_OBJECT
36public: 37public:
37 ThreadBoundary(); 38 ThreadBoundary();
38 virtual ~ThreadBoundary(); 39 virtual ~ThreadBoundary();
39 40
40 //Call in worker thread 41 // Call in worker thread
41 void callInMainThread(std::function<void()> f); 42 void callInMainThread(std::function<void()> f);
42public slots: 43public slots:
43 //Get's called in main thread by it's eventloop 44 // Get's called in main thread by it's eventloop
44 void runInMainThread(std::function<void()> f); 45 void runInMainThread(std::function<void()> f);
45}; 46};
46
47} 47}
diff --git a/common/typeindex.cpp b/common/typeindex.cpp
index ddf5df5..1321469 100644
--- a/common/typeindex.cpp
+++ b/common/typeindex.cpp
@@ -30,13 +30,13 @@ static QByteArray getByteArray(const QVariant &value)
30 if (value.isValid() && !value.toByteArray().isEmpty()) { 30 if (value.isValid() && !value.toByteArray().isEmpty()) {
31 return value.toByteArray(); 31 return value.toByteArray();
32 } 32 }
33 //LMDB can't handle empty keys, so use something different 33 // LMDB can't handle empty keys, so use something different
34 return "toplevel"; 34 return "toplevel";
35} 35}
36 36
37static QByteArray toSortableByteArray(const QDateTime &date) 37static QByteArray toSortableByteArray(const QDateTime &date)
38{ 38{
39 //Sort invalid last 39 // Sort invalid last
40 if (!date.isValid()) { 40 if (!date.isValid()) {
41 return QByteArray::number(std::numeric_limits<unsigned int>::max()); 41 return QByteArray::number(std::numeric_limits<unsigned int>::max());
42 } 42 }
@@ -44,10 +44,8 @@ static QByteArray toSortableByteArray(const QDateTime &date)
44} 44}
45 45
46 46
47TypeIndex::TypeIndex(const QByteArray &type) 47TypeIndex::TypeIndex(const QByteArray &type) : mType(type)
48 : mType(type)
49{ 48{
50
51} 49}
52 50
53QByteArray TypeIndex::indexName(const QByteArray &property, const QByteArray &sortProperty) const 51QByteArray TypeIndex::indexName(const QByteArray &property, const QByteArray &sortProperty) const
@@ -58,7 +56,7 @@ QByteArray TypeIndex::indexName(const QByteArray &property, const QByteArray &so
58 return mType + ".index." + property + ".sort." + sortProperty; 56 return mType + ".index." + property + ".sort." + sortProperty;
59} 57}
60 58
61template<> 59template <>
62void TypeIndex::addProperty<QByteArray>(const QByteArray &property) 60void TypeIndex::addProperty<QByteArray>(const QByteArray &property)
63{ 61{
64 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) { 62 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) {
@@ -69,7 +67,7 @@ void TypeIndex::addProperty<QByteArray>(const QByteArray &property)
69 mProperties << property; 67 mProperties << property;
70} 68}
71 69
72template<> 70template <>
73void TypeIndex::addProperty<QString>(const QByteArray &property) 71void TypeIndex::addProperty<QString>(const QByteArray &property)
74{ 72{
75 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) { 73 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) {
@@ -80,7 +78,7 @@ void TypeIndex::addProperty<QString>(const QByteArray &property)
80 mProperties << property; 78 mProperties << property;
81} 79}
82 80
83template<> 81template <>
84void TypeIndex::addProperty<QDateTime>(const QByteArray &property) 82void TypeIndex::addProperty<QDateTime>(const QByteArray &property)
85{ 83{
86 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) { 84 auto indexer = [this, property](const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction) {
@@ -94,7 +92,7 @@ void TypeIndex::addProperty<QDateTime>(const QByteArray &property)
94 mProperties << property; 92 mProperties << property;
95} 93}
96 94
97template<> 95template <>
98void TypeIndex::addPropertyWithSorting<QByteArray, QDateTime>(const QByteArray &property, const QByteArray &sortProperty) 96void TypeIndex::addPropertyWithSorting<QByteArray, QDateTime>(const QByteArray &property, const QByteArray &sortProperty)
99{ 97{
100 auto indexer = [=](const QByteArray &identifier, const QVariant &value, const QVariant &sortValue, Sink::Storage::Transaction &transaction) { 98 auto indexer = [=](const QByteArray &identifier, const QVariant &value, const QVariant &sortValue, Sink::Storage::Transaction &transaction) {
@@ -102,7 +100,7 @@ void TypeIndex::addPropertyWithSorting<QByteArray, QDateTime>(const QByteArray &
102 const auto propertyValue = getByteArray(value); 100 const auto propertyValue = getByteArray(value);
103 Index(indexName(property, sortProperty), transaction).add(propertyValue + toSortableByteArray(date), identifier); 101 Index(indexName(property, sortProperty), transaction).add(propertyValue + toSortableByteArray(date), identifier);
104 }; 102 };
105 mSortIndexer.insert(property+sortProperty, indexer); 103 mSortIndexer.insert(property + sortProperty, indexer);
106 mSortedProperties.insert(property, sortProperty); 104 mSortedProperties.insert(property, sortProperty);
107} 105}
108 106
@@ -116,7 +114,7 @@ void TypeIndex::add(const QByteArray &identifier, const Sink::ApplicationDomain:
116 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) { 114 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) {
117 const auto value = bufferAdaptor.getProperty(it.key()); 115 const auto value = bufferAdaptor.getProperty(it.key());
118 const auto sortValue = bufferAdaptor.getProperty(it.value()); 116 const auto sortValue = bufferAdaptor.getProperty(it.value());
119 auto indexer = mSortIndexer.value(it.key()+it.value()); 117 auto indexer = mSortIndexer.value(it.key() + it.value());
120 indexer(identifier, value, sortValue, transaction); 118 indexer(identifier, value, sortValue, transaction);
121 } 119 }
122} 120}
@@ -125,7 +123,7 @@ void TypeIndex::remove(const QByteArray &identifier, const Sink::ApplicationDoma
125{ 123{
126 for (const auto &property : mProperties) { 124 for (const auto &property : mProperties) {
127 const auto value = bufferAdaptor.getProperty(property); 125 const auto value = bufferAdaptor.getProperty(property);
128 //FIXME don't always convert to byte array 126 // FIXME don't always convert to byte array
129 Index(indexName(property), transaction).remove(getByteArray(value), identifier); 127 Index(indexName(property), transaction).remove(getByteArray(value), identifier);
130 } 128 }
131 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) { 129 for (auto it = mSortedProperties.constBegin(); it != mSortedProperties.constEnd(); it++) {
@@ -147,12 +145,8 @@ ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFi
147 Index index(indexName(it.key(), it.value()), transaction); 145 Index index(indexName(it.key(), it.value()), transaction);
148 const auto lookupKey = getByteArray(query.propertyFilter.value(it.key())); 146 const auto lookupKey = getByteArray(query.propertyFilter.value(it.key()));
149 Trace() << "looking for " << lookupKey; 147 Trace() << "looking for " << lookupKey;
150 index.lookup(lookupKey, [&](const QByteArray &value) { 148 index.lookup(lookupKey, [&](const QByteArray &value) { keys << value; },
151 keys << value; 149 [it](const Index::Error &error) { Warning() << "Error in index: " << error.message << it.key() << it.value(); }, true);
152 },
153 [it](const Index::Error &error) {
154 Warning() << "Error in index: " << error.message << it.key() << it.value();
155 }, true);
156 appliedFilters << it.key(); 150 appliedFilters << it.key();
157 appliedSorting = it.value(); 151 appliedSorting = it.value();
158 Trace() << "Index lookup on " << it.key() << it.value() << " found " << keys.size() << " keys."; 152 Trace() << "Index lookup on " << it.key() << it.value() << " found " << keys.size() << " keys.";
@@ -163,12 +157,8 @@ ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFi
163 if (query.propertyFilter.contains(property)) { 157 if (query.propertyFilter.contains(property)) {
164 Index index(indexName(property), transaction); 158 Index index(indexName(property), transaction);
165 const auto lookupKey = getByteArray(query.propertyFilter.value(property)); 159 const auto lookupKey = getByteArray(query.propertyFilter.value(property));
166 index.lookup(lookupKey, [&](const QByteArray &value) { 160 index.lookup(
167 keys << value; 161 lookupKey, [&](const QByteArray &value) { keys << value; }, [property](const Index::Error &error) { Warning() << "Error in index: " << error.message << property; });
168 },
169 [property](const Index::Error &error) {
170 Warning() << "Error in index: " << error.message << property;
171 });
172 appliedFilters << property; 162 appliedFilters << property;
173 Trace() << "Index lookup on " << property << " found " << keys.size() << " keys."; 163 Trace() << "Index lookup on " << property << " found " << keys.size() << " keys.";
174 return ResultSet(keys); 164 return ResultSet(keys);
@@ -177,4 +167,3 @@ ResultSet TypeIndex::query(const Sink::Query &query, QSet<QByteArray> &appliedFi
177 Trace() << "No matching index"; 167 Trace() << "No matching index";
178 return ResultSet(keys); 168 return ResultSet(keys);
179} 169}
180
diff --git a/common/typeindex.h b/common/typeindex.h
index c19780c..a16179c 100644
--- a/common/typeindex.h
+++ b/common/typeindex.h
@@ -29,9 +29,9 @@ class TypeIndex
29public: 29public:
30 TypeIndex(const QByteArray &type); 30 TypeIndex(const QByteArray &type);
31 31
32 template<typename T> 32 template <typename T>
33 void addProperty(const QByteArray &property); 33 void addProperty(const QByteArray &property);
34 template<typename T, typename S> 34 template <typename T, typename S>
35 void addPropertyWithSorting(const QByteArray &property, const QByteArray &sortProperty); 35 void addPropertyWithSorting(const QByteArray &property, const QByteArray &sortProperty);
36 36
37 void add(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction); 37 void add(const QByteArray &identifier, const Sink::ApplicationDomain::BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction);
@@ -44,7 +44,6 @@ private:
44 QByteArray mType; 44 QByteArray mType;
45 QByteArrayList mProperties; 45 QByteArrayList mProperties;
46 QMap<QByteArray, QByteArray> mSortedProperties; 46 QMap<QByteArray, QByteArray> mSortedProperties;
47 QHash<QByteArray, std::function<void(const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction)> > mIndexer; 47 QHash<QByteArray, std::function<void(const QByteArray &identifier, const QVariant &value, Sink::Storage::Transaction &transaction)>> mIndexer;
48 QHash<QByteArray, std::function<void(const QByteArray &identifier, const QVariant &value, const QVariant &sortValue, Sink::Storage::Transaction &transaction)> > mSortIndexer; 48 QHash<QByteArray, std::function<void(const QByteArray &identifier, const QVariant &value, const QVariant &sortValue, Sink::Storage::Transaction &transaction)>> mSortIndexer;
49}; 49};
50