summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-03-03 09:01:05 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-03-03 09:01:05 +0100
commit4d9746c828558c9f872e0aed52442863affb25d5 (patch)
tree507d7c2ba67f47d3cbbcf01a722236ff1b48426b
parent9cea920b7dd51867a0be0fed2f461b6be73c103e (diff)
downloadsink-4d9746c828558c9f872e0aed52442863affb25d5.tar.gz
sink-4d9746c828558c9f872e0aed52442863affb25d5.zip
Fromatted the whole codebase with clang-format.
clang-format -i */**{.cpp,.h}
-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
-rw-r--r--sinksh/main.cpp12
-rw-r--r--sinksh/sinksh_utils.cpp32
-rw-r--r--sinksh/sinksh_utils.h38
-rw-r--r--sinksh/state.cpp7
-rw-r--r--sinksh/state.h3
-rw-r--r--sinksh/syntaxtree.cpp18
-rw-r--r--sinksh/syntaxtree.h9
-rw-r--r--sinksh/utils.cpp6
-rw-r--r--sinksh/utils.h4
-rw-r--r--synchronizer/main.cpp34
-rw-r--r--tests/clientapitest.cpp76
-rw-r--r--tests/databasepopulationandfacadequerybenchmark.cpp61
-rw-r--r--tests/domainadaptortest.cpp12
-rw-r--r--tests/dummyresourcebenchmark.cpp78
-rw-r--r--tests/dummyresourcetest.cpp35
-rw-r--r--tests/dummyresourcewritebenchmark.cpp32
-rw-r--r--tests/genericfacadetest.cpp24
-rw-r--r--tests/genericresourcebenchmark.cpp22
-rw-r--r--tests/genericresourcetest.cpp6
-rw-r--r--tests/getrssusage.cpp106
-rw-r--r--tests/getrssusage.h2
-rw-r--r--tests/indextest.cpp23
-rw-r--r--tests/inspectiontest.cpp2
-rw-r--r--tests/maildirresourcetest.cpp205
-rw-r--r--tests/maildirsyncbenchmark.cpp12
-rw-r--r--tests/mailquerybenchmark.cpp45
-rw-r--r--tests/messagequeuetest.cpp85
-rw-r--r--tests/modelinteractivitytest.cpp27
-rw-r--r--tests/pipelinebenchmark.cpp21
-rw-r--r--tests/pipelinetest.cpp52
-rw-r--r--tests/querytest.cpp72
-rw-r--r--tests/resourcecommunicationtest.cpp34
-rw-r--r--tests/storagebenchmark.cpp34
-rw-r--r--tests/storagetest.cpp259
-rw-r--r--tests/testimplementations.h45
97 files changed, 2259 insertions, 2411 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
diff --git a/sinksh/main.cpp b/sinksh/main.cpp
index 4c00b9b..84f532d 100644
--- a/sinksh/main.cpp
+++ b/sinksh/main.cpp
@@ -44,10 +44,8 @@ int enterRepl()
44 } 44 }
45 45
46 Repl *repl = new Repl; 46 Repl *repl = new Repl;
47 QObject::connect(repl, &QStateMachine::finished, 47 QObject::connect(repl, &QStateMachine::finished, repl, &QObject::deleteLater);
48 repl, &QObject::deleteLater); 48 QObject::connect(repl, &QStateMachine::finished, QCoreApplication::instance(), &QCoreApplication::quit);
49 QObject::connect(repl, &QStateMachine::finished,
50 QCoreApplication::instance(), &QCoreApplication::quit);
51 49
52 State::setHasEventLoop(true); 50 State::setHasEventLoop(true);
53 int rv = QCoreApplication::instance()->exec(); 51 int rv = QCoreApplication::instance()->exec();
@@ -86,10 +84,10 @@ int main(int argc, char *argv[])
86{ 84{
87 const bool interactive = isatty(fileno(stdin)); 85 const bool interactive = isatty(fileno(stdin));
88 const bool startRepl = (argc == 1) && interactive; 86 const bool startRepl = (argc == 1) && interactive;
89 //TODO: make a json command parse cause that would be awesomesauce 87 // TODO: make a json command parse cause that would be awesomesauce
90 const bool fromScript = !startRepl && QFile::exists(argv[1]); 88 const bool fromScript = !startRepl && QFile::exists(argv[1]);
91 89
92 //qDebug() << "state at startup is" << interactive << startRepl << fromScript; 90 // qDebug() << "state at startup is" << interactive << startRepl << fromScript;
93 91
94 QCoreApplication app(argc, argv); 92 QCoreApplication app(argc, argv);
95 app.setApplicationName(fromScript ? "interactive-app-shell" : argv[0]); 93 app.setApplicationName(fromScript ? "interactive-app-shell" : argv[0]);
@@ -98,7 +96,7 @@ int main(int argc, char *argv[])
98 return enterRepl(); 96 return enterRepl();
99 } else if (fromScript) { 97 } else if (fromScript) {
100 QFile f(argv[1]); 98 QFile f(argv[1]);
101 if (!f.open(QIODevice::ReadOnly)) { 99 if (!f.open(QIODevice::ReadOnly)) {
102 return 1; 100 return 1;
103 } 101 }
104 102
diff --git a/sinksh/sinksh_utils.cpp b/sinksh/sinksh_utils.cpp
index d5b1c22..9ff966b 100644
--- a/sinksh/sinksh_utils.cpp
+++ b/sinksh/sinksh_utils.cpp
@@ -24,10 +24,12 @@
24 24
25#include "utils.h" 25#include "utils.h"
26 26
27namespace SinkshUtils 27namespace SinkshUtils {
28{
29 28
30static QStringList s_types = QStringList() << "resource" << "folder" << "mail" << "event"; 29static QStringList s_types = QStringList() << "resource"
30 << "folder"
31 << "mail"
32 << "event";
31 33
32bool isValidStoreType(const QString &type) 34bool isValidStoreType(const QString &type)
33{ 35{
@@ -50,9 +52,9 @@ StoreBase &getStore(const QString &type)
50 return store; 52 return store;
51 } 53 }
52 54
53 //TODO: reinstate the warning+assert 55 // TODO: reinstate the warning+assert
54 //Q_ASSERT(false); 56 // Q_ASSERT(false);
55 //qWarning() << "Trying to get a store that doesn't exist, falling back to event"; 57 // qWarning() << "Trying to get a store that doesn't exist, falling back to event";
56 static Store<Sink::ApplicationDomain::Event> store; 58 static Store<Sink::ApplicationDomain::Event> store;
57 return store; 59 return store;
58} 60}
@@ -60,9 +62,12 @@ StoreBase &getStore(const QString &type)
60QSharedPointer<QAbstractItemModel> loadModel(const QString &type, Sink::Query query) 62QSharedPointer<QAbstractItemModel> loadModel(const QString &type, Sink::Query query)
61{ 63{
62 if (type == "folder") { 64 if (type == "folder") {
63 query.requestedProperties << "name" << "parent"; 65 query.requestedProperties << "name"
66 << "parent";
64 } else if (type == "mail") { 67 } else if (type == "mail") {
65 query.requestedProperties << "subject" << "folder" << "date"; 68 query.requestedProperties << "subject"
69 << "folder"
70 << "date";
66 } else if (type == "event") { 71 } else if (type == "event") {
67 query.requestedProperties << "summary"; 72 query.requestedProperties << "summary";
68 } else if (type == "resource") { 73 } else if (type == "resource") {
@@ -80,7 +85,7 @@ QStringList resourceIds(State &state)
80 query.liveQuery = false; 85 query.liveQuery = false;
81 auto model = SinkshUtils::loadModel("resource", query); 86 auto model = SinkshUtils::loadModel("resource", query);
82 87
83 QObject::connect(model.data(), &QAbstractItemModel::rowsInserted, [model, &resources] (const QModelIndex &index, int start, int end) mutable { 88 QObject::connect(model.data(), &QAbstractItemModel::rowsInserted, [model, &resources](const QModelIndex &index, int start, int end) mutable {
84 for (int i = start; i <= end; i++) { 89 for (int i = start; i <= end; i++) {
85 auto object = model->data(model->index(i, 0, index), Sink::Store::DomainObjectBaseRole).value<Sink::ApplicationDomain::ApplicationDomainType::Ptr>(); 90 auto object = model->data(model->index(i, 0, index), Sink::Store::DomainObjectBaseRole).value<Sink::ApplicationDomain::ApplicationDomainType::Ptr>();
86 resources << object->identifier(); 91 resources << object->identifier();
@@ -105,7 +110,10 @@ QStringList resourceCompleter(const QStringList &, const QString &fragment, Stat
105 110
106QStringList resourceOrTypeCompleter(const QStringList &commands, const QString &fragment, State &state) 111QStringList resourceOrTypeCompleter(const QStringList &commands, const QString &fragment, State &state)
107{ 112{
108 static QStringList types = QStringList() << "resource" << "folder" << "mail" << "event"; 113 static QStringList types = QStringList() << "resource"
114 << "folder"
115 << "mail"
116 << "event";
109 if (commands.count() == 1) { 117 if (commands.count() == 1) {
110 return Utils::filteredCompletions(s_types, fragment); 118 return Utils::filteredCompletions(s_types, fragment);
111 } 119 }
@@ -120,7 +128,7 @@ QStringList typeCompleter(const QStringList &commands, const QString &fragment,
120 128
121QMap<QString, QString> keyValueMapFromArgs(const QStringList &args) 129QMap<QString, QString> keyValueMapFromArgs(const QStringList &args)
122{ 130{
123 //TODO: this is not the most clever of algorithms. preserved during the port of commands 131 // TODO: this is not the most clever of algorithms. preserved during the port of commands
124 // from sink_client ... we can probably do better, however ;) 132 // from sink_client ... we can probably do better, however ;)
125 QMap<QString, QString> map; 133 QMap<QString, QString> map;
126 for (int i = 0; i + 2 <= args.size(); i += 2) { 134 for (int i = 0; i + 2 <= args.size(); i += 2) {
@@ -129,6 +137,4 @@ QMap<QString, QString> keyValueMapFromArgs(const QStringList &args)
129 137
130 return map; 138 return map;
131} 139}
132
133} 140}
134
diff --git a/sinksh/sinksh_utils.h b/sinksh/sinksh_utils.h
index bc4f6e5..5f470ff 100644
--- a/sinksh/sinksh_utils.h
+++ b/sinksh/sinksh_utils.h
@@ -28,8 +28,7 @@
28 28
29#include "state.h" 29#include "state.h"
30 30
31namespace SinkshUtils 31namespace SinkshUtils {
32{
33 32
34class StoreBase; 33class StoreBase;
35 34
@@ -45,9 +44,10 @@ QMap<QString, QString> keyValueMapFromArgs(const QStringList &args);
45/** 44/**
46 * A small abstraction layer to use the sink store with the type available as string. 45 * A small abstraction layer to use the sink store with the type available as string.
47 */ 46 */
48class StoreBase { 47class StoreBase
48{
49public: 49public:
50 virtual ~StoreBase() {}; 50 virtual ~StoreBase(){};
51 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() = 0; 51 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() = 0;
52 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) = 0; 52 virtual Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) = 0;
53 virtual KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) = 0; 53 virtual KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) = 0;
@@ -57,33 +57,37 @@ public:
57}; 57};
58 58
59template <typename T> 59template <typename T>
60class Store : public StoreBase { 60class Store : public StoreBase
61{
61public: 62public:
62 Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() Q_DECL_OVERRIDE { 63 Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject() Q_DECL_OVERRIDE
64 {
63 return T::Ptr::create(); 65 return T::Ptr::create();
64 } 66 }
65 67
66 Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) Q_DECL_OVERRIDE { 68 Sink::ApplicationDomain::ApplicationDomainType::Ptr getObject(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier = QByteArray()) Q_DECL_OVERRIDE
69 {
67 return T::Ptr::create(resourceInstanceIdentifier, identifier, 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 70 return T::Ptr::create(resourceInstanceIdentifier, identifier, 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
68 } 71 }
69 72
70 KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE { 73 KAsync::Job<void> create(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE
71 return Sink::Store::create<T>(*static_cast<const T*>(&type)); 74 {
75 return Sink::Store::create<T>(*static_cast<const T *>(&type));
72 } 76 }
73 77
74 KAsync::Job<void> modify(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE { 78 KAsync::Job<void> modify(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE
75 return Sink::Store::modify<T>(*static_cast<const T*>(&type)); 79 {
80 return Sink::Store::modify<T>(*static_cast<const T *>(&type));
76 } 81 }
77 82
78 KAsync::Job<void> remove(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE { 83 KAsync::Job<void> remove(const Sink::ApplicationDomain::ApplicationDomainType &type) Q_DECL_OVERRIDE
79 return Sink::Store::remove<T>(*static_cast<const T*>(&type)); 84 {
85 return Sink::Store::remove<T>(*static_cast<const T *>(&type));
80 } 86 }
81 87
82 QSharedPointer<QAbstractItemModel> loadModel(const Sink::Query &query) Q_DECL_OVERRIDE { 88 QSharedPointer<QAbstractItemModel> loadModel(const Sink::Query &query) Q_DECL_OVERRIDE
89 {
83 return Sink::Store::loadModel<T>(query); 90 return Sink::Store::loadModel<T>(query);
84 } 91 }
85}; 92};
86
87
88} 93}
89
diff --git a/sinksh/state.cpp b/sinksh/state.cpp
index e03bf87..7fd3959 100644
--- a/sinksh/state.cpp
+++ b/sinksh/state.cpp
@@ -31,8 +31,7 @@ static bool s_hasEventLoop = false;
31class State::Private 31class State::Private
32{ 32{
33public: 33public:
34 Private() 34 Private() : outStream(stdout)
35 : outStream(stdout)
36 { 35 {
37 } 36 }
38 37
@@ -51,8 +50,7 @@ public:
51 QTextStream outStream; 50 QTextStream outStream;
52}; 51};
53 52
54State::State() 53State::State() : d(new Private)
55 : d(new Private)
56{ 54{
57} 55}
58 56
@@ -141,4 +139,3 @@ QString State::loggingLevel() const
141 QByteArray rv = Sink::Log::debugLevelName(Sink::Log::debugOutputLevel()); 139 QByteArray rv = Sink::Log::debugLevelName(Sink::Log::debugOutputLevel());
142 return rv.toLower(); 140 return rv.toLower();
143} 141}
144
diff --git a/sinksh/state.h b/sinksh/state.h
index 3c4c2c7..2a0eb7c 100644
--- a/sinksh/state.h
+++ b/sinksh/state.h
@@ -47,6 +47,5 @@ public:
47 47
48private: 48private:
49 class Private; 49 class Private;
50 Private * const d; 50 Private *const d;
51}; 51};
52
diff --git a/sinksh/syntaxtree.cpp b/sinksh/syntaxtree.cpp
index 4860582..3380b04 100644
--- a/sinksh/syntaxtree.cpp
+++ b/sinksh/syntaxtree.cpp
@@ -29,10 +29,7 @@ Syntax::Syntax()
29} 29}
30 30
31Syntax::Syntax(const QString &k, const QString &helpText, std::function<bool(const QStringList &, State &)> l, Interactivity inter) 31Syntax::Syntax(const QString &k, const QString &helpText, std::function<bool(const QStringList &, State &)> l, Interactivity inter)
32 : keyword(k), 32 : keyword(k), help(helpText), interactivity(inter), lambda(l)
33 help(helpText),
34 interactivity(inter),
35 lambda(l)
36{ 33{
37} 34}
38 35
@@ -75,10 +72,10 @@ bool SyntaxTree::run(const QStringList &commands)
75 m_state.printError(QObject::tr("Broken command... sorry :("), "st_broken"); 72 m_state.printError(QObject::tr("Broken command... sorry :("), "st_broken");
76 } else { 73 } else {
77 QStringList keywordList; 74 QStringList keywordList;
78 for (auto syntax: command.first->children) { 75 for (auto syntax : command.first->children) {
79 keywordList << syntax.keyword; 76 keywordList << syntax.keyword;
80 } 77 }
81 const QString keywords = keywordList.join(" " ); 78 const QString keywords = keywordList.join(" ");
82 m_state.printError(QObject::tr("Command requires additional arguments, one of: %1").arg(keywords)); 79 m_state.printError(QObject::tr("Command requires additional arguments, one of: %1").arg(keywords));
83 } 80 }
84 } else { 81 } else {
@@ -129,9 +126,9 @@ Syntax::List SyntaxTree::nearestSyntax(const QStringList &words, const QString &
129{ 126{
130 Syntax::List matches; 127 Syntax::List matches;
131 128
132 //qDebug() << "words are" << words; 129 // qDebug() << "words are" << words;
133 if (words.isEmpty()) { 130 if (words.isEmpty()) {
134 for (const Syntax &syntax: m_syntax) { 131 for (const Syntax &syntax : m_syntax) {
135 if (syntax.keyword.startsWith(fragment)) { 132 if (syntax.keyword.startsWith(fragment)) {
136 matches.push_back(syntax); 133 matches.push_back(syntax);
137 } 134 }
@@ -153,7 +150,7 @@ Syntax::List SyntaxTree::nearestSyntax(const QStringList &words, const QString &
153 } 150 }
154 } 151 }
155 152
156 //qDebug() << "exiting with" << lastFullSyntax.keyword << words.last(); 153 // qDebug() << "exiting with" << lastFullSyntax.keyword << words.last();
157 if (lastFullSyntax.keyword == words.last()) { 154 if (lastFullSyntax.keyword == words.last()) {
158 syntaxIt = lastFullSyntax.children; 155 syntaxIt = lastFullSyntax.children;
159 while (syntaxIt.hasNext()) { 156 while (syntaxIt.hasNext()) {
@@ -175,7 +172,7 @@ State &SyntaxTree::state()
175 172
176QStringList SyntaxTree::tokenize(const QString &text) 173QStringList SyntaxTree::tokenize(const QString &text)
177{ 174{
178 //TODO: properly tokenize (e.g. "foo bar" should not become ['"foo', 'bar"']a 175 // TODO: properly tokenize (e.g. "foo bar" should not become ['"foo', 'bar"']a
179 static const QVector<QChar> quoters = QVector<QChar>() << '"' << '\''; 176 static const QVector<QChar> quoters = QVector<QChar>() << '"' << '\'';
180 QStringList tokens; 177 QStringList tokens;
181 QString acc; 178 QString acc;
@@ -218,4 +215,3 @@ QStringList SyntaxTree::tokenize(const QString &text)
218 215
219 return tokens; 216 return tokens;
220} 217}
221
diff --git a/sinksh/syntaxtree.h b/sinksh/syntaxtree.h
index 468aad3..be56067 100644
--- a/sinksh/syntaxtree.h
+++ b/sinksh/syntaxtree.h
@@ -32,16 +32,15 @@ class Syntax
32public: 32public:
33 typedef QVector<Syntax> List; 33 typedef QVector<Syntax> List;
34 34
35 enum Interactivity { 35 enum Interactivity
36 {
36 NotInteractive = 0, 37 NotInteractive = 0,
37 EventDriven 38 EventDriven
38 }; 39 };
39 40
40 Syntax(); 41 Syntax();
41 Syntax(const QString &keyword, 42 Syntax(const QString &keyword, const QString &helpText = QString(),
42 const QString &helpText = QString(), 43 std::function<bool(const QStringList &, State &)> lambda = std::function<bool(const QStringList &, State &)>(), Interactivity interactivity = NotInteractive);
43 std::function<bool(const QStringList &, State &)> lambda = std::function<bool(const QStringList &, State &)>(),
44 Interactivity interactivity = NotInteractive);
45 44
46 QString keyword; 45 QString keyword;
47 QString help; 46 QString help;
diff --git a/sinksh/utils.cpp b/sinksh/utils.cpp
index d2a28ed..7eea85f 100644
--- a/sinksh/utils.cpp
+++ b/sinksh/utils.cpp
@@ -19,8 +19,7 @@
19 19
20#include "utils.h" 20#include "utils.h"
21 21
22namespace Utils 22namespace Utils {
23{
24 23
25QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs) 24QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs)
26{ 25{
@@ -29,7 +28,7 @@ QStringList filteredCompletions(const QStringList &possibleCompletions, const QS
29 } 28 }
30 29
31 QStringList filtered; 30 QStringList filtered;
32 for (auto item: possibleCompletions) { 31 for (auto item : possibleCompletions) {
33 if (item.startsWith(commandFragment, cs)) { 32 if (item.startsWith(commandFragment, cs)) {
34 filtered << item; 33 filtered << item;
35 } 34 }
@@ -39,4 +38,3 @@ QStringList filteredCompletions(const QStringList &possibleCompletions, const QS
39} 38}
40 39
41} // namespace Utils 40} // namespace Utils
42
diff --git a/sinksh/utils.h b/sinksh/utils.h
index 82be8d5..bcbdedb 100644
--- a/sinksh/utils.h
+++ b/sinksh/utils.h
@@ -21,10 +21,8 @@
21 21
22#include <QStringList> 22#include <QStringList>
23 23
24namespace Utils 24namespace Utils {
25{
26 25
27QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs = Qt::CaseSensitive); 26QStringList filteredCompletions(const QStringList &possibleCompletions, const QString &commandFragment, Qt::CaseSensitivity cs = Qt::CaseSensitive);
28 27
29} // namespace Utils 28} // namespace Utils
30
diff --git a/synchronizer/main.cpp b/synchronizer/main.cpp
index d7a18e2..02cf365 100644
--- a/synchronizer/main.cpp
+++ b/synchronizer/main.cpp
@@ -29,33 +29,31 @@
29#undef DEBUG_AREA 29#undef DEBUG_AREA
30#define DEBUG_AREA "resource" 30#define DEBUG_AREA "resource"
31 31
32void crashHandler(int sig) { 32void crashHandler(int sig)
33{
33 std::fprintf(stderr, "Error: signal %d\n", sig); 34 std::fprintf(stderr, "Error: signal %d\n", sig);
34 35
35 QString s; 36 QString s;
36 void *trace[256]; 37 void *trace[256];
37 int n = backtrace( trace, 256 ); 38 int n = backtrace(trace, 256);
38 if ( n ) { 39 if (n) {
39 char **strings = backtrace_symbols( trace, n ); 40 char **strings = backtrace_symbols(trace, n);
40 41
41 s = QLatin1String( "[\n" ); 42 s = QLatin1String("[\n");
42 43
43 for ( int i = 0; i < n; ++i ) { 44 for (int i = 0; i < n; ++i) {
44 s += QString::number( i ) + 45 s += QString::number(i) + QLatin1String(": ") + QLatin1String(strings[i]) + QLatin1String("\n");
45 QLatin1String( ": " ) +
46 QLatin1String( strings[i] ) + QLatin1String( "\n" );
47 } 46 }
48 s += QLatin1String( "]\n" ); 47 s += QLatin1String("]\n");
49 std::fprintf(stderr, "Backtrace: %s\n", s.toLatin1().data()); 48 std::fprintf(stderr, "Backtrace: %s\n", s.toLatin1().data());
50 49
51 if ( strings ) { 50 if (strings) {
52 free( strings ); 51 free(strings);
53 } 52 }
54
55 } 53 }
56 54
57 std::system("exec gdb -p \"$PPID\" -ex \"thread apply all bt\""); 55 std::system("exec gdb -p \"$PPID\" -ex \"thread apply all bt\"");
58 //This only works if we actually have xterm and X11 available 56 // This only works if we actually have xterm and X11 available
59 // std::system("exec xterm -e gdb -p \"$PPID\""); 57 // std::system("exec xterm -e gdb -p \"$PPID\"");
60 58
61 std::abort(); 59 std::abort();
@@ -63,7 +61,7 @@ void crashHandler(int sig) {
63 61
64int main(int argc, char *argv[]) 62int main(int argc, char *argv[])
65{ 63{
66 //For crashes 64 // For crashes
67 signal(SIGSEGV, crashHandler); 65 signal(SIGSEGV, crashHandler);
68 QCoreApplication app(argc, argv); 66 QCoreApplication app(argc, argv);
69 67
@@ -84,10 +82,8 @@ int main(int argc, char *argv[])
84 82
85 Listener *listener = new Listener(instanceIdentifier, &app); 83 Listener *listener = new Listener(instanceIdentifier, &app);
86 84
87 QObject::connect(&app, &QCoreApplication::aboutToQuit, 85 QObject::connect(&app, &QCoreApplication::aboutToQuit, listener, &Listener::closeAllConnections);
88 listener, &Listener::closeAllConnections); 86 QObject::connect(listener, &Listener::noClients, &app, &QCoreApplication::quit);
89 QObject::connect(listener, &Listener::noClients,
90 &app, &QCoreApplication::quit);
91 87
92 return app.exec(); 88 return app.exec();
93} 89}
diff --git a/tests/clientapitest.cpp b/tests/clientapitest.cpp
index 879ffc4..172232f 100644
--- a/tests/clientapitest.cpp
+++ b/tests/clientapitest.cpp
@@ -13,34 +13,41 @@ template <typename T>
13class DummyResourceFacade : public Sink::StoreFacade<T> 13class DummyResourceFacade : public Sink::StoreFacade<T>
14{ 14{
15public: 15public:
16 static std::shared_ptr<DummyResourceFacade<T> > registerFacade(const QByteArray &instanceIdentifier = QByteArray()) 16 static std::shared_ptr<DummyResourceFacade<T>> registerFacade(const QByteArray &instanceIdentifier = QByteArray())
17 { 17 {
18 static QMap<QByteArray, std::shared_ptr<DummyResourceFacade<T> > > map; 18 static QMap<QByteArray, std::shared_ptr<DummyResourceFacade<T>>> map;
19 auto facade = std::make_shared<DummyResourceFacade<T> >(); 19 auto facade = std::make_shared<DummyResourceFacade<T>>();
20 map.insert(instanceIdentifier, facade); 20 map.insert(instanceIdentifier, facade);
21 bool alwaysReturnFacade = instanceIdentifier.isEmpty(); 21 bool alwaysReturnFacade = instanceIdentifier.isEmpty();
22 Sink::FacadeFactory::instance().registerFacade<T, DummyResourceFacade<T> >("dummyresource", 22 Sink::FacadeFactory::instance().registerFacade<T, DummyResourceFacade<T>>("dummyresource", [alwaysReturnFacade](const QByteArray &instanceIdentifier) {
23 [alwaysReturnFacade](const QByteArray &instanceIdentifier) { 23 if (alwaysReturnFacade) {
24 if (alwaysReturnFacade) { 24 return map.value(QByteArray());
25 return map.value(QByteArray());
26 }
27 return map.value(instanceIdentifier);
28 } 25 }
29 ); 26 return map.value(instanceIdentifier);
27 });
30 return facade; 28 return facade;
31 } 29 }
32 ~DummyResourceFacade(){}; 30 ~DummyResourceFacade(){};
33 KAsync::Job<void> create(const T &domainObject) Q_DECL_OVERRIDE { return KAsync::null<void>(); }; 31 KAsync::Job<void> create(const T &domainObject) Q_DECL_OVERRIDE
34 KAsync::Job<void> modify(const T &domainObject) Q_DECL_OVERRIDE { return KAsync::null<void>(); }; 32 {
35 KAsync::Job<void> remove(const T &domainObject) Q_DECL_OVERRIDE { return KAsync::null<void>(); }; 33 return KAsync::null<void>();
36 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename T::Ptr>::Ptr > load(const Sink::Query &query) Q_DECL_OVERRIDE 34 };
35 KAsync::Job<void> modify(const T &domainObject) Q_DECL_OVERRIDE
36 {
37 return KAsync::null<void>();
38 };
39 KAsync::Job<void> remove(const T &domainObject) Q_DECL_OVERRIDE
40 {
41 return KAsync::null<void>();
42 };
43 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename T::Ptr>::Ptr> load(const Sink::Query &query) Q_DECL_OVERRIDE
37 { 44 {
38 auto resultProvider = new Sink::ResultProvider<typename T::Ptr>(); 45 auto resultProvider = new Sink::ResultProvider<typename T::Ptr>();
39 resultProvider->onDone([resultProvider]() { 46 resultProvider->onDone([resultProvider]() {
40 Trace() << "Result provider is done"; 47 Trace() << "Result provider is done";
41 delete resultProvider; 48 delete resultProvider;
42 }); 49 });
43 //We have to do it this way, otherwise we're not setting the fetcher right 50 // We have to do it this way, otherwise we're not setting the fetcher right
44 auto emitter = resultProvider->emitter(); 51 auto emitter = resultProvider->emitter();
45 52
46 resultProvider->setFetcher([query, resultProvider, this](const typename T::Ptr &parent) { 53 resultProvider->setFetcher([query, resultProvider, this](const typename T::Ptr &parent) {
@@ -60,8 +67,7 @@ public:
60 } 67 }
61 resultProvider->initialResultSetComplete(parent); 68 resultProvider->initialResultSetComplete(parent);
62 }); 69 });
63 auto job = KAsync::start<void>([query, resultProvider]() { 70 auto job = KAsync::start<void>([query, resultProvider]() {});
64 });
65 mResultProvider = resultProvider; 71 mResultProvider = resultProvider;
66 return qMakePair(job, emitter); 72 return qMakePair(job, emitter);
67 } 73 }
@@ -73,7 +79,7 @@ public:
73 79
74/** 80/**
75 * Test of the client api implementation. 81 * Test of the client api implementation.
76 * 82 *
77 * This test works with injected dummy facades and thus doesn't write to storage. 83 * This test works with injected dummy facades and thus doesn't write to storage.
78 */ 84 */
79class ClientAPITest : public QObject 85class ClientAPITest : public QObject
@@ -113,7 +119,7 @@ private slots:
113 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 119 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
114 } 120 }
115 121
116 //TODO: This test doesn't belong to this testsuite 122 // TODO: This test doesn't belong to this testsuite
117 void resourceManagement() 123 void resourceManagement()
118 { 124 {
119 ResourceConfig::clear(); 125 ResourceConfig::clear();
@@ -158,13 +164,13 @@ private slots:
158 void testModelNested() 164 void testModelNested()
159 { 165 {
160 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade(); 166 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade();
161 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 167 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
162 auto subfolder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 168 auto subfolder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
163 subfolder->setProperty("parent", "id"); 169 subfolder->setProperty("parent", "id");
164 facade->results << folder << subfolder; 170 facade->results << folder << subfolder;
165 ResourceConfig::addResource("dummyresource.instance1", "dummyresource"); 171 ResourceConfig::addResource("dummyresource.instance1", "dummyresource");
166 172
167 //Test 173 // Test
168 Sink::Query query; 174 Sink::Query query;
169 query.resources << "dummyresource.instance1"; 175 query.resources << "dummyresource.instance1";
170 query.liveQuery = false; 176 query.liveQuery = false;
@@ -181,13 +187,13 @@ private slots:
181 void testModelSignals() 187 void testModelSignals()
182 { 188 {
183 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade(); 189 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade();
184 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 190 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
185 auto subfolder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 191 auto subfolder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
186 subfolder->setProperty("parent", "id"); 192 subfolder->setProperty("parent", "id");
187 facade->results << folder << subfolder; 193 facade->results << folder << subfolder;
188 ResourceConfig::addResource("dummyresource.instance1", "dummyresource"); 194 ResourceConfig::addResource("dummyresource.instance1", "dummyresource");
189 195
190 //Test 196 // Test
191 Sink::Query query; 197 Sink::Query query;
192 query.resources << "dummyresource.instance1"; 198 query.resources << "dummyresource.instance1";
193 query.liveQuery = false; 199 query.liveQuery = false;
@@ -203,13 +209,14 @@ private slots:
203 void testModelNestedLive() 209 void testModelNestedLive()
204 { 210 {
205 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade(); 211 auto facade = DummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade();
206 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("dummyresource.instance1", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 212 auto folder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("dummyresource.instance1", "id", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
207 auto subfolder = QSharedPointer<Sink::ApplicationDomain::Folder>::create("dummyresource.instance1", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 213 auto subfolder =
214 QSharedPointer<Sink::ApplicationDomain::Folder>::create("dummyresource.instance1", "subId", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
208 subfolder->setProperty("parent", "id"); 215 subfolder->setProperty("parent", "id");
209 facade->results << folder << subfolder; 216 facade->results << folder << subfolder;
210 ResourceConfig::addResource("dummyresource.instance1", "dummyresource"); 217 ResourceConfig::addResource("dummyresource.instance1", "dummyresource");
211 218
212 //Test 219 // Test
213 Sink::Query query; 220 Sink::Query query;
214 query.resources << "dummyresource.instance1"; 221 query.resources << "dummyresource.instance1";
215 query.liveQuery = true; 222 query.liveQuery = true;
@@ -222,7 +229,7 @@ private slots:
222 229
223 auto resultProvider = facade->mResultProvider; 230 auto resultProvider = facade->mResultProvider;
224 231
225 //Test new toplevel folder 232 // Test new toplevel folder
226 { 233 {
227 QSignalSpy rowsInsertedSpy(model.data(), SIGNAL(rowsInserted(const QModelIndex &, int, int))); 234 QSignalSpy rowsInsertedSpy(model.data(), SIGNAL(rowsInserted(const QModelIndex &, int, int)));
228 auto folder2 = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 235 auto folder2 = QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
@@ -232,7 +239,7 @@ private slots:
232 QCOMPARE(rowsInsertedSpy.at(0).at(0).value<QModelIndex>(), QModelIndex()); 239 QCOMPARE(rowsInsertedSpy.at(0).at(0).value<QModelIndex>(), QModelIndex());
233 } 240 }
234 241
235 //Test changed name 242 // Test changed name
236 { 243 {
237 QSignalSpy dataChanged(model.data(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &))); 244 QSignalSpy dataChanged(model.data(), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &)));
238 folder->setProperty("subject", "modifiedSubject"); 245 folder->setProperty("subject", "modifiedSubject");
@@ -241,7 +248,7 @@ private slots:
241 QTRY_COMPARE(dataChanged.count(), 1); 248 QTRY_COMPARE(dataChanged.count(), 1);
242 } 249 }
243 250
244 //Test removal 251 // Test removal
245 { 252 {
246 QSignalSpy rowsRemovedSpy(model.data(), SIGNAL(rowsRemoved(const QModelIndex &, int, int))); 253 QSignalSpy rowsRemovedSpy(model.data(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)));
247 folder->setProperty("subject", "modifiedSubject"); 254 folder->setProperty("subject", "modifiedSubject");
@@ -250,7 +257,7 @@ private slots:
250 QTRY_COMPARE(rowsRemovedSpy.count(), 1); 257 QTRY_COMPARE(rowsRemovedSpy.count(), 1);
251 } 258 }
252 259
253 //TODO: A modification can also be a move 260 // TODO: A modification can also be a move
254 } 261 }
255 262
256 void testLoadMultiResource() 263 void testLoadMultiResource()
@@ -274,7 +281,7 @@ private slots:
274 }); 281 });
275 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 282 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
276 QCOMPARE(model->rowCount(QModelIndex()), 2); 283 QCOMPARE(model->rowCount(QModelIndex()), 2);
277 //Ensure children fetched is only emitted once (when all resources are done) 284 // Ensure children fetched is only emitted once (when all resources are done)
278 QTest::qWait(50); 285 QTest::qWait(50);
279 QCOMPARE(childrenFetchedCount, 1); 286 QCOMPARE(childrenFetchedCount, 1);
280 } 287 }
@@ -291,15 +298,12 @@ private slots:
291 298
292 bool gotValue = false; 299 bool gotValue = false;
293 auto result = Sink::Store::fetchOne<Sink::ApplicationDomain::Event>(query) 300 auto result = Sink::Store::fetchOne<Sink::ApplicationDomain::Event>(query)
294 .then<void, Sink::ApplicationDomain::Event>([&gotValue](const Sink::ApplicationDomain::Event &event) { 301 .then<void, Sink::ApplicationDomain::Event>([&gotValue](const Sink::ApplicationDomain::Event &event) { gotValue = true; })
295 gotValue = true; 302 .exec();
296 }).exec();
297 result.waitForFinished(); 303 result.waitForFinished();
298 QVERIFY(!result.errorCode()); 304 QVERIFY(!result.errorCode());
299 QVERIFY(gotValue); 305 QVERIFY(gotValue);
300 } 306 }
301
302
303}; 307};
304 308
305QTEST_MAIN(ClientAPITest) 309QTEST_MAIN(ClientAPITest)
diff --git a/tests/databasepopulationandfacadequerybenchmark.cpp b/tests/databasepopulationandfacadequerybenchmark.cpp
index 16537c0..4e886af 100644
--- a/tests/databasepopulationandfacadequerybenchmark.cpp
+++ b/tests/databasepopulationandfacadequerybenchmark.cpp
@@ -23,7 +23,7 @@
23 23
24/** 24/**
25 * Benchmark read performance of the facade implementation. 25 * Benchmark read performance of the facade implementation.
26 * 26 *
27 * The memory used should grow linearly with the number of retrieved entities. 27 * The memory used should grow linearly with the number of retrieved entities.
28 * The memory used should be independent from the database size, after accounting for the memory mapped db. 28 * The memory used should be independent from the database size, after accounting for the memory mapped db.
29 */ 29 */
@@ -39,7 +39,7 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
39 void populateDatabase(int count) 39 void populateDatabase(int count)
40 { 40 {
41 Sink::Storage(Sink::storageLocation(), "identifier", Sink::Storage::ReadWrite).removeFromDisk(); 41 Sink::Storage(Sink::storageLocation(), "identifier", Sink::Storage::ReadWrite).removeFromDisk();
42 //Setup 42 // Setup
43 auto domainTypeAdaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create(); 43 auto domainTypeAdaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create();
44 { 44 {
45 Sink::Storage storage(Sink::storageLocation(), identifier, Sink::Storage::ReadWrite); 45 Sink::Storage storage(Sink::storageLocation(), identifier, Sink::Storage::ReadWrite);
@@ -57,7 +57,7 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
57 domainObject->setProperty("attachment", attachment); 57 domainObject->setProperty("attachment", attachment);
58 flatbuffers::FlatBufferBuilder fbb; 58 flatbuffers::FlatBufferBuilder fbb;
59 domainTypeAdaptorFactory->createBuffer(*domainObject, fbb); 59 domainTypeAdaptorFactory->createBuffer(*domainObject, fbb);
60 const auto buffer = QByteArray::fromRawData(reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()); 60 const auto buffer = QByteArray::fromRawData(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
61 const auto key = QUuid::createUuid().toString().toLatin1(); 61 const auto key = QUuid::createUuid().toString().toLatin1();
62 db.write(key, buffer); 62 db.write(key, buffer);
63 bufferSizeTotal += buffer.size(); 63 bufferSizeTotal += buffer.size();
@@ -72,15 +72,15 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
72 auto size = db.getSize(); 72 auto size = db.getSize();
73 auto onDisk = storage.diskUsage(); 73 auto onDisk = storage.diskUsage();
74 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal); 74 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal);
75 std::cout << "Database size [kb]: " << size/1024 << std::endl; 75 std::cout << "Database size [kb]: " << size / 1024 << std::endl;
76 std::cout << "On disk [kb]: " << onDisk/1024 << std::endl; 76 std::cout << "On disk [kb]: " << onDisk / 1024 << std::endl;
77 std::cout << "Buffer size total [kb]: " << bufferSizeTotal/1024 << std::endl; 77 std::cout << "Buffer size total [kb]: " << bufferSizeTotal / 1024 << std::endl;
78 std::cout << "Key size total [kb]: " << keysSizeTotal/1024 << std::endl; 78 std::cout << "Key size total [kb]: " << keysSizeTotal / 1024 << std::endl;
79 std::cout << "Data size total [kb]: " << dataSizeTotal/1024 << std::endl; 79 std::cout << "Data size total [kb]: " << dataSizeTotal / 1024 << std::endl;
80 std::cout << "Write amplification: " << writeAmplification << std::endl; 80 std::cout << "Write amplification: " << writeAmplification << std::endl;
81 81
82 //The buffer has an overhead, but with a reasonable attachment size it should be relatively small 82 // The buffer has an overhead, but with a reasonable attachment size it should be relatively small
83 //A write amplification of 2 should be the worst case 83 // A write amplification of 2 should be the worst case
84 QVERIFY(writeAmplification < 2); 84 QVERIFY(writeAmplification < 2);
85 } 85 }
86 } 86 }
@@ -91,13 +91,14 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
91 91
92 Sink::Query query; 92 Sink::Query query;
93 query.liveQuery = false; 93 query.liveQuery = false;
94 query.requestedProperties << "uid" << "summary"; 94 query.requestedProperties << "uid"
95 << "summary";
95 96
96 //Benchmark 97 // Benchmark
97 QTime time; 98 QTime time;
98 time.start(); 99 time.start();
99 100
100 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr> >::create(); 101 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create();
101 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 102 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
102 TestResourceFacade facade(identifier, resourceAccess); 103 TestResourceFacade facade(identifier, resourceAccess);
103 104
@@ -105,13 +106,9 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
105 ret.first.exec().waitForFinished(); 106 ret.first.exec().waitForFinished();
106 auto emitter = ret.second; 107 auto emitter = ret.second;
107 QList<Sink::ApplicationDomain::Event::Ptr> list; 108 QList<Sink::ApplicationDomain::Event::Ptr> list;
108 emitter->onAdded([&list](const Sink::ApplicationDomain::Event::Ptr &event) { 109 emitter->onAdded([&list](const Sink::ApplicationDomain::Event::Ptr &event) { list << event; });
109 list << event;
110 });
111 bool done = false; 110 bool done = false;
112 emitter->onInitialResultSetComplete([&done](const Sink::ApplicationDomain::Event::Ptr &event) { 111 emitter->onInitialResultSetComplete([&done](const Sink::ApplicationDomain::Event::Ptr &event) { done = true; });
113 done = true;
114 });
115 emitter->fetch(Sink::ApplicationDomain::Event::Ptr()); 112 emitter->fetch(Sink::ApplicationDomain::Event::Ptr());
116 QTRY_VERIFY(done); 113 QTRY_VERIFY(done);
117 QCOMPARE(list.size(), count); 114 QCOMPARE(list.size(), count);
@@ -120,35 +117,35 @@ class DatabasePopulationAndFacadeQueryBenchmark : public QObject
120 117
121 const auto finalRss = getCurrentRSS(); 118 const auto finalRss = getCurrentRSS();
122 const auto rssGrowth = finalRss - startingRss; 119 const auto rssGrowth = finalRss - startingRss;
123 //Since the database is memory mapped it is attributted to the resident set size. 120 // Since the database is memory mapped it is attributted to the resident set size.
124 const auto rssWithoutDb = finalRss - Sink::Storage(Sink::storageLocation(), identifier, Sink::Storage::ReadWrite).diskUsage(); 121 const auto rssWithoutDb = finalRss - Sink::Storage(Sink::storageLocation(), identifier, Sink::Storage::ReadWrite).diskUsage();
125 const auto peakRss = getPeakRSS(); 122 const auto peakRss = getPeakRSS();
126 //How much peak deviates from final rss in percent (should be around 0) 123 // How much peak deviates from final rss in percent (should be around 0)
127 const auto percentageRssError = static_cast<double>(peakRss - finalRss)*100.0/static_cast<double>(finalRss); 124 const auto percentageRssError = static_cast<double>(peakRss - finalRss) * 100.0 / static_cast<double>(finalRss);
128 auto rssGrowthPerEntity = rssGrowth/count; 125 auto rssGrowthPerEntity = rssGrowth / count;
129 126
130 std::cout << "Loaded " << list.size() << " results." << std::endl; 127 std::cout << "Loaded " << list.size() << " results." << std::endl;
131 std::cout << "The query took [ms]: " << elapsed << std::endl; 128 std::cout << "The query took [ms]: " << elapsed << std::endl;
132 std::cout << "Current Rss usage [kb]: " << finalRss/1024 << std::endl; 129 std::cout << "Current Rss usage [kb]: " << finalRss / 1024 << std::endl;
133 std::cout << "Peak Rss usage [kb]: " << peakRss/1024 << std::endl; 130 std::cout << "Peak Rss usage [kb]: " << peakRss / 1024 << std::endl;
134 std::cout << "Rss growth [kb]: " << rssGrowth/1024 << std::endl; 131 std::cout << "Rss growth [kb]: " << rssGrowth / 1024 << std::endl;
135 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl; 132 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl;
136 std::cout << "Rss without db [kb]: " << rssWithoutDb/1024 << std::endl; 133 std::cout << "Rss without db [kb]: " << rssWithoutDb / 1024 << std::endl;
137 std::cout << "Percentage error: " << percentageRssError << std::endl; 134 std::cout << "Percentage error: " << percentageRssError << std::endl;
138 135
139 HAWD::Dataset dataset("facade_query", mHawdState); 136 HAWD::Dataset dataset("facade_query", mHawdState);
140 HAWD::Dataset::Row row = dataset.row(); 137 HAWD::Dataset::Row row = dataset.row();
141 row.setValue("rows", list.size()); 138 row.setValue("rows", list.size());
142 row.setValue("queryResultPerMs", (qreal)list.size()/elapsed); 139 row.setValue("queryResultPerMs", (qreal)list.size() / elapsed);
143 dataset.insertRow(row); 140 dataset.insertRow(row);
144 HAWD::Formatter::print(dataset); 141 HAWD::Formatter::print(dataset);
145 142
146 mTimePerEntity << static_cast<double>(elapsed)/static_cast<double>(count); 143 mTimePerEntity << static_cast<double>(elapsed) / static_cast<double>(count);
147 mRssGrowthPerEntity << rssGrowthPerEntity; 144 mRssGrowthPerEntity << rssGrowthPerEntity;
148 145
149 QVERIFY(percentageRssError < 10); 146 QVERIFY(percentageRssError < 10);
150 //TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase, 147 // TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase,
151 //so it doesn't look like that memory is being duplicated. 148 // so it doesn't look like that memory is being duplicated.
152 QVERIFY(rssGrowthPerEntity < 3300); 149 QVERIFY(rssGrowthPerEntity < 3300);
153 150
154 // Print memory layout, RSS is what is in memory 151 // Print memory layout, RSS is what is in memory
diff --git a/tests/domainadaptortest.cpp b/tests/domainadaptortest.cpp
index 5939a31..ff75d21 100644
--- a/tests/domainadaptortest.cpp
+++ b/tests/domainadaptortest.cpp
@@ -54,7 +54,7 @@ private slots:
54 54
55 void testAdaptor() 55 void testAdaptor()
56 { 56 {
57 //Create entity buffer 57 // Create entity buffer
58 flatbuffers::FlatBufferBuilder metadataFbb; 58 flatbuffers::FlatBufferBuilder metadataFbb;
59 auto metadataBuilder = Sink::MetadataBuilder(metadataFbb); 59 auto metadataBuilder = Sink::MetadataBuilder(metadataFbb);
60 metadataBuilder.add_revision(1); 60 metadataBuilder.add_revision(1);
@@ -75,19 +75,19 @@ private slots:
75 Sink::ApplicationDomain::Buffer::FinishEventBuffer(m_fbb, buffer); 75 Sink::ApplicationDomain::Buffer::FinishEventBuffer(m_fbb, buffer);
76 76
77 flatbuffers::FlatBufferBuilder fbb; 77 flatbuffers::FlatBufferBuilder fbb;
78 Sink::EntityBuffer::assembleEntityBuffer(fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), m_fbb.GetBufferPointer(), m_fbb.GetSize(), m_fbb.GetBufferPointer(), m_fbb.GetSize()); 78 Sink::EntityBuffer::assembleEntityBuffer(
79 fbb, metadataFbb.GetBufferPointer(), metadataFbb.GetSize(), m_fbb.GetBufferPointer(), m_fbb.GetSize(), m_fbb.GetBufferPointer(), m_fbb.GetSize());
79 80
80 //Extract entity buffer 81 // Extract entity buffer
81 { 82 {
82 std::string data(reinterpret_cast<const char*>(fbb.GetBufferPointer()), fbb.GetSize()); 83 std::string data(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
83 Sink::EntityBuffer buffer((void*)(data.data()), data.size()); 84 Sink::EntityBuffer buffer((void *)(data.data()), data.size());
84 85
85 TestFactory factory; 86 TestFactory factory;
86 auto adaptor = factory.createAdaptor(buffer.entity()); 87 auto adaptor = factory.createAdaptor(buffer.entity());
87 QCOMPARE(adaptor->getProperty("summary").toString(), QString("summary1")); 88 QCOMPARE(adaptor->getProperty("summary").toString(), QString("summary1"));
88 } 89 }
89 } 90 }
90
91}; 91};
92 92
93QTEST_MAIN(DomainAdaptorTest) 93QTEST_MAIN(DomainAdaptorTest)
diff --git a/tests/dummyresourcebenchmark.cpp b/tests/dummyresourcebenchmark.cpp
index 77b87fb..124abc1 100644
--- a/tests/dummyresourcebenchmark.cpp
+++ b/tests/dummyresourcebenchmark.cpp
@@ -44,40 +44,38 @@ private slots:
44 { 44 {
45 } 45 }
46 46
47 static KAsync::Job<void> waitForCompletion(QList<KAsync::Future<void> > &futures) 47 static KAsync::Job<void> waitForCompletion(QList<KAsync::Future<void>> &futures)
48 { 48 {
49 auto context = new QObject; 49 auto context = new QObject;
50 return KAsync::start<void>([futures, context](KAsync::Future<void> &future) { 50 return KAsync::start<void>([futures, context](KAsync::Future<void> &future) {
51 const auto total = futures.size(); 51 const auto total = futures.size();
52 auto count = QSharedPointer<int>::create(); 52 auto count = QSharedPointer<int>::create();
53 int i = 0; 53 int i = 0;
54 for (KAsync::Future<void> subFuture : futures) { 54 for (KAsync::Future<void> subFuture : futures) {
55 i++; 55 i++;
56 if (subFuture.isFinished()) { 56 if (subFuture.isFinished()) {
57 *count += 1; 57 *count += 1;
58 continue; 58 continue;
59 } 59 }
60 //FIXME bind lifetime all watcher to future (repectively the main job 60 // FIXME bind lifetime all watcher to future (repectively the main job
61 auto watcher = QSharedPointer<KAsync::FutureWatcher<void> >::create(); 61 auto watcher = QSharedPointer<KAsync::FutureWatcher<void>>::create();
62 QObject::connect(watcher.data(), &KAsync::FutureWatcher<void>::futureReady, 62 QObject::connect(watcher.data(), &KAsync::FutureWatcher<void>::futureReady, [count, total, &future]() {
63 [count, total, &future](){ 63 *count += 1;
64 *count += 1; 64 if (*count == total) {
65 if (*count == total) { 65 future.setFinished();
66 future.setFinished(); 66 }
67 } 67 });
68 }); 68 watcher->setFuture(subFuture);
69 watcher->setFuture(subFuture); 69 context->setProperty(QString("future%1").arg(i).toLatin1().data(), QVariant::fromValue(watcher));
70 context->setProperty(QString("future%1").arg(i).toLatin1().data(), QVariant::fromValue(watcher)); 70 }
71 } 71 })
72 }).then<void>([context]() { 72 .then<void>([context]() { delete context; });
73 delete context;
74 });
75 } 73 }
76 74
77 //Ensure we can process a command in less than 0.1s 75 // Ensure we can process a command in less than 0.1s
78 void testCommandResponsiveness() 76 void testCommandResponsiveness()
79 { 77 {
80 //Test responsiveness including starting the process. 78 // Test responsiveness including starting the process.
81 Sink::Store::removeDataFromDisk("org.kde.dummy.instance1").exec().waitForFinished(); 79 Sink::Store::removeDataFromDisk("org.kde.dummy.instance1").exec().waitForFinished();
82 80
83 QTime time; 81 QTime time;
@@ -100,7 +98,7 @@ private slots:
100 98
101 Sink::Store::create<Sink::ApplicationDomain::Event>(event).exec(); 99 Sink::Store::create<Sink::ApplicationDomain::Event>(event).exec();
102 100
103 //Wait for notification 101 // Wait for notification
104 QTRY_VERIFY(gotNotification); 102 QTRY_VERIFY(gotNotification);
105 103
106 QVERIFY2(duration < 100, QString::fromLatin1("Processing a create command took more than 100ms: %1").arg(duration).toLatin1()); 104 QVERIFY2(duration < 100, QString::fromLatin1("Processing a create command took more than 100ms: %1").arg(duration).toLatin1());
@@ -114,7 +112,7 @@ private slots:
114 112
115 QTime time; 113 QTime time;
116 time.start(); 114 time.start();
117 QList<KAsync::Future<void> > waitCondition; 115 QList<KAsync::Future<void>> waitCondition;
118 for (int i = 0; i < num; i++) { 116 for (int i = 0; i < num; i++) {
119 Sink::ApplicationDomain::Event event("org.kde.dummy.instance1"); 117 Sink::ApplicationDomain::Event event("org.kde.dummy.instance1");
120 event.setProperty("uid", "testuid"); 118 event.setProperty("uid", "testuid");
@@ -125,7 +123,7 @@ private slots:
125 waitForCompletion(waitCondition).exec().waitForFinished(); 123 waitForCompletion(waitCondition).exec().waitForFinished();
126 auto appendTime = time.elapsed(); 124 auto appendTime = time.elapsed();
127 125
128 //Ensure everything is processed 126 // Ensure everything is processed
129 { 127 {
130 Sink::Query query; 128 Sink::Query query;
131 query.resources << "org.kde.dummy.instance1"; 129 query.resources << "org.kde.dummy.instance1";
@@ -137,13 +135,13 @@ private slots:
137 HAWD::Dataset::Row row = dataset.row(); 135 HAWD::Dataset::Row row = dataset.row();
138 136
139 row.setValue("rows", num); 137 row.setValue("rows", num);
140 row.setValue("append", (qreal)num/appendTime); 138 row.setValue("append", (qreal)num / appendTime);
141 row.setValue("total", (qreal)num/allProcessedTime); 139 row.setValue("total", (qreal)num / allProcessedTime);
142 dataset.insertRow(row); 140 dataset.insertRow(row);
143 HAWD::Formatter::print(dataset); 141 HAWD::Formatter::print(dataset);
144 142
145 auto diskUsage = DummyResource::diskUsage("org.kde.dummy.instance1"); 143 auto diskUsage = DummyResource::diskUsage("org.kde.dummy.instance1");
146 qDebug() << "Database size [kb]: " << diskUsage/1024; 144 qDebug() << "Database size [kb]: " << diskUsage / 1024;
147 145
148 // Print memory layout, RSS is what is in memory 146 // Print memory layout, RSS is what is in memory
149 // std::system("exec pmap -x \"$PPID\""); 147 // std::system("exec pmap -x \"$PPID\"");
@@ -153,7 +151,7 @@ private slots:
153 { 151 {
154 QTime time; 152 QTime time;
155 time.start(); 153 time.start();
156 //Measure query 154 // Measure query
157 { 155 {
158 time.start(); 156 time.start();
159 Sink::Query query; 157 Sink::Query query;
@@ -168,7 +166,7 @@ private slots:
168 HAWD::Dataset dataset("dummy_query_by_uid", m_hawdState); 166 HAWD::Dataset dataset("dummy_query_by_uid", m_hawdState);
169 HAWD::Dataset::Row row = dataset.row(); 167 HAWD::Dataset::Row row = dataset.row();
170 row.setValue("rows", num); 168 row.setValue("rows", num);
171 row.setValue("read", (qreal)num/queryTime); 169 row.setValue("read", (qreal)num / queryTime);
172 dataset.insertRow(row); 170 dataset.insertRow(row);
173 HAWD::Formatter::print(dataset); 171 HAWD::Formatter::print(dataset);
174 } 172 }
@@ -220,7 +218,7 @@ private slots:
220 } 218 }
221 auto appendTime = time.elapsed(); 219 auto appendTime = time.elapsed();
222 220
223 //Wait until all messages have been processed 221 // Wait until all messages have been processed
224 resource.processAllMessages().exec().waitForFinished(); 222 resource.processAllMessages().exec().waitForFinished();
225 223
226 auto allProcessedTime = time.elapsed(); 224 auto allProcessedTime = time.elapsed();
@@ -229,8 +227,8 @@ private slots:
229 HAWD::Dataset::Row row = dataset.row(); 227 HAWD::Dataset::Row row = dataset.row();
230 228
231 row.setValue("rows", num); 229 row.setValue("rows", num);
232 row.setValue("append", (qreal)num/appendTime); 230 row.setValue("append", (qreal)num / appendTime);
233 row.setValue("total", (qreal)num/allProcessedTime); 231 row.setValue("total", (qreal)num / allProcessedTime);
234 dataset.insertRow(row); 232 dataset.insertRow(row);
235 HAWD::Formatter::print(dataset); 233 HAWD::Formatter::print(dataset);
236 234
@@ -250,7 +248,7 @@ private slots:
250 248
251 static flatbuffers::FlatBufferBuilder fbb; 249 static flatbuffers::FlatBufferBuilder fbb;
252 fbb.Clear(); 250 fbb.Clear();
253 //This is the resource buffer type and not the domain type 251 // This is the resource buffer type and not the domain type
254 auto entityId = fbb.CreateString(""); 252 auto entityId = fbb.CreateString("");
255 auto type = fbb.CreateString("event"); 253 auto type = fbb.CreateString("event");
256 // auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); 254 // auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize());
@@ -260,7 +258,7 @@ private slots:
260 } 258 }
261 } 259 }
262 260
263 //This allows to run individual parts without doing a cleanup, but still cleaning up normally 261 // This allows to run individual parts without doing a cleanup, but still cleaning up normally
264 void testCleanupForCompleteTest() 262 void testCleanupForCompleteTest()
265 { 263 {
266 Sink::Store::removeDataFromDisk("org.kde.dummy.instance1").exec().waitForFinished(); 264 Sink::Store::removeDataFromDisk("org.kde.dummy.instance1").exec().waitForFinished();
diff --git a/tests/dummyresourcetest.cpp b/tests/dummyresourcetest.cpp
index 8b5a8fa..33304e1 100644
--- a/tests/dummyresourcetest.cpp
+++ b/tests/dummyresourcetest.cpp
@@ -14,7 +14,7 @@
14 14
15/** 15/**
16 * Test of complete system using the dummy resource. 16 * Test of complete system using the dummy resource.
17 * 17 *
18 * This test requires the dummy resource installed. 18 * This test requires the dummy resource installed.
19 */ 19 */
20class DummyResourceTest : public QObject 20class DummyResourceTest : public QObject
@@ -65,7 +65,7 @@ private slots:
65 Sink::Query query; 65 Sink::Query query;
66 query.resources << "org.kde.dummy.instance1"; 66 query.resources << "org.kde.dummy.instance1";
67 67
68 //Ensure all local data is processed 68 // Ensure all local data is processed
69 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 69 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
70 70
71 query.propertyFilter.insert("uid", "testuid"); 71 query.propertyFilter.insert("uid", "testuid");
@@ -89,7 +89,7 @@ private slots:
89 Sink::Query query; 89 Sink::Query query;
90 query.resources << "org.kde.dummy.instance1"; 90 query.resources << "org.kde.dummy.instance1";
91 91
92 //Ensure all local data is processed 92 // Ensure all local data is processed
93 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 93 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
94 94
95 query.propertyFilter.insert("uid", "testuid"); 95 query.propertyFilter.insert("uid", "testuid");
@@ -117,7 +117,7 @@ private slots:
117 Sink::Query query; 117 Sink::Query query;
118 query.resources << "org.kde.dummy.instance1"; 118 query.resources << "org.kde.dummy.instance1";
119 119
120 //Ensure all local data is processed 120 // Ensure all local data is processed
121 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 121 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
122 122
123 query.propertyFilter.insert("summary", "summaryValue2"); 123 query.propertyFilter.insert("summary", "summaryValue2");
@@ -135,7 +135,7 @@ private slots:
135 auto pipeline = QSharedPointer<Sink::Pipeline>::create("org.kde.dummy.instance1"); 135 auto pipeline = QSharedPointer<Sink::Pipeline>::create("org.kde.dummy.instance1");
136 DummyResource resource("org.kde.dummy.instance1", pipeline); 136 DummyResource resource("org.kde.dummy.instance1", pipeline);
137 auto job = resource.synchronizeWithSource(); 137 auto job = resource.synchronizeWithSource();
138 //TODO pass in optional timeout? 138 // TODO pass in optional timeout?
139 auto future = job.exec(); 139 auto future = job.exec();
140 future.waitForFinished(); 140 future.waitForFinished();
141 QVERIFY(!future.errorCode()); 141 QVERIFY(!future.errorCode());
@@ -150,7 +150,7 @@ private slots:
150 Sink::Query query; 150 Sink::Query query;
151 query.resources << "org.kde.dummy.instance1"; 151 query.resources << "org.kde.dummy.instance1";
152 152
153 //Ensure all local data is processed 153 // Ensure all local data is processed
154 Sink::Store::synchronize(query).exec().waitForFinished(); 154 Sink::Store::synchronize(query).exec().waitForFinished();
155 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 155 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
156 156
@@ -167,7 +167,7 @@ private slots:
167 Sink::Query query; 167 Sink::Query query;
168 query.resources << "org.kde.dummy.instance1"; 168 query.resources << "org.kde.dummy.instance1";
169 169
170 //Ensure all local data is processed 170 // Ensure all local data is processed
171 Sink::Store::synchronize(query).exec().waitForFinished(); 171 Sink::Store::synchronize(query).exec().waitForFinished();
172 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 172 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
173 173
@@ -191,10 +191,10 @@ private slots:
191 query.resources << "org.kde.dummy.instance1"; 191 query.resources << "org.kde.dummy.instance1";
192 query.propertyFilter.insert("uid", "testuid"); 192 query.propertyFilter.insert("uid", "testuid");
193 193
194 //Ensure all local data is processed 194 // Ensure all local data is processed
195 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 195 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
196 196
197 //Test create 197 // Test create
198 Sink::ApplicationDomain::Event event2; 198 Sink::ApplicationDomain::Event event2;
199 { 199 {
200 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query); 200 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query);
@@ -210,10 +210,10 @@ private slots:
210 event2.setProperty("summary", "summaryValue2"); 210 event2.setProperty("summary", "summaryValue2");
211 Sink::Store::modify<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished(); 211 Sink::Store::modify<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished();
212 212
213 //Ensure all local data is processed 213 // Ensure all local data is processed
214 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 214 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
215 215
216 //Test modify 216 // Test modify
217 { 217 {
218 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query); 218 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query);
219 QTRY_COMPARE(model->rowCount(QModelIndex()), 1); 219 QTRY_COMPARE(model->rowCount(QModelIndex()), 1);
@@ -225,10 +225,10 @@ private slots:
225 225
226 Sink::Store::remove<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished(); 226 Sink::Store::remove<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished();
227 227
228 //Ensure all local data is processed 228 // Ensure all local data is processed
229 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 229 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
230 230
231 //Test remove 231 // Test remove
232 { 232 {
233 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query); 233 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query);
234 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 234 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
@@ -253,7 +253,7 @@ private slots:
253 event.setProperty("summary", "summaryValue"); 253 event.setProperty("summary", "summaryValue");
254 Sink::Store::create<Sink::ApplicationDomain::Event>(event).exec().waitForFinished(); 254 Sink::Store::create<Sink::ApplicationDomain::Event>(event).exec().waitForFinished();
255 255
256 //Test create 256 // Test create
257 Sink::ApplicationDomain::Event event2; 257 Sink::ApplicationDomain::Event event2;
258 { 258 {
259 QTRY_COMPARE(model->rowCount(QModelIndex()), 1); 259 QTRY_COMPARE(model->rowCount(QModelIndex()), 1);
@@ -267,9 +267,9 @@ private slots:
267 event2.setProperty("summary", "summaryValue2"); 267 event2.setProperty("summary", "summaryValue2");
268 Sink::Store::modify<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished(); 268 Sink::Store::modify<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished();
269 269
270 //Test modify 270 // Test modify
271 { 271 {
272 //TODO wait for a change signal 272 // TODO wait for a change signal
273 QTRY_COMPARE(model->rowCount(QModelIndex()), 1); 273 QTRY_COMPARE(model->rowCount(QModelIndex()), 1);
274 auto value = model->index(0, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Event::Ptr>(); 274 auto value = model->index(0, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Event::Ptr>();
275 QCOMPARE(value->getProperty("uid").toByteArray(), QByteArray("testuid")); 275 QCOMPARE(value->getProperty("uid").toByteArray(), QByteArray("testuid"));
@@ -278,12 +278,11 @@ private slots:
278 278
279 Sink::Store::remove<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished(); 279 Sink::Store::remove<Sink::ApplicationDomain::Event>(event2).exec().waitForFinished();
280 280
281 //Test remove 281 // Test remove
282 { 282 {
283 QTRY_COMPARE(model->rowCount(QModelIndex()), 0); 283 QTRY_COMPARE(model->rowCount(QModelIndex()), 0);
284 } 284 }
285 } 285 }
286
287}; 286};
288 287
289QTEST_MAIN(DummyResourceTest) 288QTEST_MAIN(DummyResourceTest)
diff --git a/tests/dummyresourcewritebenchmark.cpp b/tests/dummyresourcewritebenchmark.cpp
index 539d189..b4ab438 100644
--- a/tests/dummyresourcewritebenchmark.cpp
+++ b/tests/dummyresourcewritebenchmark.cpp
@@ -123,39 +123,39 @@ class DummyResourceWriteBenchmark : public QObject
123 Q_UNUSED(appendTime); 123 Q_UNUSED(appendTime);
124 auto bufferSizeTotal = bufferSize * num; 124 auto bufferSizeTotal = bufferSize * num;
125 125
126 //Wait until all messages have been processed 126 // Wait until all messages have been processed
127 resource.processAllMessages().exec().waitForFinished(); 127 resource.processAllMessages().exec().waitForFinished();
128 128
129 auto allProcessedTime = time.elapsed(); 129 auto allProcessedTime = time.elapsed();
130 130
131 const auto finalRss = getCurrentRSS(); 131 const auto finalRss = getCurrentRSS();
132 const auto rssGrowth = finalRss - startingRss; 132 const auto rssGrowth = finalRss - startingRss;
133 //Since the database is memory mapped it is attributted to the resident set size. 133 // Since the database is memory mapped it is attributted to the resident set size.
134 const auto rssWithoutDb = finalRss - DummyResource::diskUsage("org.kde.dummy.instance1"); 134 const auto rssWithoutDb = finalRss - DummyResource::diskUsage("org.kde.dummy.instance1");
135 const auto peakRss = getPeakRSS(); 135 const auto peakRss = getPeakRSS();
136 //How much peak deviates from final rss in percent 136 // How much peak deviates from final rss in percent
137 const auto percentageRssError = static_cast<double>(peakRss - finalRss)*100.0/static_cast<double>(finalRss); 137 const auto percentageRssError = static_cast<double>(peakRss - finalRss) * 100.0 / static_cast<double>(finalRss);
138 auto rssGrowthPerEntity = rssGrowth/num; 138 auto rssGrowthPerEntity = rssGrowth / num;
139 std::cout << "Current Rss usage [kb]: " << finalRss/1024 << std::endl; 139 std::cout << "Current Rss usage [kb]: " << finalRss / 1024 << std::endl;
140 std::cout << "Peak Rss usage [kb]: " << peakRss/1024 << std::endl; 140 std::cout << "Peak Rss usage [kb]: " << peakRss / 1024 << std::endl;
141 std::cout << "Rss growth [kb]: " << rssGrowth/1024 << std::endl; 141 std::cout << "Rss growth [kb]: " << rssGrowth / 1024 << std::endl;
142 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl; 142 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl;
143 std::cout << "Rss without db [kb]: " << rssWithoutDb/1024 << std::endl; 143 std::cout << "Rss without db [kb]: " << rssWithoutDb / 1024 << std::endl;
144 std::cout << "Percentage peak rss error: " << percentageRssError << std::endl; 144 std::cout << "Percentage peak rss error: " << percentageRssError << std::endl;
145 145
146 auto onDisk = DummyResource::diskUsage("org.kde.dummy.instance1"); 146 auto onDisk = DummyResource::diskUsage("org.kde.dummy.instance1");
147 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal); 147 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal);
148 std::cout << "On disk [kb]: " << onDisk/1024 << std::endl; 148 std::cout << "On disk [kb]: " << onDisk / 1024 << std::endl;
149 std::cout << "Buffer size total [kb]: " << bufferSizeTotal/1024 << std::endl; 149 std::cout << "Buffer size total [kb]: " << bufferSizeTotal / 1024 << std::endl;
150 std::cout << "Write amplification: " << writeAmplification << std::endl; 150 std::cout << "Write amplification: " << writeAmplification << std::endl;
151 151
152 152
153 mTimePerEntity << static_cast<double>(allProcessedTime)/static_cast<double>(num); 153 mTimePerEntity << static_cast<double>(allProcessedTime) / static_cast<double>(num);
154 mRssGrowthPerEntity << rssGrowthPerEntity; 154 mRssGrowthPerEntity << rssGrowthPerEntity;
155 155
156 QVERIFY(percentageRssError < 10); 156 QVERIFY(percentageRssError < 10);
157 //TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase, 157 // TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase,
158 //so it doesn't look like that memory is being duplicated. 158 // so it doesn't look like that memory is being duplicated.
159 QVERIFY(rssGrowthPerEntity < 2500); 159 QVERIFY(rssGrowthPerEntity < 2500);
160 160
161 // HAWD::Dataset dataset("dummy_write_in_process", m_hawdState); 161 // HAWD::Dataset dataset("dummy_write_in_process", m_hawdState);
@@ -219,7 +219,7 @@ private slots:
219 std::system(QString("mdb_stat %1/%2 -ff").arg(Sink::storageLocation()).arg("org.kde.dummy.instance1").toLatin1().constData()); 219 std::system(QString("mdb_stat %1/%2 -ff").arg(Sink::storageLocation()).arg("org.kde.dummy.instance1").toLatin1().constData());
220 } 220 }
221 221
222 //This allows to run individual parts without doing a cleanup, but still cleaning up normally 222 // This allows to run individual parts without doing a cleanup, but still cleaning up normally
223 void testCleanupForCompleteTest() 223 void testCleanupForCompleteTest()
224 { 224 {
225 DummyResource::removeFromDisk("org.kde.dummy.instance1"); 225 DummyResource::removeFromDisk("org.kde.dummy.instance1");
diff --git a/tests/genericfacadetest.cpp b/tests/genericfacadetest.cpp
index 397bf6a..8336875 100644
--- a/tests/genericfacadetest.cpp
+++ b/tests/genericfacadetest.cpp
@@ -9,7 +9,7 @@
9#include <common/resultprovider.h> 9#include <common/resultprovider.h>
10#include <common/synclistresult.h> 10#include <common/synclistresult.h>
11 11
12//Replace with something different 12// Replace with something different
13#include "event_generated.h" 13#include "event_generated.h"
14 14
15 15
@@ -34,7 +34,7 @@ private slots:
34 Sink::Query query; 34 Sink::Query query;
35 query.liveQuery = false; 35 query.liveQuery = false;
36 36
37 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr> >::create(); 37 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create();
38 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 38 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
39 // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create(); 39 // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create();
40 TestResourceFacade facade("identifier", resourceAccess); 40 TestResourceFacade facade("identifier", resourceAccess);
@@ -44,7 +44,7 @@ private slots:
44 facade.load(query, *resultSet).exec().waitForFinished(); 44 facade.load(query, *resultSet).exec().waitForFinished();
45 resultSet->initialResultSetComplete(); 45 resultSet->initialResultSetComplete();
46 46
47 //We have to wait for the events that deliver the results to be processed by the eventloop 47 // We have to wait for the events that deliver the results to be processed by the eventloop
48 result.exec(); 48 result.exec();
49 49
50 QCOMPARE(result.size(), 1); 50 QCOMPARE(result.size(), 1);
@@ -55,7 +55,7 @@ private slots:
55 Sink::Query query; 55 Sink::Query query;
56 query.liveQuery = true; 56 query.liveQuery = true;
57 57
58 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr> >::create(); 58 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create();
59 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 59 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
60 // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create(); 60 // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create();
61 TestResourceFacade facade("identifier", resourceAccess); 61 TestResourceFacade facade("identifier", resourceAccess);
@@ -68,13 +68,13 @@ private slots:
68 result.exec(); 68 result.exec();
69 QCOMPARE(result.size(), 1); 69 QCOMPARE(result.size(), 1);
70 70
71 //Enter a second result 71 // Enter a second result
72 // storage->mResults.clear(); 72 // storage->mResults.clear();
73 // storage->mResults << QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>()); 73 // storage->mResults << QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>());
74 // storage->mLatestRevision = 2; 74 // storage->mLatestRevision = 2;
75 resourceAccess->emit revisionChanged(2); 75 resourceAccess->emit revisionChanged(2);
76 76
77 //Hack to get event loop in synclistresult to abort again 77 // Hack to get event loop in synclistresult to abort again
78 resultSet->initialResultSetComplete(); 78 resultSet->initialResultSetComplete();
79 result.exec(); 79 result.exec();
80 80
@@ -86,7 +86,7 @@ private slots:
86 Sink::Query query; 86 Sink::Query query;
87 query.liveQuery = true; 87 query.liveQuery = true;
88 88
89 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr> >::create(); 89 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create();
90 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 90 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
91 auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 91 auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
92 entity->setProperty("test", "test1"); 92 entity->setProperty("test", "test1");
@@ -101,7 +101,7 @@ private slots:
101 result.exec(); 101 result.exec();
102 QCOMPARE(result.size(), 1); 102 QCOMPARE(result.size(), 1);
103 103
104 //Modify the entity again 104 // Modify the entity again
105 // storage->mResults.clear(); 105 // storage->mResults.clear();
106 entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); 106 entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
107 entity->setProperty("test", "test2"); 107 entity->setProperty("test", "test2");
@@ -109,7 +109,7 @@ private slots:
109 // storage->mLatestRevision = 2; 109 // storage->mLatestRevision = 2;
110 resourceAccess->emit revisionChanged(2); 110 resourceAccess->emit revisionChanged(2);
111 111
112 //Hack to get event loop in synclistresult to abort again 112 // Hack to get event loop in synclistresult to abort again
113 resultSet->initialResultSetComplete(); 113 resultSet->initialResultSetComplete();
114 result.exec(); 114 result.exec();
115 115
@@ -122,7 +122,7 @@ private slots:
122 Sink::Query query; 122 Sink::Query query;
123 query.liveQuery = true; 123 query.liveQuery = true;
124 124
125 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr> >::create(); 125 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create();
126 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 126 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
127 auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>()); 127 auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>());
128 // storage->mResults << entity; 128 // storage->mResults << entity;
@@ -136,13 +136,13 @@ private slots:
136 result.exec(); 136 result.exec();
137 QCOMPARE(result.size(), 1); 137 QCOMPARE(result.size(), 1);
138 138
139 //Remove the entity again 139 // Remove the entity again
140 // storage->mResults.clear(); 140 // storage->mResults.clear();
141 // storage->mRemovals << entity; 141 // storage->mRemovals << entity;
142 // storage->mLatestRevision = 2; 142 // storage->mLatestRevision = 2;
143 resourceAccess->emit revisionChanged(2); 143 resourceAccess->emit revisionChanged(2);
144 144
145 //Hack to get event loop in synclistresult to abort again 145 // Hack to get event loop in synclistresult to abort again
146 resultSet->initialResultSetComplete(); 146 resultSet->initialResultSetComplete();
147 result.exec(); 147 result.exec();
148 148
diff --git a/tests/genericresourcebenchmark.cpp b/tests/genericresourcebenchmark.cpp
index b3af6a6..a0a368c 100644
--- a/tests/genericresourcebenchmark.cpp
+++ b/tests/genericresourcebenchmark.cpp
@@ -60,7 +60,8 @@ static QByteArray createEntityBuffer()
60 return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); 60 return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
61} 61}
62 62
63class IndexUpdater : public Sink::Preprocessor { 63class IndexUpdater : public Sink::Preprocessor
64{
64public: 65public:
65 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 66 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
66 { 67 {
@@ -70,7 +71,8 @@ public:
70 } 71 }
71 } 72 }
72 73
73 void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 74 void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity,
75 Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
74 { 76 {
75 } 77 }
76 78
@@ -117,7 +119,7 @@ private slots:
117 } 119 }
118 auto appendTime = time.elapsed(); 120 auto appendTime = time.elapsed();
119 121
120 //Wait until all messages have been processed 122 // Wait until all messages have been processed
121 resource.processAllMessages().exec().waitForFinished(); 123 resource.processAllMessages().exec().waitForFinished();
122 124
123 auto allProcessedTime = time.elapsed(); 125 auto allProcessedTime = time.elapsed();
@@ -129,8 +131,8 @@ private slots:
129 HAWD::Dataset::Row row = dataset.row(); 131 HAWD::Dataset::Row row = dataset.row();
130 132
131 row.setValue("rows", num); 133 row.setValue("rows", num);
132 row.setValue("append", (qreal)num/appendTime); 134 row.setValue("append", (qreal)num / appendTime);
133 row.setValue("total", (qreal)num/allProcessedTime); 135 row.setValue("total", (qreal)num / allProcessedTime);
134 dataset.insertRow(row); 136 dataset.insertRow(row);
135 HAWD::Formatter::print(dataset); 137 HAWD::Formatter::print(dataset);
136 } 138 }
@@ -145,7 +147,7 @@ private slots:
145 const QByteArray resourceIdentifier = "org.kde.test.instance1"; 147 const QByteArray resourceIdentifier = "org.kde.test.instance1";
146 auto indexer = QSharedPointer<IndexUpdater>::create(); 148 auto indexer = QSharedPointer<IndexUpdater>::create();
147 149
148 pipeline->setPreprocessors("event", QVector<Sink::Preprocessor*>() << indexer.data()); 150 pipeline->setPreprocessors("event", QVector<Sink::Preprocessor *>() << indexer.data());
149 pipeline->setAdaptorFactory("event", eventFactory); 151 pipeline->setAdaptorFactory("event", eventFactory);
150 152
151 TestResource resource("org.kde.test.instance1", pipeline); 153 TestResource resource("org.kde.test.instance1", pipeline);
@@ -160,7 +162,7 @@ private slots:
160 } 162 }
161 auto appendTime = time.elapsed(); 163 auto appendTime = time.elapsed();
162 164
163 //Wait until all messages have been processed 165 // Wait until all messages have been processed
164 resource.processAllMessages().exec().waitForFinished(); 166 resource.processAllMessages().exec().waitForFinished();
165 167
166 auto allProcessedTime = time.elapsed(); 168 auto allProcessedTime = time.elapsed();
@@ -172,8 +174,8 @@ private slots:
172 HAWD::Dataset::Row row = dataset.row(); 174 HAWD::Dataset::Row row = dataset.row();
173 175
174 row.setValue("rows", num); 176 row.setValue("rows", num);
175 row.setValue("append", (qreal)num/appendTime); 177 row.setValue("append", (qreal)num / appendTime);
176 row.setValue("total", (qreal)num/allProcessedTime); 178 row.setValue("total", (qreal)num / allProcessedTime);
177 dataset.insertRow(row); 179 dataset.insertRow(row);
178 HAWD::Formatter::print(dataset); 180 HAWD::Formatter::print(dataset);
179 } 181 }
@@ -190,7 +192,7 @@ private slots:
190 192
191 static flatbuffers::FlatBufferBuilder fbb; 193 static flatbuffers::FlatBufferBuilder fbb;
192 fbb.Clear(); 194 fbb.Clear();
193 //This is the resource buffer type and not the domain type 195 // This is the resource buffer type and not the domain type
194 auto type = fbb.CreateString("event"); 196 auto type = fbb.CreateString("event");
195 // auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); 197 // auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize());
196 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); 198 auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize());
diff --git a/tests/genericresourcetest.cpp b/tests/genericresourcetest.cpp
index a04c634..7474cbf 100644
--- a/tests/genericresourcetest.cpp
+++ b/tests/genericresourcetest.cpp
@@ -16,7 +16,7 @@
16 16
17/** 17/**
18 * Test of the generic resource implementation. 18 * Test of the generic resource implementation.
19 * 19 *
20 * This test relies on a working pipeline implementation, and writes to storage. 20 * This test relies on a working pipeline implementation, and writes to storage.
21 */ 21 */
22class GenericResourceTest : public QObject 22class GenericResourceTest : public QObject
@@ -30,7 +30,7 @@ private slots:
30 Sink::Log::setDebugOutputLevel(Sink::Log::Trace); 30 Sink::Log::setDebugOutputLevel(Sink::Log::Trace);
31 } 31 }
32 32
33 ///Ensure the resource can process messages 33 /// Ensure the resource can process messages
34 void testProcessCommand() 34 void testProcessCommand()
35 { 35 {
36 flatbuffers::FlatBufferBuilder eventFbb; 36 flatbuffers::FlatBufferBuilder eventFbb;
@@ -70,7 +70,7 @@ private slots:
70 QVERIFY(Sink::Commands::VerifyCreateEntityBuffer(verifyer)); 70 QVERIFY(Sink::Commands::VerifyCreateEntityBuffer(verifyer));
71 } 71 }
72 72
73 //Actual test 73 // Actual test
74 auto pipeline = QSharedPointer<Sink::Pipeline>::create("org.kde.test.instance1"); 74 auto pipeline = QSharedPointer<Sink::Pipeline>::create("org.kde.test.instance1");
75 QSignalSpy revisionSpy(pipeline.data(), SIGNAL(revisionUpdated(qint64))); 75 QSignalSpy revisionSpy(pipeline.data(), SIGNAL(revisionUpdated(qint64)));
76 QVERIFY(revisionSpy.isValid()); 76 QVERIFY(revisionSpy.isValid());
diff --git a/tests/getrssusage.cpp b/tests/getrssusage.cpp
index 020c7d6..16fec52 100644
--- a/tests/getrssusage.cpp
+++ b/tests/getrssusage.cpp
@@ -21,7 +21,7 @@
21#if defined(__APPLE__) && defined(__MACH__) 21#if defined(__APPLE__) && defined(__MACH__)
22#include <mach/mach.h> 22#include <mach/mach.h>
23 23
24#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) 24#elif(defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
25#include <fcntl.h> 25#include <fcntl.h>
26#include <procfs.h> 26#include <procfs.h>
27 27
@@ -40,85 +40,79 @@
40 * memory use) measured in bytes, or zero if the value cannot be 40 * memory use) measured in bytes, or zero if the value cannot be
41 * determined on this OS. 41 * determined on this OS.
42 */ 42 */
43size_t getPeakRSS( ) 43size_t getPeakRSS()
44{ 44{
45#if defined(_WIN32) 45#if defined(_WIN32)
46 /* Windows -------------------------------------------------- */ 46 /* Windows -------------------------------------------------- */
47 PROCESS_MEMORY_COUNTERS info; 47 PROCESS_MEMORY_COUNTERS info;
48 GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); 48 GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
49 return (size_t)info.PeakWorkingSetSize; 49 return (size_t)info.PeakWorkingSetSize;
50 50
51#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) 51#elif(defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
52 /* AIX and Solaris ------------------------------------------ */ 52 /* AIX and Solaris ------------------------------------------ */
53 struct psinfo psinfo; 53 struct psinfo psinfo;
54 int fd = -1; 54 int fd = -1;
55 if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 ) 55 if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
56 return (size_t)0L; /* Can't open? */ 56 return (size_t)0L; /* Can't open? */
57 if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) ) 57 if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
58 { 58 close(fd);
59 close( fd ); 59 return (size_t)0L; /* Can't read? */
60 return (size_t)0L; /* Can't read? */ 60 }
61 } 61 close(fd);
62 close( fd ); 62 return (size_t)(psinfo.pr_rssize * 1024L);
63 return (size_t)(psinfo.pr_rssize * 1024L);
64 63
65#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) 64#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
66 /* BSD, Linux, and OSX -------------------------------------- */ 65 /* BSD, Linux, and OSX -------------------------------------- */
67 struct rusage rusage; 66 struct rusage rusage;
68 getrusage( RUSAGE_SELF, &rusage ); 67 getrusage(RUSAGE_SELF, &rusage);
69#if defined(__APPLE__) && defined(__MACH__) 68#if defined(__APPLE__) && defined(__MACH__)
70 return (size_t)rusage.ru_maxrss; 69 return (size_t)rusage.ru_maxrss;
71#else 70#else
72 return (size_t)(rusage.ru_maxrss * 1024L); 71 return (size_t)(rusage.ru_maxrss * 1024L);
73#endif 72#endif
74 73
75#else 74#else
76 /* Unknown OS ----------------------------------------------- */ 75 /* Unknown OS ----------------------------------------------- */
77 return (size_t)0L; /* Unsupported. */ 76 return (size_t)0L; /* Unsupported. */
78#endif 77#endif
79} 78}
80 79
81 80
82
83
84
85/** 81/**
86 * Returns the current resident set size (physical memory use) measured 82 * Returns the current resident set size (physical memory use) measured
87 * in bytes, or zero if the value cannot be determined on this OS. 83 * in bytes, or zero if the value cannot be determined on this OS.
88 */ 84 */
89size_t getCurrentRSS( ) 85size_t getCurrentRSS()
90{ 86{
91#if defined(_WIN32) 87#if defined(_WIN32)
92 /* Windows -------------------------------------------------- */ 88 /* Windows -------------------------------------------------- */
93 PROCESS_MEMORY_COUNTERS info; 89 PROCESS_MEMORY_COUNTERS info;
94 GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) ); 90 GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
95 return (size_t)info.WorkingSetSize; 91 return (size_t)info.WorkingSetSize;
96 92
97#elif defined(__APPLE__) && defined(__MACH__) 93#elif defined(__APPLE__) && defined(__MACH__)
98 /* OSX ------------------------------------------------------ */ 94 /* OSX ------------------------------------------------------ */
99 struct mach_task_basic_info info; 95 struct mach_task_basic_info info;
100 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; 96 mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
101 if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO, 97 if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) != KERN_SUCCESS)
102 (task_info_t)&info, &infoCount ) != KERN_SUCCESS ) 98 return (size_t)0L; /* Can't access? */
103 return (size_t)0L; /* Can't access? */ 99 return (size_t)info.resident_size;
104 return (size_t)info.resident_size;
105 100
106#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) 101#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
107 /* Linux ---------------------------------------------------- */ 102 /* Linux ---------------------------------------------------- */
108 long rss = 0L; 103 long rss = 0L;
109 FILE* fp = NULL; 104 FILE *fp = NULL;
110 if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL ) 105 if ((fp = fopen("/proc/self/statm", "r")) == NULL)
111 return (size_t)0L; /* Can't open? */ 106 return (size_t)0L; /* Can't open? */
112 if ( fscanf( fp, "%*s%ld", &rss ) != 1 ) 107 if (fscanf(fp, "%*s%ld", &rss) != 1) {
113 { 108 fclose(fp);
114 fclose( fp ); 109 return (size_t)0L; /* Can't read? */
115 return (size_t)0L; /* Can't read? */ 110 }
116 } 111 fclose(fp);
117 fclose( fp ); 112 return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
118 return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
119 113
120#else 114#else
121 /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ 115 /* AIX, BSD, Solaris, and Unknown OS ------------------------ */
122 return (size_t)0L; /* Unsupported. */ 116 return (size_t)0L; /* Unsupported. */
123#endif 117#endif
124} 118}
diff --git a/tests/getrssusage.h b/tests/getrssusage.h
index e47b14c..bc3d91e 100644
--- a/tests/getrssusage.h
+++ b/tests/getrssusage.h
@@ -22,7 +22,7 @@
22#if defined(__APPLE__) && defined(__MACH__) 22#if defined(__APPLE__) && defined(__MACH__)
23#include <mach/mach.h> 23#include <mach/mach.h>
24 24
25#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) 25#elif(defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
26#include <fcntl.h> 26#include <fcntl.h>
27#include <procfs.h> 27#include <procfs.h>
28 28
diff --git a/tests/indextest.cpp b/tests/indextest.cpp
index 1676ecb..fa3ace4 100644
--- a/tests/indextest.cpp
+++ b/tests/indextest.cpp
@@ -29,42 +29,29 @@ private slots:
29 void testIndex() 29 void testIndex()
30 { 30 {
31 Index index("./testindex", "org.kde.dummy.testindex", Sink::Storage::ReadWrite); 31 Index index("./testindex", "org.kde.dummy.testindex", Sink::Storage::ReadWrite);
32 //The first key is specifically a substring of the second key 32 // The first key is specifically a substring of the second key
33 index.add("key", "value1"); 33 index.add("key", "value1");
34 index.add("keyFoo", "value2"); 34 index.add("keyFoo", "value2");
35 index.add("keyFoo", "value3"); 35 index.add("keyFoo", "value3");
36 36
37 { 37 {
38 QList<QByteArray> values; 38 QList<QByteArray> values;
39 index.lookup(QByteArray("key"), [&values](const QByteArray &value) { 39 index.lookup(QByteArray("key"), [&values](const QByteArray &value) { values << value; }, [](const Index::Error &error) { qWarning() << "Error: "; });
40 values << value;
41 },
42 [](const Index::Error &error){ qWarning() << "Error: "; });
43 QCOMPARE(values.size(), 1); 40 QCOMPARE(values.size(), 1);
44 } 41 }
45 { 42 {
46 QList<QByteArray> values; 43 QList<QByteArray> values;
47 index.lookup(QByteArray("keyFoo"), [&values](const QByteArray &value) { 44 index.lookup(QByteArray("keyFoo"), [&values](const QByteArray &value) { values << value; }, [](const Index::Error &error) { qWarning() << "Error: "; });
48 values << value;
49 },
50 [](const Index::Error &error){ qWarning() << "Error: "; });
51 QCOMPARE(values.size(), 2); 45 QCOMPARE(values.size(), 2);
52 } 46 }
53 { 47 {
54 QList<QByteArray> values; 48 QList<QByteArray> values;
55 index.lookup(QByteArray("key3"), [&values](const QByteArray &value) { 49 index.lookup(QByteArray("key3"), [&values](const QByteArray &value) { values << value; }, [](const Index::Error &error) { qWarning() << "Error: "; });
56 values << value;
57 },
58 [](const Index::Error &error){ qWarning() << "Error: "; });
59 QCOMPARE(values.size(), 0); 50 QCOMPARE(values.size(), 0);
60 } 51 }
61 { 52 {
62 QList<QByteArray> values; 53 QList<QByteArray> values;
63 index.lookup(QByteArray("key"), [&values](const QByteArray &value) { 54 index.lookup(QByteArray("key"), [&values](const QByteArray &value) { values << value; }, [](const Index::Error &error) { qWarning() << "Error: "; }, true);
64 values << value;
65 },
66 [](const Index::Error &error){ qWarning() << "Error: "; },
67 true);
68 QCOMPARE(values.size(), 3); 55 QCOMPARE(values.size(), 3);
69 } 56 }
70 } 57 }
diff --git a/tests/inspectiontest.cpp b/tests/inspectiontest.cpp
index cdf62e6..38bf23d 100644
--- a/tests/inspectiontest.cpp
+++ b/tests/inspectiontest.cpp
@@ -41,7 +41,7 @@ private slots:
41 41
42 Mail mail(QByteArray("org.kde.dummy.instance1"), QByteArray("identifier"), 0, QSharedPointer<MemoryBufferAdaptor::MemoryBufferAdaptor>::create()); 42 Mail mail(QByteArray("org.kde.dummy.instance1"), QByteArray("identifier"), 0, QSharedPointer<MemoryBufferAdaptor::MemoryBufferAdaptor>::create());
43 43
44 //testInspection is a magic property that the dummyresource supports 44 // testInspection is a magic property that the dummyresource supports
45 auto inspectionCommand = ResourceControl::Inspection::PropertyInspection(mail, "testInspection", success); 45 auto inspectionCommand = ResourceControl::Inspection::PropertyInspection(mail, "testInspection", success);
46 auto result = ResourceControl::inspect<Mail>(inspectionCommand).exec(); 46 auto result = ResourceControl::inspect<Mail>(inspectionCommand).exec();
47 result.waitForFinished(); 47 result.waitForFinished();
diff --git a/tests/maildirresourcetest.cpp b/tests/maildirresourcetest.cpp
index d5f7f95..b5c1c3c 100644
--- a/tests/maildirresourcetest.cpp
+++ b/tests/maildirresourcetest.cpp
@@ -12,8 +12,7 @@
12#include "pipeline.h" 12#include "pipeline.h"
13#include "log.h" 13#include "log.h"
14 14
15static bool copyRecursively(const QString &srcFilePath, 15static bool copyRecursively(const QString &srcFilePath, const QString &tgtFilePath)
16 const QString &tgtFilePath)
17{ 16{
18 QFileInfo srcFileInfo(srcFilePath); 17 QFileInfo srcFileInfo(srcFilePath);
19 if (srcFileInfo.isDir()) { 18 if (srcFileInfo.isDir()) {
@@ -26,10 +25,8 @@ static bool copyRecursively(const QString &srcFilePath,
26 QDir sourceDir(srcFilePath); 25 QDir sourceDir(srcFilePath);
27 QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); 26 QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
28 foreach (const QString &fileName, fileNames) { 27 foreach (const QString &fileName, fileNames) {
29 const QString newSrcFilePath 28 const QString newSrcFilePath = srcFilePath + QLatin1Char('/') + fileName;
30 = srcFilePath + QLatin1Char('/') + fileName; 29 const QString newTgtFilePath = tgtFilePath + QLatin1Char('/') + fileName;
31 const QString newTgtFilePath
32 = tgtFilePath + QLatin1Char('/') + fileName;
33 if (!copyRecursively(newSrcFilePath, newTgtFilePath)) 30 if (!copyRecursively(newSrcFilePath, newTgtFilePath))
34 return false; 31 return false;
35 } 32 }
@@ -44,7 +41,7 @@ static bool copyRecursively(const QString &srcFilePath,
44 41
45/** 42/**
46 * Test of complete system using the maildir resource. 43 * Test of complete system using the maildir resource.
47 * 44 *
48 * This test requires the maildir resource installed. 45 * This test requires the maildir resource installed.
49 */ 46 */
50class MaildirResourceTest : public QObject 47class MaildirResourceTest : public QObject
@@ -89,7 +86,7 @@ private slots:
89 Sink::Query query; 86 Sink::Query query;
90 query.resources << "org.kde.maildir.instance1"; 87 query.resources << "org.kde.maildir.instance1";
91 88
92 //Ensure all local data is processed 89 // Ensure all local data is processed
93 Sink::Store::synchronize(query).exec().waitForFinished(); 90 Sink::Store::synchronize(query).exec().waitForFinished();
94 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 91 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
95 92
@@ -104,7 +101,7 @@ private slots:
104 query.resources << "org.kde.maildir.instance1"; 101 query.resources << "org.kde.maildir.instance1";
105 query.parentProperty = "parent"; 102 query.parentProperty = "parent";
106 103
107 //Ensure all local data is processed 104 // Ensure all local data is processed
108 Sink::Store::synchronize(query).exec().waitForFinished(); 105 Sink::Store::synchronize(query).exec().waitForFinished();
109 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 106 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
110 107
@@ -121,23 +118,18 @@ private slots:
121 { 118 {
122 using namespace Sink; 119 using namespace Sink;
123 using namespace Sink::ApplicationDomain; 120 using namespace Sink::ApplicationDomain;
124 //Ensure all local data is processed 121 // Ensure all local data is processed
125 auto query = Query::ResourceFilter("org.kde.maildir.instance1"); 122 auto query = Query::ResourceFilter("org.kde.maildir.instance1");
126 Store::synchronize(query).exec().waitForFinished(); 123 Store::synchronize(query).exec().waitForFinished();
127 ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 124 ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
128 auto result = Store::fetchOne<Folder>( 125 auto result = Store::fetchOne<Folder>(Query::ResourceFilter("org.kde.maildir.instance1") + Query::RequestedProperties(QByteArrayList() << "name"))
129 Query::ResourceFilter("org.kde.maildir.instance1") + Query::RequestedProperties(QByteArrayList() << "name") 126 .then<QList<Mail::Ptr>, Folder>([](const Folder &folder) {
130 ) 127 Trace() << "Found a folder" << folder.identifier();
131 .then<QList<Mail::Ptr>, Folder>([](const Folder &folder) { 128 return Store::fetchAll<Mail>(Query::PropertyFilter("folder", folder) + Query::RequestedProperties(QByteArrayList() << "folder"
132 Trace() << "Found a folder" << folder.identifier(); 129 << "subject"));
133 return Store::fetchAll<Mail>( 130 })
134 Query::PropertyFilter("folder", folder) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject") 131 .then<void, QList<Mail::Ptr>>([](const QList<Mail::Ptr> &mails) { QVERIFY(mails.size() >= 1); })
135 ); 132 .exec();
136 })
137 .then<void, QList<Mail::Ptr> >([](const QList<Mail::Ptr> &mails) {
138 QVERIFY(mails.size() >= 1);
139 })
140 .exec();
141 result.waitForFinished(); 133 result.waitForFinished();
142 QVERIFY(!result.errorCode()); 134 QVERIFY(!result.errorCode());
143 } 135 }
@@ -146,9 +138,12 @@ private slots:
146 { 138 {
147 Sink::Query query; 139 Sink::Query query;
148 query.resources << "org.kde.maildir.instance1"; 140 query.resources << "org.kde.maildir.instance1";
149 query.requestedProperties << "folder" << "subject" << "mimeMessage" << "date"; 141 query.requestedProperties << "folder"
142 << "subject"
143 << "mimeMessage"
144 << "date";
150 145
151 //Ensure all local data is processed 146 // Ensure all local data is processed
152 Sink::Store::synchronize(query).exec().waitForFinished(); 147 Sink::Store::synchronize(query).exec().waitForFinished();
153 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 148 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
154 149
@@ -171,7 +166,7 @@ private slots:
171 query.resources << "org.kde.maildir.instance1"; 166 query.resources << "org.kde.maildir.instance1";
172 query.requestedProperties << "name"; 167 query.requestedProperties << "name";
173 168
174 //Ensure all local data is processed 169 // Ensure all local data is processed
175 Sink::Store::synchronize(query).exec().waitForFinished(); 170 Sink::Store::synchronize(query).exec().waitForFinished();
176 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 171 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
177 172
@@ -179,7 +174,7 @@ private slots:
179 QDir dir(targetPath); 174 QDir dir(targetPath);
180 QVERIFY(dir.rename("inbox", "newbox")); 175 QVERIFY(dir.rename("inbox", "newbox"));
181 176
182 //Ensure all local data is processed 177 // Ensure all local data is processed
183 Sink::Store::synchronize(query).exec().waitForFinished(); 178 Sink::Store::synchronize(query).exec().waitForFinished();
184 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 179 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
185 180
@@ -193,13 +188,14 @@ private slots:
193 { 188 {
194 Sink::Query query; 189 Sink::Query query;
195 query.resources << "org.kde.maildir.instance1"; 190 query.resources << "org.kde.maildir.instance1";
196 query.requestedProperties << "folder" << "subject"; 191 query.requestedProperties << "folder"
192 << "subject";
197 193
198 //Ensure all local data is processed 194 // Ensure all local data is processed
199 Sink::Store::synchronize(query).exec().waitForFinished(); 195 Sink::Store::synchronize(query).exec().waitForFinished();
200 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 196 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
201 197
202 //Ensure all local data is processed 198 // Ensure all local data is processed
203 Sink::Store::synchronize(query).exec().waitForFinished(); 199 Sink::Store::synchronize(query).exec().waitForFinished();
204 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 200 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
205 201
@@ -212,9 +208,10 @@ private slots:
212 { 208 {
213 Sink::Query query; 209 Sink::Query query;
214 query.resources << "org.kde.maildir.instance1"; 210 query.resources << "org.kde.maildir.instance1";
215 query.requestedProperties << "folder" << "subject"; 211 query.requestedProperties << "folder"
212 << "subject";
216 213
217 //Ensure all local data is processed 214 // Ensure all local data is processed
218 Sink::Store::synchronize(query).exec().waitForFinished(); 215 Sink::Store::synchronize(query).exec().waitForFinished();
219 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 216 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
220 217
@@ -222,7 +219,7 @@ private slots:
222 QFile file(targetPath); 219 QFile file(targetPath);
223 QVERIFY(file.remove()); 220 QVERIFY(file.remove());
224 221
225 //Ensure all local data is processed 222 // Ensure all local data is processed
226 Sink::Store::synchronize(query).exec().waitForFinished(); 223 Sink::Store::synchronize(query).exec().waitForFinished();
227 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 224 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
228 225
@@ -236,7 +233,7 @@ private slots:
236 Sink::Query query; 233 Sink::Query query;
237 query.resources << "org.kde.maildir.instance1"; 234 query.resources << "org.kde.maildir.instance1";
238 235
239 //Ensure all local data is processed 236 // Ensure all local data is processed
240 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 237 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
241 238
242 Sink::ApplicationDomain::Folder folder("org.kde.maildir.instance1"); 239 Sink::ApplicationDomain::Folder folder("org.kde.maildir.instance1");
@@ -244,7 +241,7 @@ private slots:
244 241
245 Sink::Store::create(folder).exec().waitForFinished(); 242 Sink::Store::create(folder).exec().waitForFinished();
246 243
247 //Ensure all local data is processed 244 // Ensure all local data is processed
248 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 245 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
249 246
250 auto targetPath = tempDir.path() + "/maildir1/testCreateFolder"; 247 auto targetPath = tempDir.path() + "/maildir1/testCreateFolder";
@@ -284,16 +281,16 @@ private slots:
284 Sink::Query query; 281 Sink::Query query;
285 query.resources << "org.kde.maildir.instance1"; 282 query.resources << "org.kde.maildir.instance1";
286 283
287 //Ensure all local data is processed 284 // Ensure all local data is processed
288 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 285 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
289 286
290 Sink::ApplicationDomain::Mail mail("org.kde.maildir.instance1"); 287 Sink::ApplicationDomain::Mail mail("org.kde.maildir.instance1");
291 mail.setProperty("name", "testCreateMail"); 288 mail.setProperty("name", "testCreateMail");
292 //FIXME instead of properties, ensure the mimeMessage property is used and the file is moved as expected 289 // FIXME instead of properties, ensure the mimeMessage property is used and the file is moved as expected
293 290
294 Sink::Store::create(mail).exec().waitForFinished(); 291 Sink::Store::create(mail).exec().waitForFinished();
295 292
296 //Ensure all local data is processed 293 // Ensure all local data is processed
297 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 294 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
298 295
299 auto targetPath = tempDir.path() + "/maildir1/new"; 296 auto targetPath = tempDir.path() + "/maildir1/new";
@@ -312,25 +309,23 @@ private slots:
312 ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 309 ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
313 310
314 auto result = Store::fetchOne<Folder>( 311 auto result = Store::fetchOne<Folder>(
315 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("name", "maildir1") + Query::RequestedProperties(QByteArrayList() << "name") 312 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("name", "maildir1") + Query::RequestedProperties(QByteArrayList() << "name"))
316 ) 313 .then<void, KAsync::Job<void>, Folder>([query](const Folder &folder) {
317 .then<void, KAsync::Job<void>, Folder>([query](const Folder &folder) { 314 return Store::fetchAll<Mail>(Query::PropertyFilter("folder", folder) + Query::RequestedProperties(QByteArrayList() << "folder"
318 return Store::fetchAll<Mail>( 315 << "subject"))
319 Query::PropertyFilter("folder", folder) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject") 316 .then<void, KAsync::Job<void>, QList<Mail::Ptr>>([query](const QList<Mail::Ptr> &mails) {
320 ) 317 // Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE
321 .then<void, KAsync::Job<void>, QList<Mail::Ptr> >([query](const QList<Mail::Ptr> &mails) { 318 if (mails.size() != 1) {
322 //Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE 319 return KAsync::error<void>(1, "Wrong number of mails.");
323 if (mails.size() != 1) { 320 }
324 return KAsync::error<void>(1, "Wrong number of mails."); 321 auto mail = mails.first();
325 } 322
326 auto mail = mails.first(); 323 return Store::remove(*mail)
327 324 .then(ResourceControl::flushReplayQueue(query.resources)) // The change needs to be replayed already
328 return Store::remove(*mail) 325 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::ExistenceInspection(*mail, false)));
329 .then(ResourceControl::flushReplayQueue(query.resources)) //The change needs to be replayed already 326 });
330 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::ExistenceInspection(*mail, false))); 327 })
331 }); 328 .exec();
332 })
333 .exec();
334 result.waitForFinished(); 329 result.waitForFinished();
335 QVERIFY(!result.errorCode()); 330 QVERIFY(!result.errorCode());
336 } 331 }
@@ -347,61 +342,61 @@ private slots:
347 Folder f; 342 Folder f;
348 343
349 auto result = Store::fetchOne<Folder>( 344 auto result = Store::fetchOne<Folder>(
350 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("name", "maildir1") + Query::RequestedProperties(QByteArrayList() << "name") 345 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("name", "maildir1") + Query::RequestedProperties(QByteArrayList() << "name"))
351 ) 346 .then<void, KAsync::Job<void>, Folder>([query, &f](const Folder &folder) {
352 .then<void, KAsync::Job<void>, Folder>([query, &f](const Folder &folder) { 347 f = folder;
353 f = folder; 348 return Store::fetchAll<Mail>(Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", folder) +
354 return Store::fetchAll<Mail>( 349 Query::RequestedProperties(QByteArrayList() << "folder"
355 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", folder) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject") 350 << "subject"))
356 ) 351 .then<void, KAsync::Job<void>, QList<Mail::Ptr>>([query](const QList<Mail::Ptr> &mails) {
357 .then<void, KAsync::Job<void>, QList<Mail::Ptr> >([query](const QList<Mail::Ptr> &mails) { 352 // Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE
358 //Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE 353 if (mails.size() != 1) {
359 if (mails.size() != 1) { 354 return KAsync::error<void>(1, "Wrong number of mails.");
360 return KAsync::error<void>(1, "Wrong number of mails."); 355 }
361 } 356 auto mail = mails.first();
362 auto mail = mails.first(); 357 mail->setProperty("unread", true);
363 mail->setProperty("unread", true); 358 return Store::modify(*mail)
364 return Store::modify(*mail) 359 .then<void>(ResourceControl::flushReplayQueue(query.resources)) // The change needs to be replayed already
365 .then<void>(ResourceControl::flushReplayQueue(query.resources)) //The change needs to be replayed already 360 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::PropertyInspection(*mail, "unread", true)))
366 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::PropertyInspection(*mail, "unread", true))) 361 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::PropertyInspection(*mail, "subject", mail->getProperty("subject"))));
367 .then(ResourceControl::inspect<Mail>(ResourceControl::Inspection::PropertyInspection(*mail, "subject", mail->getProperty("subject")))); 362 });
368 }); 363 })
369 }) 364 .exec();
370 .exec();
371 result.waitForFinished(); 365 result.waitForFinished();
372 QVERIFY(!result.errorCode()); 366 QVERIFY(!result.errorCode());
373 367
374 //Verify that we can still query for all relevant information 368 // Verify that we can still query for all relevant information
375 auto result2 = Store::fetchAll<Mail>( 369 auto result2 = Store::fetchAll<Mail>(
376 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", f) + Query::RequestedProperties(QByteArrayList() << "folder" << "subject" << "mimeMessage" << "unread") 370 Query::ResourceFilter("org.kde.maildir.instance1") + Query::PropertyFilter("folder", f) + Query::RequestedProperties(QByteArrayList() << "folder"
377 ) 371 << "subject"
378 .then<void, KAsync::Job<void>, QList<Mail::Ptr> >([](const QList<Mail::Ptr> &mails) { 372 << "mimeMessage"
379 //Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE 373 << "unread"))
380 if (mails.size() != 1) { 374 .then<void, KAsync::Job<void>, QList<Mail::Ptr>>([](const QList<Mail::Ptr> &mails) {
381 qWarning() << "Wrong number of mails"; 375 // Can't use QCOMPARE because it tries to return FIXME Implement ASYNCCOMPARE
382 return KAsync::error<void>(1, "Wrong number of mails."); 376 if (mails.size() != 1) {
383 } 377 qWarning() << "Wrong number of mails";
384 auto mail = mails.first(); 378 return KAsync::error<void>(1, "Wrong number of mails.");
385 if (mail->getProperty("subject").toString().isEmpty()) { 379 }
386 qWarning() << "Wrong subject"; 380 auto mail = mails.first();
387 return KAsync::error<void>(1, "Wrong subject."); 381 if (mail->getProperty("subject").toString().isEmpty()) {
388 } 382 qWarning() << "Wrong subject";
389 if (mail->getProperty("unread").toBool() != true) { 383 return KAsync::error<void>(1, "Wrong subject.");
390 qWarning() << "Not unread"; 384 }
391 return KAsync::error<void>(1, "Not unread."); 385 if (mail->getProperty("unread").toBool() != true) {
392 } 386 qWarning() << "Not unread";
393 QFileInfo info(mail->getProperty("mimeMessage").toString()); 387 return KAsync::error<void>(1, "Not unread.");
394 if (!info.exists()) { 388 }
395 qWarning() << "Wrong subject"; 389 QFileInfo info(mail->getProperty("mimeMessage").toString());
396 return KAsync::error<void>(1, "Can't find mime message."); 390 if (!info.exists()) {
397 } 391 qWarning() << "Wrong subject";
398 return KAsync::null<void>(); 392 return KAsync::error<void>(1, "Can't find mime message.");
399 }) 393 }
400 .exec(); 394 return KAsync::null<void>();
395 })
396 .exec();
401 result2.waitForFinished(); 397 result2.waitForFinished();
402 QVERIFY(!result2.errorCode()); 398 QVERIFY(!result2.errorCode());
403 } 399 }
404
405}; 400};
406 401
407QTEST_MAIN(MaildirResourceTest) 402QTEST_MAIN(MaildirResourceTest)
diff --git a/tests/maildirsyncbenchmark.cpp b/tests/maildirsyncbenchmark.cpp
index 7904a82..06c5ab1 100644
--- a/tests/maildirsyncbenchmark.cpp
+++ b/tests/maildirsyncbenchmark.cpp
@@ -16,8 +16,7 @@
16#include "log.h" 16#include "log.h"
17 17
18 18
19static bool copyRecursively(const QString &srcFilePath, 19static bool copyRecursively(const QString &srcFilePath, const QString &tgtFilePath)
20 const QString &tgtFilePath)
21{ 20{
22 QFileInfo srcFileInfo(srcFilePath); 21 QFileInfo srcFileInfo(srcFilePath);
23 if (srcFileInfo.isDir()) { 22 if (srcFileInfo.isDir()) {
@@ -30,10 +29,8 @@ static bool copyRecursively(const QString &srcFilePath,
30 QDir sourceDir(srcFilePath); 29 QDir sourceDir(srcFilePath);
31 QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); 30 QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System);
32 foreach (const QString &fileName, fileNames) { 31 foreach (const QString &fileName, fileNames) {
33 const QString newSrcFilePath 32 const QString newSrcFilePath = srcFilePath + QLatin1Char('/') + fileName;
34 = srcFilePath + QLatin1Char('/') + fileName; 33 const QString newTgtFilePath = tgtFilePath + QLatin1Char('/') + fileName;
35 const QString newTgtFilePath
36 = tgtFilePath + QLatin1Char('/') + fileName;
37 if (!copyRecursively(newSrcFilePath, newTgtFilePath)) 34 if (!copyRecursively(newSrcFilePath, newTgtFilePath))
38 return false; 35 return false;
39 } 36 }
@@ -48,7 +45,7 @@ static bool copyRecursively(const QString &srcFilePath,
48 45
49/** 46/**
50 * Test of complete system using the maildir resource. 47 * Test of complete system using the maildir resource.
51 * 48 *
52 * This test requires the maildir resource installed. 49 * This test requires the maildir resource installed.
53 */ 50 */
54class MaildirSyncBenchmark : public QObject 51class MaildirSyncBenchmark : public QObject
@@ -102,7 +99,6 @@ private slots:
102 // row.setValue("totalTime", allProcessedTime); 99 // row.setValue("totalTime", allProcessedTime);
103 // dataset.insertRow(row); 100 // dataset.insertRow(row);
104 // HAWD::Formatter::print(dataset); 101 // HAWD::Formatter::print(dataset);
105
106 } 102 }
107}; 103};
108 104
diff --git a/tests/mailquerybenchmark.cpp b/tests/mailquerybenchmark.cpp
index ea919ac..6b93863 100644
--- a/tests/mailquerybenchmark.cpp
+++ b/tests/mailquerybenchmark.cpp
@@ -61,9 +61,9 @@ class MailQueryBenchmark : public QObject
61 auto pipeline = QSharedPointer<Sink::Pipeline>::create(resourceIdentifier); 61 auto pipeline = QSharedPointer<Sink::Pipeline>::create(resourceIdentifier);
62 62
63 auto mailFactory = QSharedPointer<TestMailAdaptorFactory>::create(); 63 auto mailFactory = QSharedPointer<TestMailAdaptorFactory>::create();
64 auto indexer = QSharedPointer<DefaultIndexUpdater<Sink::ApplicationDomain::Mail> >::create(); 64 auto indexer = QSharedPointer<DefaultIndexUpdater<Sink::ApplicationDomain::Mail>>::create();
65 65
66 pipeline->setPreprocessors("mail", QVector<Sink::Preprocessor*>() << indexer.data()); 66 pipeline->setPreprocessors("mail", QVector<Sink::Preprocessor *>() << indexer.data());
67 pipeline->setAdaptorFactory("mail", mailFactory); 67 pipeline->setAdaptorFactory("mail", mailFactory);
68 68
69 auto domainTypeAdaptorFactory = QSharedPointer<TestMailAdaptorFactory>::create(); 69 auto domainTypeAdaptorFactory = QSharedPointer<TestMailAdaptorFactory>::create();
@@ -88,11 +88,11 @@ class MailQueryBenchmark : public QObject
88 const auto startingRss = getCurrentRSS(); 88 const auto startingRss = getCurrentRSS();
89 89
90 90
91 //Benchmark 91 // Benchmark
92 QTime time; 92 QTime time;
93 time.start(); 93 time.start();
94 94
95 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Mail::Ptr> >::create(); 95 auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Mail::Ptr>>::create();
96 auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); 96 auto resourceAccess = QSharedPointer<TestResourceAccess>::create();
97 TestMailResourceFacade facade(resourceIdentifier, resourceAccess); 97 TestMailResourceFacade facade(resourceIdentifier, resourceAccess);
98 98
@@ -100,13 +100,9 @@ class MailQueryBenchmark : public QObject
100 ret.first.exec().waitForFinished(); 100 ret.first.exec().waitForFinished();
101 auto emitter = ret.second; 101 auto emitter = ret.second;
102 QList<Sink::ApplicationDomain::Mail::Ptr> list; 102 QList<Sink::ApplicationDomain::Mail::Ptr> list;
103 emitter->onAdded([&list](const Sink::ApplicationDomain::Mail::Ptr &mail) { 103 emitter->onAdded([&list](const Sink::ApplicationDomain::Mail::Ptr &mail) { list << mail; });
104 list << mail;
105 });
106 bool done = false; 104 bool done = false;
107 emitter->onInitialResultSetComplete([&done](const Sink::ApplicationDomain::Mail::Ptr &mail) { 105 emitter->onInitialResultSetComplete([&done](const Sink::ApplicationDomain::Mail::Ptr &mail) { done = true; });
108 done = true;
109 });
110 emitter->fetch(Sink::ApplicationDomain::Mail::Ptr()); 106 emitter->fetch(Sink::ApplicationDomain::Mail::Ptr());
111 QTRY_VERIFY(done); 107 QTRY_VERIFY(done);
112 QCOMPARE(list.size(), query.limit); 108 QCOMPARE(list.size(), query.limit);
@@ -115,32 +111,32 @@ class MailQueryBenchmark : public QObject
115 111
116 const auto finalRss = getCurrentRSS(); 112 const auto finalRss = getCurrentRSS();
117 const auto rssGrowth = finalRss - startingRss; 113 const auto rssGrowth = finalRss - startingRss;
118 //Since the database is memory mapped it is attributted to the resident set size. 114 // Since the database is memory mapped it is attributted to the resident set size.
119 const auto rssWithoutDb = finalRss - Sink::Storage(Sink::storageLocation(), resourceIdentifier, Sink::Storage::ReadWrite).diskUsage(); 115 const auto rssWithoutDb = finalRss - Sink::Storage(Sink::storageLocation(), resourceIdentifier, Sink::Storage::ReadWrite).diskUsage();
120 const auto peakRss = getPeakRSS(); 116 const auto peakRss = getPeakRSS();
121 //How much peak deviates from final rss in percent (should be around 0) 117 // How much peak deviates from final rss in percent (should be around 0)
122 const auto percentageRssError = static_cast<double>(peakRss - finalRss)*100.0/static_cast<double>(finalRss); 118 const auto percentageRssError = static_cast<double>(peakRss - finalRss) * 100.0 / static_cast<double>(finalRss);
123 auto rssGrowthPerEntity = rssGrowth/count; 119 auto rssGrowthPerEntity = rssGrowth / count;
124 120
125 std::cout << "Loaded " << list.size() << " results." << std::endl; 121 std::cout << "Loaded " << list.size() << " results." << std::endl;
126 std::cout << "The query took [ms]: " << elapsed << std::endl; 122 std::cout << "The query took [ms]: " << elapsed << std::endl;
127 std::cout << "Current Rss usage [kb]: " << finalRss/1024 << std::endl; 123 std::cout << "Current Rss usage [kb]: " << finalRss / 1024 << std::endl;
128 std::cout << "Peak Rss usage [kb]: " << peakRss/1024 << std::endl; 124 std::cout << "Peak Rss usage [kb]: " << peakRss / 1024 << std::endl;
129 std::cout << "Rss growth [kb]: " << rssGrowth/1024 << std::endl; 125 std::cout << "Rss growth [kb]: " << rssGrowth / 1024 << std::endl;
130 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl; 126 std::cout << "Rss growth per entity [byte]: " << rssGrowthPerEntity << std::endl;
131 std::cout << "Rss without db [kb]: " << rssWithoutDb/1024 << std::endl; 127 std::cout << "Rss without db [kb]: " << rssWithoutDb / 1024 << std::endl;
132 std::cout << "Percentage error: " << percentageRssError << std::endl; 128 std::cout << "Percentage error: " << percentageRssError << std::endl;
133 129
134 HAWD::Dataset dataset("mail_query", mHawdState); 130 HAWD::Dataset dataset("mail_query", mHawdState);
135 HAWD::Dataset::Row row = dataset.row(); 131 HAWD::Dataset::Row row = dataset.row();
136 row.setValue("rows", list.size()); 132 row.setValue("rows", list.size());
137 row.setValue("queryResultPerMs", (qreal)list.size()/elapsed); 133 row.setValue("queryResultPerMs", (qreal)list.size() / elapsed);
138 dataset.insertRow(row); 134 dataset.insertRow(row);
139 HAWD::Formatter::print(dataset); 135 HAWD::Formatter::print(dataset);
140 136
141 QVERIFY(percentageRssError < 10); 137 QVERIFY(percentageRssError < 10);
142 //TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase, 138 // TODO This is much more than it should it seems, although adding the attachment results in pretty exactly a 1k increase,
143 //so it doesn't look like that memory is being duplicated. 139 // so it doesn't look like that memory is being duplicated.
144 QVERIFY(rssGrowthPerEntity < 3300); 140 QVERIFY(rssGrowthPerEntity < 3300);
145 141
146 // Print memory layout, RSS is what is in memory 142 // Print memory layout, RSS is what is in memory
@@ -159,7 +155,9 @@ private slots:
159 { 155 {
160 Sink::Query query; 156 Sink::Query query;
161 query.liveQuery = false; 157 query.liveQuery = false;
162 query.requestedProperties << "uid" << "subject" << "date"; 158 query.requestedProperties << "uid"
159 << "subject"
160 << "date";
163 query.sortProperty = "date"; 161 query.sortProperty = "date";
164 query.propertyFilter.insert("folder", "folder1"); 162 query.propertyFilter.insert("folder", "folder1");
165 query.limit = 1000; 163 query.limit = 1000;
@@ -167,7 +165,6 @@ private slots:
167 populateDatabase(50000); 165 populateDatabase(50000);
168 testLoad(query, 50000); 166 testLoad(query, 50000);
169 } 167 }
170
171}; 168};
172 169
173QTEST_MAIN(MailQueryBenchmark) 170QTEST_MAIN(MailQueryBenchmark)
diff --git a/tests/messagequeuetest.cpp b/tests/messagequeuetest.cpp
index 06a4ae6..484ff86 100644
--- a/tests/messagequeuetest.cpp
+++ b/tests/messagequeuetest.cpp
@@ -45,12 +45,7 @@ private slots:
45 MessageQueue queue(Sink::Store::storageLocation(), "org.kde.dummy.testqueue"); 45 MessageQueue queue(Sink::Store::storageLocation(), "org.kde.dummy.testqueue");
46 bool gotValue = false; 46 bool gotValue = false;
47 bool gotError = false; 47 bool gotError = false;
48 queue.dequeue([&](void *ptr, int size, std::function<void(bool success)> callback) { 48 queue.dequeue([&](void *ptr, int size, std::function<void(bool success)> callback) { gotValue = true; }, [&](const MessageQueue::Error &error) { gotError = true; });
49 gotValue = true;
50 },
51 [&](const MessageQueue::Error &error) {
52 gotError = true;
53 });
54 QVERIFY(!gotValue); 49 QVERIFY(!gotValue);
55 QVERIFY(!gotError); 50 QVERIFY(!gotError);
56 } 51 }
@@ -69,9 +64,7 @@ private slots:
69 QSignalSpy spy(&queue, SIGNAL(drained())); 64 QSignalSpy spy(&queue, SIGNAL(drained()));
70 queue.enqueue("value1"); 65 queue.enqueue("value1");
71 66
72 queue.dequeue([](void *ptr, int size, std::function<void(bool success)> callback) { 67 queue.dequeue([](void *ptr, int size, std::function<void(bool success)> callback) { callback(true); }, [](const MessageQueue::Error &error) {});
73 callback(true);
74 }, [](const MessageQueue::Error &error) {});
75 QCOMPARE(spy.size(), 1); 68 QCOMPARE(spy.size(), 1);
76 } 69 }
77 70
@@ -91,15 +84,14 @@ private slots:
91 const auto expected = values.dequeue(); 84 const auto expected = values.dequeue();
92 bool gotValue = false; 85 bool gotValue = false;
93 bool gotError = false; 86 bool gotError = false;
94 queue.dequeue([&](void *ptr, int size, std::function<void(bool success)> callback) { 87 queue.dequeue(
95 if (QByteArray(static_cast<char*>(ptr), size) == expected) { 88 [&](void *ptr, int size, std::function<void(bool success)> callback) {
96 gotValue = true; 89 if (QByteArray(static_cast<char *>(ptr), size) == expected) {
97 } 90 gotValue = true;
98 callback(true); 91 }
99 }, 92 callback(true);
100 [&](const MessageQueue::Error &error) { 93 },
101 gotError = true; 94 [&](const MessageQueue::Error &error) { gotError = true; });
102 });
103 QVERIFY(gotValue); 95 QVERIFY(gotValue);
104 QVERIFY(!gotError); 96 QVERIFY(!gotError);
105 } 97 }
@@ -123,22 +115,21 @@ private slots:
123 bool gotValue = false; 115 bool gotValue = false;
124 bool gotError = false; 116 bool gotError = false;
125 117
126 queue.dequeue([&](void *ptr, int size, std::function<void(bool success)> callback) { 118 queue.dequeue(
127 if (QByteArray(static_cast<char*>(ptr), size) == expected) { 119 [&](void *ptr, int size, std::function<void(bool success)> callback) {
128 gotValue = true; 120 if (QByteArray(static_cast<char *>(ptr), size) == expected) {
129 } 121 gotValue = true;
130 auto timer = new QTimer(); 122 }
131 timer->setSingleShot(true); 123 auto timer = new QTimer();
132 QObject::connect(timer, &QTimer::timeout, [timer, callback, &eventLoop]() { 124 timer->setSingleShot(true);
133 delete timer; 125 QObject::connect(timer, &QTimer::timeout, [timer, callback, &eventLoop]() {
134 callback(true); 126 delete timer;
135 eventLoop.exit(); 127 callback(true);
136 }); 128 eventLoop.exit();
137 timer->start(0); 129 });
138 }, 130 timer->start(0);
139 [&](const MessageQueue::Error &error) { 131 },
140 gotError = true; 132 [&](const MessageQueue::Error &error) { gotError = true; });
141 });
142 eventLoop.exec(); 133 eventLoop.exec();
143 QVERIFY(gotValue); 134 QVERIFY(gotValue);
144 QVERIFY(!gotError); 135 QVERIFY(!gotError);
@@ -155,13 +146,12 @@ private slots:
155 queue.enqueue("value1"); 146 queue.enqueue("value1");
156 147
157 bool gotError = false; 148 bool gotError = false;
158 queue.dequeue([&](void *ptr, int size, std::function<void(bool success)> callback) { 149 queue.dequeue(
159 queue.enqueue("value3"); 150 [&](void *ptr, int size, std::function<void(bool success)> callback) {
160 callback(true); 151 queue.enqueue("value3");
161 }, 152 callback(true);
162 [&](const MessageQueue::Error &error) { 153 },
163 gotError = true; 154 [&](const MessageQueue::Error &error) { gotError = true; });
164 });
165 QVERIFY(!gotError); 155 QVERIFY(!gotError);
166 } 156 }
167 157
@@ -174,15 +164,15 @@ private slots:
174 164
175 int count = 0; 165 int count = 0;
176 queue.dequeueBatch(2, [&count](const QByteArray &data) { 166 queue.dequeueBatch(2, [&count](const QByteArray &data) {
177 count++; 167 count++;
178 return KAsync::null<void>(); 168 return KAsync::null<void>();
179 }).exec().waitForFinished(); 169 }).exec().waitForFinished();
180 QCOMPARE(count, 2); 170 QCOMPARE(count, 2);
181 171
182 queue.dequeueBatch(1, [&count](const QByteArray &data) { 172 queue.dequeueBatch(1, [&count](const QByteArray &data) {
183 count++; 173 count++;
184 return KAsync::null<void>(); 174 return KAsync::null<void>();
185 }).exec().waitForFinished(); 175 }).exec().waitForFinished();
186 QCOMPARE(count, 3); 176 QCOMPARE(count, 3);
187 } 177 }
188 178
@@ -203,7 +193,6 @@ private slots:
203 QVERIFY(!queue.isEmpty()); 193 QVERIFY(!queue.isEmpty());
204 QCOMPARE(spy.count(), 1); 194 QCOMPARE(spy.count(), 1);
205 } 195 }
206
207}; 196};
208 197
209QTEST_MAIN(MessageQueueTest) 198QTEST_MAIN(MessageQueueTest)
diff --git a/tests/modelinteractivitytest.cpp b/tests/modelinteractivitytest.cpp
index ad23e0f..d0a0920 100644
--- a/tests/modelinteractivitytest.cpp
+++ b/tests/modelinteractivitytest.cpp
@@ -16,20 +16,23 @@ static int blockingTime;
16class TimeMeasuringApplication : public QCoreApplication 16class TimeMeasuringApplication : public QCoreApplication
17{ 17{
18 QElapsedTimer t; 18 QElapsedTimer t;
19
19public: 20public:
20 TimeMeasuringApplication(int& argc, char ** argv) : QCoreApplication(argc, argv) { } 21 TimeMeasuringApplication(int &argc, char **argv) : QCoreApplication(argc, argv)
21 virtual ~TimeMeasuringApplication() { } 22 {
23 }
24 virtual ~TimeMeasuringApplication()
25 {
26 }
22 27
23 virtual bool notify(QObject* receiver, QEvent* event) 28 virtual bool notify(QObject *receiver, QEvent *event)
24 { 29 {
25 t.start(); 30 t.start();
26 const bool ret = QCoreApplication::notify(receiver, event); 31 const bool ret = QCoreApplication::notify(receiver, event);
27 if(t.elapsed() > 1) 32 if (t.elapsed() > 1)
28 std::cout << QString("processing event type %1 for object %2 took %3ms") 33 std::cout
29 .arg((int)event->type()) 34 << QString("processing event type %1 for object %2 took %3ms").arg((int)event->type()).arg("" /* receiver->objectName().toLocal8Bit().data()*/).arg((int)t.elapsed()).toStdString()
30 .arg(""/* receiver->objectName().toLocal8Bit().data()*/) 35 << std::endl;
31 .arg((int)t.elapsed())
32 .toStdString() << std::endl;
33 blockingTime += t.elapsed(); 36 blockingTime += t.elapsed();
34 return ret; 37 return ret;
35 } 38 }
@@ -62,7 +65,7 @@ private slots:
62 65
63 void testSingle() 66 void testSingle()
64 { 67 {
65 //Setup 68 // Setup
66 { 69 {
67 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1"); 70 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
68 for (int i = 0; i < 1000; i++) { 71 for (int i = 0; i < 1000; i++) {
@@ -76,13 +79,13 @@ private slots:
76 79
77 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 80 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
78 81
79 //Test 82 // Test
80 QTime time; 83 QTime time;
81 time.start(); 84 time.start();
82 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 85 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
83 blockingTime += time.elapsed(); 86 blockingTime += time.elapsed();
84 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 87 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
85 //Never block longer than 10 ms 88 // Never block longer than 10 ms
86 QVERIFY2(blockingTime < 10, QString("Total blocking time: %1").arg(blockingTime).toLatin1().data()); 89 QVERIFY2(blockingTime < 10, QString("Total blocking time: %1").arg(blockingTime).toLatin1().data());
87 } 90 }
88}; 91};
diff --git a/tests/pipelinebenchmark.cpp b/tests/pipelinebenchmark.cpp
index 5743830..0133a6c 100644
--- a/tests/pipelinebenchmark.cpp
+++ b/tests/pipelinebenchmark.cpp
@@ -54,7 +54,8 @@
54// } 54// }
55// } 55// }
56// 56//
57// void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 57// void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity,
58// Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
58// { 59// {
59// } 60// }
60// 61//
@@ -66,7 +67,7 @@
66 67
67/** 68/**
68 * Benchmark pipeline processing speed. 69 * Benchmark pipeline processing speed.
69 * 70 *
70 * This benchmark especially highlights: 71 * This benchmark especially highlights:
71 * * Cost of an index in speed and size 72 * * Cost of an index in speed and size
72 */ 73 */
@@ -77,7 +78,7 @@ class PipelineBenchmark : public QObject
77 QByteArray resourceIdentifier; 78 QByteArray resourceIdentifier;
78 HAWD::State mHawdState; 79 HAWD::State mHawdState;
79 80
80 void populateDatabase(int count, const QVector<Sink::Preprocessor*> &preprocessors) 81 void populateDatabase(int count, const QVector<Sink::Preprocessor *> &preprocessors)
81 { 82 {
82 TestResource::removeFromDisk(resourceIdentifier); 83 TestResource::removeFromDisk(resourceIdentifier);
83 84
@@ -112,18 +113,17 @@ class PipelineBenchmark : public QObject
112 // Print memory layout, RSS is what is in memory 113 // Print memory layout, RSS is what is in memory
113 // std::system("exec pmap -x \"$PPID\""); 114 // std::system("exec pmap -x \"$PPID\"");
114 // 115 //
115 std::cout << "Size: " << Sink::Storage(Sink::storageLocation(), resourceIdentifier, Sink::Storage::ReadOnly).diskUsage()/1024 << " [kb]" << std::endl; 116 std::cout << "Size: " << Sink::Storage(Sink::storageLocation(), resourceIdentifier, Sink::Storage::ReadOnly).diskUsage() / 1024 << " [kb]" << std::endl;
116 std::cout << "Time: " << allProcessedTime << " [ms]" << std::endl; 117 std::cout << "Time: " << allProcessedTime << " [ms]" << std::endl;
117 118
118 HAWD::Dataset dataset("pipeline", mHawdState); 119 HAWD::Dataset dataset("pipeline", mHawdState);
119 HAWD::Dataset::Row row = dataset.row(); 120 HAWD::Dataset::Row row = dataset.row();
120 121
121 row.setValue("rows", count); 122 row.setValue("rows", count);
122 row.setValue("append", (qreal)count/appendTime); 123 row.setValue("append", (qreal)count / appendTime);
123 row.setValue("total", (qreal)count/allProcessedTime); 124 row.setValue("total", (qreal)count / allProcessedTime);
124 dataset.insertRow(row); 125 dataset.insertRow(row);
125 HAWD::Formatter::print(dataset); 126 HAWD::Formatter::print(dataset);
126
127 } 127 }
128 128
129private slots: 129private slots:
@@ -136,15 +136,14 @@ private slots:
136 136
137 void testWithoutIndex() 137 void testWithoutIndex()
138 { 138 {
139 populateDatabase(10000, QVector<Sink::Preprocessor*>()); 139 populateDatabase(10000, QVector<Sink::Preprocessor *>());
140 } 140 }
141 141
142 void testWithIndex() 142 void testWithIndex()
143 { 143 {
144 auto indexer = QSharedPointer<DefaultIndexUpdater<Sink::ApplicationDomain::Mail> >::create(); 144 auto indexer = QSharedPointer<DefaultIndexUpdater<Sink::ApplicationDomain::Mail>>::create();
145 populateDatabase(10000, QVector<Sink::Preprocessor*>() << indexer.data()); 145 populateDatabase(10000, QVector<Sink::Preprocessor *>() << indexer.data());
146 } 146 }
147
148}; 147};
149 148
150QTEST_MAIN(PipelineBenchmark) 149QTEST_MAIN(PipelineBenchmark)
diff --git a/tests/pipelinetest.cpp b/tests/pipelinetest.cpp
index 92b7554..cdd260d 100644
--- a/tests/pipelinetest.cpp
+++ b/tests/pipelinetest.cpp
@@ -143,7 +143,8 @@ QByteArray deleteEntityCommand(const QByteArray &uid, qint64 revision)
143 return command; 143 return command;
144} 144}
145 145
146class TestProcessor : public Sink::Preprocessor { 146class TestProcessor : public Sink::Preprocessor
147{
147public: 148public:
148 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 149 void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
149 { 150 {
@@ -151,7 +152,8 @@ public:
151 newRevisions << revision; 152 newRevisions << revision;
152 } 153 }
153 154
154 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE 155 void modifiedEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity,
156 Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE
155 { 157 {
156 modifiedUids << uid; 158 modifiedUids << uid;
157 modifiedRevisions << revision; 159 modifiedRevisions << revision;
@@ -214,42 +216,42 @@ private slots:
214 auto adaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create(); 216 auto adaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create();
215 pipeline.setAdaptorFactory("event", adaptorFactory); 217 pipeline.setAdaptorFactory("event", adaptorFactory);
216 218
217 //Create the initial revision 219 // Create the initial revision
218 pipeline.startTransaction(); 220 pipeline.startTransaction();
219 pipeline.newEntity(command.constData(), command.size()); 221 pipeline.newEntity(command.constData(), command.size());
220 pipeline.commit(); 222 pipeline.commit();
221 223
222 //Get uid of written entity 224 // Get uid of written entity
223 auto keys = getKeys("org.kde.pipelinetest.instance1", "event.main"); 225 auto keys = getKeys("org.kde.pipelinetest.instance1", "event.main");
224 QCOMPARE(keys.size(), 1); 226 QCOMPARE(keys.size(), 1);
225 const auto key = keys.first(); 227 const auto key = keys.first();
226 const auto uid = Sink::Storage::uidFromKey(key); 228 const auto uid = Sink::Storage::uidFromKey(key);
227 229
228 //Execute the modification 230 // Execute the modification
229 entityFbb.Clear(); 231 entityFbb.Clear();
230 auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 1); 232 auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 1);
231 pipeline.startTransaction(); 233 pipeline.startTransaction();
232 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size()); 234 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size());
233 pipeline.commit(); 235 pipeline.commit();
234 236
235 //Ensure we've got the new revision with the modification 237 // Ensure we've got the new revision with the modification
236 auto buffer = getEntity("org.kde.pipelinetest.instance1", "event.main", Sink::Storage::assembleKey(uid, 2)); 238 auto buffer = getEntity("org.kde.pipelinetest.instance1", "event.main", Sink::Storage::assembleKey(uid, 2));
237 QVERIFY(!buffer.isEmpty()); 239 QVERIFY(!buffer.isEmpty());
238 Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); 240 Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size());
239 auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity()); 241 auto adaptor = adaptorFactory->createAdaptor(entityBuffer.entity());
240 QVERIFY2(adaptor->getProperty("summary").toString() == QString("summary2"), "The modification isn't applied."); 242 QVERIFY2(adaptor->getProperty("summary").toString() == QString("summary2"), "The modification isn't applied.");
241 //Ensure we didn't modify anything else 243 // Ensure we didn't modify anything else
242 QVERIFY2(adaptor->getProperty("description").toString() == QString("description"), "The modification has sideeffects."); 244 QVERIFY2(adaptor->getProperty("description").toString() == QString("description"), "The modification has sideeffects.");
243 245
244 //Both revisions are in the store at this point 246 // Both revisions are in the store at this point
245 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 2); 247 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 2);
246 248
247 //Cleanup old revisions 249 // Cleanup old revisions
248 pipeline.startTransaction(); 250 pipeline.startTransaction();
249 pipeline.cleanupRevision(2); 251 pipeline.cleanupRevision(2);
250 pipeline.commit(); 252 pipeline.commit();
251 253
252 //And now only the latest revision is left 254 // And now only the latest revision is left
253 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 1); 255 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 1);
254 } 256 }
255 257
@@ -263,18 +265,18 @@ private slots:
263 auto adaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create(); 265 auto adaptorFactory = QSharedPointer<TestEventAdaptorFactory>::create();
264 pipeline.setAdaptorFactory("event", adaptorFactory); 266 pipeline.setAdaptorFactory("event", adaptorFactory);
265 267
266 //Create the initial revision 268 // Create the initial revision
267 pipeline.startTransaction(); 269 pipeline.startTransaction();
268 pipeline.newEntity(command.constData(), command.size()); 270 pipeline.newEntity(command.constData(), command.size());
269 pipeline.commit(); 271 pipeline.commit();
270 272
271 //Get uid of written entity 273 // Get uid of written entity
272 auto keys = getKeys("org.kde.pipelinetest.instance1", "event.main"); 274 auto keys = getKeys("org.kde.pipelinetest.instance1", "event.main");
273 QCOMPARE(keys.size(), 1); 275 QCOMPARE(keys.size(), 1);
274 const auto uid = Sink::Storage::uidFromKey(keys.first()); 276 const auto uid = Sink::Storage::uidFromKey(keys.first());
275 277
276 278
277 //Create another operation inbetween 279 // Create another operation inbetween
278 { 280 {
279 entityFbb.Clear(); 281 entityFbb.Clear();
280 auto command = createEntityCommand(createEvent(entityFbb)); 282 auto command = createEntityCommand(createEvent(entityFbb));
@@ -283,14 +285,14 @@ private slots:
283 pipeline.commit(); 285 pipeline.commit();
284 } 286 }
285 287
286 //Execute the modification on revision 2 288 // Execute the modification on revision 2
287 entityFbb.Clear(); 289 entityFbb.Clear();
288 auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 2); 290 auto modifyCommand = modifyEntityCommand(createEvent(entityFbb, "summary2"), uid, 2);
289 pipeline.startTransaction(); 291 pipeline.startTransaction();
290 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size()); 292 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size());
291 pipeline.commit(); 293 pipeline.commit();
292 294
293 //Ensure we've got the new revision with the modification 295 // Ensure we've got the new revision with the modification
294 auto buffer = getEntity("org.kde.pipelinetest.instance1", "event.main", Sink::Storage::assembleKey(uid, 3)); 296 auto buffer = getEntity("org.kde.pipelinetest.instance1", "event.main", Sink::Storage::assembleKey(uid, 3));
295 QVERIFY(!buffer.isEmpty()); 297 QVERIFY(!buffer.isEmpty());
296 Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size()); 298 Sink::EntityBuffer entityBuffer(buffer.data(), buffer.size());
@@ -305,7 +307,7 @@ private slots:
305 Sink::Pipeline pipeline("org.kde.pipelinetest.instance1"); 307 Sink::Pipeline pipeline("org.kde.pipelinetest.instance1");
306 pipeline.setAdaptorFactory("event", QSharedPointer<TestEventAdaptorFactory>::create()); 308 pipeline.setAdaptorFactory("event", QSharedPointer<TestEventAdaptorFactory>::create());
307 309
308 //Create the initial revision 310 // Create the initial revision
309 pipeline.startTransaction(); 311 pipeline.startTransaction();
310 pipeline.newEntity(command.constData(), command.size()); 312 pipeline.newEntity(command.constData(), command.size());
311 pipeline.commit(); 313 pipeline.commit();
@@ -315,21 +317,21 @@ private slots:
315 317
316 const auto uid = Sink::Storage::uidFromKey(result.first()); 318 const auto uid = Sink::Storage::uidFromKey(result.first());
317 319
318 //Delete entity 320 // Delete entity
319 auto deleteCommand = deleteEntityCommand(uid, 1); 321 auto deleteCommand = deleteEntityCommand(uid, 1);
320 pipeline.startTransaction(); 322 pipeline.startTransaction();
321 pipeline.deletedEntity(deleteCommand.constData(), deleteCommand.size()); 323 pipeline.deletedEntity(deleteCommand.constData(), deleteCommand.size());
322 pipeline.commit(); 324 pipeline.commit();
323 325
324 //We have a new revision that indicates the deletion 326 // We have a new revision that indicates the deletion
325 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 2); 327 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 2);
326 328
327 //Cleanup old revisions 329 // Cleanup old revisions
328 pipeline.startTransaction(); 330 pipeline.startTransaction();
329 pipeline.cleanupRevision(2); 331 pipeline.cleanupRevision(2);
330 pipeline.commit(); 332 pipeline.commit();
331 333
332 //And all revisions are gone 334 // And all revisions are gone
333 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 0); 335 QCOMPARE(getKeys("org.kde.pipelinetest.instance1", "event.main").size(), 0);
334 } 336 }
335 337
@@ -340,17 +342,17 @@ private slots:
340 TestProcessor testProcessor; 342 TestProcessor testProcessor;
341 343
342 Sink::Pipeline pipeline("org.kde.pipelinetest.instance1"); 344 Sink::Pipeline pipeline("org.kde.pipelinetest.instance1");
343 pipeline.setPreprocessors("event", QVector<Sink::Preprocessor*>() << &testProcessor); 345 pipeline.setPreprocessors("event", QVector<Sink::Preprocessor *>() << &testProcessor);
344 pipeline.startTransaction(); 346 pipeline.startTransaction();
345 pipeline.setAdaptorFactory("event", QSharedPointer<TestEventAdaptorFactory>::create()); 347 pipeline.setAdaptorFactory("event", QSharedPointer<TestEventAdaptorFactory>::create());
346 348
347 //Actual test 349 // Actual test
348 { 350 {
349 auto command = createEntityCommand(createEvent(entityFbb)); 351 auto command = createEntityCommand(createEvent(entityFbb));
350 pipeline.newEntity(command.constData(), command.size()); 352 pipeline.newEntity(command.constData(), command.size());
351 QCOMPARE(testProcessor.newUids.size(), 1); 353 QCOMPARE(testProcessor.newUids.size(), 1);
352 QCOMPARE(testProcessor.newRevisions.size(), 1); 354 QCOMPARE(testProcessor.newRevisions.size(), 1);
353 //Key doesn't contain revision and is just the uid 355 // Key doesn't contain revision and is just the uid
354 QCOMPARE(testProcessor.newUids.at(0), Sink::Storage::uidFromKey(testProcessor.newUids.at(0))); 356 QCOMPARE(testProcessor.newUids.at(0), Sink::Storage::uidFromKey(testProcessor.newUids.at(0)));
355 } 357 }
356 pipeline.commit(); 358 pipeline.commit();
@@ -364,7 +366,7 @@ private slots:
364 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size()); 366 pipeline.modifiedEntity(modifyCommand.constData(), modifyCommand.size());
365 QCOMPARE(testProcessor.modifiedUids.size(), 1); 367 QCOMPARE(testProcessor.modifiedUids.size(), 1);
366 QCOMPARE(testProcessor.modifiedRevisions.size(), 1); 368 QCOMPARE(testProcessor.modifiedRevisions.size(), 1);
367 //Key doesn't contain revision and is just the uid 369 // Key doesn't contain revision and is just the uid
368 QCOMPARE(testProcessor.modifiedUids.at(0), Sink::Storage::uidFromKey(testProcessor.modifiedUids.at(0))); 370 QCOMPARE(testProcessor.modifiedUids.at(0), Sink::Storage::uidFromKey(testProcessor.modifiedUids.at(0)));
369 } 371 }
370 pipeline.commit(); 372 pipeline.commit();
@@ -376,7 +378,7 @@ private slots:
376 QCOMPARE(testProcessor.deletedUids.size(), 1); 378 QCOMPARE(testProcessor.deletedUids.size(), 1);
377 QCOMPARE(testProcessor.deletedUids.size(), 1); 379 QCOMPARE(testProcessor.deletedUids.size(), 1);
378 QCOMPARE(testProcessor.deletedSummaries.size(), 1); 380 QCOMPARE(testProcessor.deletedSummaries.size(), 1);
379 //Key doesn't contain revision and is just the uid 381 // Key doesn't contain revision and is just the uid
380 QCOMPARE(testProcessor.deletedUids.at(0), Sink::Storage::uidFromKey(testProcessor.deletedUids.at(0))); 382 QCOMPARE(testProcessor.deletedUids.at(0), Sink::Storage::uidFromKey(testProcessor.deletedUids.at(0)));
381 QCOMPARE(testProcessor.deletedSummaries.at(0), QByteArray("summary2")); 383 QCOMPARE(testProcessor.deletedSummaries.at(0), QByteArray("summary2"));
382 } 384 }
diff --git a/tests/querytest.cpp b/tests/querytest.cpp
index 2531c25..7b9129e 100644
--- a/tests/querytest.cpp
+++ b/tests/querytest.cpp
@@ -42,12 +42,12 @@ private slots:
42 42
43 void testNoResources() 43 void testNoResources()
44 { 44 {
45 //Test 45 // Test
46 Sink::Query query; 46 Sink::Query query;
47 query.resources << "foobar"; 47 query.resources << "foobar";
48 query.liveQuery = true; 48 query.liveQuery = true;
49 49
50 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 50 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
51 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 51 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
52 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 52 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
53 QCOMPARE(model->rowCount(), 0); 53 QCOMPARE(model->rowCount(), 0);
@@ -56,39 +56,39 @@ private slots:
56 56
57 void testSingle() 57 void testSingle()
58 { 58 {
59 //Setup 59 // Setup
60 { 60 {
61 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1"); 61 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
62 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); 62 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished();
63 } 63 }
64 64
65 //Test 65 // Test
66 Sink::Query query; 66 Sink::Query query;
67 query.resources << "org.kde.dummy.instance1"; 67 query.resources << "org.kde.dummy.instance1";
68 query.liveQuery = true; 68 query.liveQuery = true;
69 69
70 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 70 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
71 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 71 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
72 QTRY_COMPARE(model->rowCount(), 1); 72 QTRY_COMPARE(model->rowCount(), 1);
73 } 73 }
74 74
75 void testSingleWithDelay() 75 void testSingleWithDelay()
76 { 76 {
77 //Setup 77 // Setup
78 { 78 {
79 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1"); 79 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
80 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); 80 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished();
81 } 81 }
82 82
83 //Test 83 // Test
84 Sink::Query query; 84 Sink::Query query;
85 query.resources << "org.kde.dummy.instance1"; 85 query.resources << "org.kde.dummy.instance1";
86 query.liveQuery = false; 86 query.liveQuery = false;
87 87
88 //Ensure all local data is processed 88 // Ensure all local data is processed
89 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 89 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
90 90
91 //We fetch after the data is available and don't rely on the live query mechanism to deliver the actual data 91 // We fetch after the data is available and don't rely on the live query mechanism to deliver the actual data
92 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 92 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
93 93
94 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 94 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
@@ -98,7 +98,7 @@ private slots:
98 void testById() 98 void testById()
99 { 99 {
100 QByteArray id; 100 QByteArray id;
101 //Setup 101 // Setup
102 { 102 {
103 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1"); 103 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
104 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); 104 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished();
@@ -107,17 +107,17 @@ private slots:
107 Sink::Query query; 107 Sink::Query query;
108 query.resources << "org.kde.dummy.instance1"; 108 query.resources << "org.kde.dummy.instance1";
109 109
110 //Ensure all local data is processed 110 // Ensure all local data is processed
111 Sink::Store::synchronize(query).exec().waitForFinished(); 111 Sink::Store::synchronize(query).exec().waitForFinished();
112 112
113 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 113 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
114 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 114 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
115 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 115 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
116 QVERIFY(model->rowCount() >= 1); 116 QVERIFY(model->rowCount() >= 1);
117 id = model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->identifier(); 117 id = model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->identifier();
118 } 118 }
119 119
120 //Test 120 // Test
121 Sink::Query query; 121 Sink::Query query;
122 query.resources << "org.kde.dummy.instance1"; 122 query.resources << "org.kde.dummy.instance1";
123 query.ids << id; 123 query.ids << id;
@@ -128,18 +128,18 @@ private slots:
128 128
129 void testFolder() 129 void testFolder()
130 { 130 {
131 //Setup 131 // Setup
132 { 132 {
133 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1"); 133 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1");
134 Sink::Store::create<Sink::ApplicationDomain::Folder>(folder).exec().waitForFinished(); 134 Sink::Store::create<Sink::ApplicationDomain::Folder>(folder).exec().waitForFinished();
135 } 135 }
136 136
137 //Test 137 // Test
138 Sink::Query query; 138 Sink::Query query;
139 query.resources << "org.kde.dummy.instance1"; 139 query.resources << "org.kde.dummy.instance1";
140 query.liveQuery = true; 140 query.liveQuery = true;
141 141
142 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 142 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
143 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); 143 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
144 QTRY_COMPARE(model->rowCount(), 1); 144 QTRY_COMPARE(model->rowCount(), 1);
145 auto folderEntity = model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Folder::Ptr>(); 145 auto folderEntity = model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Folder::Ptr>();
@@ -148,7 +148,7 @@ private slots:
148 148
149 void testFolderTree() 149 void testFolderTree()
150 { 150 {
151 //Setup 151 // Setup
152 { 152 {
153 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1"); 153 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1");
154 Sink::Store::create<Sink::ApplicationDomain::Folder>(folder).exec().waitForFinished(); 154 Sink::Store::create<Sink::ApplicationDomain::Folder>(folder).exec().waitForFinished();
@@ -156,7 +156,7 @@ private slots:
156 Sink::Query query; 156 Sink::Query query;
157 query.resources << "org.kde.dummy.instance1"; 157 query.resources << "org.kde.dummy.instance1";
158 158
159 //Ensure all local data is processed 159 // Ensure all local data is processed
160 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 160 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
161 161
162 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); 162 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
@@ -171,15 +171,15 @@ private slots:
171 Sink::Store::create<Sink::ApplicationDomain::Folder>(subfolder).exec().waitForFinished(); 171 Sink::Store::create<Sink::ApplicationDomain::Folder>(subfolder).exec().waitForFinished();
172 } 172 }
173 173
174 //Test 174 // Test
175 Sink::Query query; 175 Sink::Query query;
176 query.resources << "org.kde.dummy.instance1"; 176 query.resources << "org.kde.dummy.instance1";
177 query.parentProperty = "parent"; 177 query.parentProperty = "parent";
178 178
179 //Ensure all local data is processed 179 // Ensure all local data is processed
180 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 180 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
181 181
182 //We fetch after the data is available and don't rely on the live query mechanism to deliver the actual data 182 // We fetch after the data is available and don't rely on the live query mechanism to deliver the actual data
183 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); 183 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
184 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 184 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
185 QCOMPARE(model->rowCount(), 1); 185 QCOMPARE(model->rowCount(), 1);
@@ -190,7 +190,7 @@ private slots:
190 190
191 void testMailByUid() 191 void testMailByUid()
192 { 192 {
193 //Setup 193 // Setup
194 { 194 {
195 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1"); 195 Sink::ApplicationDomain::Mail mail("org.kde.dummy.instance1");
196 mail.setProperty("uid", "test1"); 196 mail.setProperty("uid", "test1");
@@ -198,16 +198,16 @@ private slots:
198 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); 198 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished();
199 } 199 }
200 200
201 //Test 201 // Test
202 Sink::Query query; 202 Sink::Query query;
203 query.resources << "org.kde.dummy.instance1"; 203 query.resources << "org.kde.dummy.instance1";
204 query.liveQuery = false; 204 query.liveQuery = false;
205 query.propertyFilter.insert("uid", "test1"); 205 query.propertyFilter.insert("uid", "test1");
206 206
207 //Ensure all local data is processed 207 // Ensure all local data is processed
208 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 208 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
209 209
210 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 210 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
211 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 211 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
212 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 212 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
213 QCOMPARE(model->rowCount(), 1); 213 QCOMPARE(model->rowCount(), 1);
@@ -215,7 +215,7 @@ private slots:
215 215
216 void testMailByFolder() 216 void testMailByFolder()
217 { 217 {
218 //Setup 218 // Setup
219 Sink::ApplicationDomain::Folder::Ptr folderEntity; 219 Sink::ApplicationDomain::Folder::Ptr folderEntity;
220 { 220 {
221 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1"); 221 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1");
@@ -224,7 +224,7 @@ private slots:
224 Sink::Query query; 224 Sink::Query query;
225 query.resources << "org.kde.dummy.instance1"; 225 query.resources << "org.kde.dummy.instance1";
226 226
227 //Ensure all local data is processed 227 // Ensure all local data is processed
228 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 228 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
229 229
230 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); 230 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
@@ -240,15 +240,15 @@ private slots:
240 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); 240 Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished();
241 } 241 }
242 242
243 //Test 243 // Test
244 Sink::Query query; 244 Sink::Query query;
245 query.resources << "org.kde.dummy.instance1"; 245 query.resources << "org.kde.dummy.instance1";
246 query.propertyFilter.insert("folder", folderEntity->identifier()); 246 query.propertyFilter.insert("folder", folderEntity->identifier());
247 247
248 //Ensure all local data is processed 248 // Ensure all local data is processed
249 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 249 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
250 250
251 //We fetch before the data is available and rely on the live query mechanism to deliver the actual data 251 // We fetch before the data is available and rely on the live query mechanism to deliver the actual data
252 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 252 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
253 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 253 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
254 QCOMPARE(model->rowCount(), 1); 254 QCOMPARE(model->rowCount(), 1);
@@ -256,7 +256,7 @@ private slots:
256 256
257 void testMailByFolderSortedByDate() 257 void testMailByFolderSortedByDate()
258 { 258 {
259 //Setup 259 // Setup
260 Sink::ApplicationDomain::Folder::Ptr folderEntity; 260 Sink::ApplicationDomain::Folder::Ptr folderEntity;
261 { 261 {
262 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1"); 262 Sink::ApplicationDomain::Folder folder("org.kde.dummy.instance1");
@@ -265,7 +265,7 @@ private slots:
265 Sink::Query query; 265 Sink::Query query;
266 query.resources << "org.kde.dummy.instance1"; 266 query.resources << "org.kde.dummy.instance1";
267 267
268 //Ensure all local data is processed 268 // Ensure all local data is processed
269 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 269 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
270 270
271 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query); 271 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
@@ -299,7 +299,7 @@ private slots:
299 } 299 }
300 } 300 }
301 301
302 //Test 302 // Test
303 Sink::Query query; 303 Sink::Query query;
304 query.resources << "org.kde.dummy.instance1"; 304 query.resources << "org.kde.dummy.instance1";
305 query.propertyFilter.insert("folder", folderEntity->identifier()); 305 query.propertyFilter.insert("folder", folderEntity->identifier());
@@ -307,19 +307,19 @@ private slots:
307 query.limit = 1; 307 query.limit = 1;
308 query.liveQuery = false; 308 query.liveQuery = false;
309 309
310 //Ensure all local data is processed 310 // Ensure all local data is processed
311 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished(); 311 Sink::ResourceControl::flushMessageQueue(query.resources).exec().waitForFinished();
312 312
313 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); 313 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query);
314 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 314 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
315 //The model is not sorted, but the limited set is sorted, so we can only test for the latest result. 315 // The model is not sorted, but the limited set is sorted, so we can only test for the latest result.
316 QCOMPARE(model->rowCount(), 1); 316 QCOMPARE(model->rowCount(), 1);
317 QCOMPARE(model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->getProperty("uid").toByteArray(), QByteArray("testLatest")); 317 QCOMPARE(model->index(0, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->getProperty("uid").toByteArray(), QByteArray("testLatest"));
318 318
319 model->fetchMore(QModelIndex()); 319 model->fetchMore(QModelIndex());
320 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); 320 QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool());
321 QCOMPARE(model->rowCount(), 2); 321 QCOMPARE(model->rowCount(), 2);
322 //We can't make any assumptions about the order of the indexes 322 // We can't make any assumptions about the order of the indexes
323 // QCOMPARE(model->index(1, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->getProperty("uid").toByteArray(), QByteArray("testSecond")); 323 // QCOMPARE(model->index(1, 0).data(Sink::Store::DomainObjectRole).value<Sink::ApplicationDomain::Mail::Ptr>()->getProperty("uid").toByteArray(), QByteArray("testSecond"));
324 } 324 }
325}; 325};
diff --git a/tests/resourcecommunicationtest.cpp b/tests/resourcecommunicationtest.cpp
index db8703e..2daf372 100644
--- a/tests/resourcecommunicationtest.cpp
+++ b/tests/resourcecommunicationtest.cpp
@@ -51,14 +51,13 @@ private slots:
51 int errors = 0; 51 int errors = 0;
52 for (int i = 0; i < count; i++) { 52 for (int i = 0; i < count; i++) {
53 auto result = resourceAccess.sendCommand(Sink::Commands::PingCommand) 53 auto result = resourceAccess.sendCommand(Sink::Commands::PingCommand)
54 .then<void>([&complete]() { 54 .then<void>([&complete]() { complete++; },
55 complete++; 55 [&errors, &complete](int error, const QString &msg) {
56 }, 56 qWarning() << msg;
57 [&errors, &complete](int error, const QString &msg) { 57 errors++;
58 qWarning() << msg; 58 complete++;
59 errors++; 59 })
60 complete++; 60 .exec();
61 }).exec();
62 } 61 }
63 QTRY_COMPARE(complete, count); 62 QTRY_COMPARE(complete, count);
64 QVERIFY(!errors); 63 QVERIFY(!errors);
@@ -77,17 +76,18 @@ private slots:
77 int errors = 0; 76 int errors = 0;
78 for (int i = 0; i < count; i++) { 77 for (int i = 0; i < count; i++) {
79 resourceAccess.sendCommand(Sink::Commands::PingCommand) 78 resourceAccess.sendCommand(Sink::Commands::PingCommand)
80 .then<void>([&complete]() { 79 .then<void>([&complete]() { complete++; },
81 complete++; 80 [&errors, &complete](int error, const QString &msg) {
82 }, 81 qWarning() << msg;
83 [&errors, &complete](int error, const QString &msg) { 82 errors++;
84 qWarning() << msg; 83 complete++;
85 errors++; 84 })
86 complete++; 85 .then<void>([&resourceAccess]() {
87 }).then<void>([&resourceAccess]() {
88 resourceAccess.close(); 86 resourceAccess.close();
89 resourceAccess.open(); 87 resourceAccess.open();
90 }).exec().waitForFinished(); 88 })
89 .exec()
90 .waitForFinished();
91 } 91 }
92 QTRY_COMPARE(complete, count); 92 QTRY_COMPARE(complete, count);
93 QVERIFY(!errors); 93 QVERIFY(!errors);
diff --git a/tests/storagebenchmark.cpp b/tests/storagebenchmark.cpp
index 8498df9..a1ddcc9 100644
--- a/tests/storagebenchmark.cpp
+++ b/tests/storagebenchmark.cpp
@@ -18,7 +18,7 @@ using namespace flatbuffers;
18 18
19static QByteArray createEvent() 19static QByteArray createEvent()
20{ 20{
21 static const size_t attachmentSize = 1024*2; // 2KB 21 static const size_t attachmentSize = 1024 * 2; // 2KB
22 static uint8_t rawData[attachmentSize]; 22 static uint8_t rawData[attachmentSize];
23 static FlatBufferBuilder fbb; 23 static FlatBufferBuilder fbb;
24 fbb.Clear(); 24 fbb.Clear();
@@ -26,13 +26,13 @@ static QByteArray createEvent()
26 uint8_t *rawDataPtr = Q_NULLPTR; 26 uint8_t *rawDataPtr = Q_NULLPTR;
27 auto summary = fbb.CreateString("summary"); 27 auto summary = fbb.CreateString("summary");
28 auto data = fbb.CreateUninitializedVector<uint8_t>(attachmentSize, &rawDataPtr); 28 auto data = fbb.CreateUninitializedVector<uint8_t>(attachmentSize, &rawDataPtr);
29 //auto data = fbb.CreateVector(rawData, attachmentSize); 29 // auto data = fbb.CreateVector(rawData, attachmentSize);
30 Calendar::EventBuilder eventBuilder(fbb); 30 Calendar::EventBuilder eventBuilder(fbb);
31 eventBuilder.add_summary(summary); 31 eventBuilder.add_summary(summary);
32 eventBuilder.add_attachment(data); 32 eventBuilder.add_attachment(data);
33 auto eventLocation = eventBuilder.Finish(); 33 auto eventLocation = eventBuilder.Finish();
34 Calendar::FinishEventBuffer(fbb, eventLocation); 34 Calendar::FinishEventBuffer(fbb, eventLocation);
35 memcpy((void*)rawDataPtr, rawData, attachmentSize); 35 memcpy((void *)rawDataPtr, rawData, attachmentSize);
36 } 36 }
37 37
38 return QByteArray::fromRawData(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); 38 return QByteArray::fromRawData(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
@@ -45,7 +45,7 @@ class StorageBenchmark : public QObject
45{ 45{
46 Q_OBJECT 46 Q_OBJECT
47private: 47private:
48 //This should point to a directory on disk and not a ramdisk (since we're measuring performance) 48 // This should point to a directory on disk and not a ramdisk (since we're measuring performance)
49 QString testDataPath; 49 QString testDataPath;
50 QString dbName; 50 QString dbName;
51 QString filePath; 51 QString filePath;
@@ -76,7 +76,7 @@ private slots:
76 76
77 QTime time; 77 QTime time;
78 time.start(); 78 time.start();
79 //Test db write time 79 // Test db write time
80 { 80 {
81 auto transaction = store->createTransaction(Sink::Storage::ReadWrite); 81 auto transaction = store->createTransaction(Sink::Storage::ReadWrite);
82 for (int i = 0; i < count; i++) { 82 for (int i = 0; i < count; i++) {
@@ -91,7 +91,7 @@ private slots:
91 qreal dbWriteDuration = time.restart(); 91 qreal dbWriteDuration = time.restart();
92 qreal dbWriteOpsPerMs = count / dbWriteDuration; 92 qreal dbWriteOpsPerMs = count / dbWriteDuration;
93 93
94 //Test file write time 94 // Test file write time
95 { 95 {
96 std::ofstream myfile; 96 std::ofstream myfile;
97 myfile.open(filePath.toStdString()); 97 myfile.open(filePath.toStdString());
@@ -103,7 +103,7 @@ private slots:
103 qreal fileWriteDuration = time.restart(); 103 qreal fileWriteDuration = time.restart();
104 qreal fileWriteOpsPerMs = count / fileWriteDuration; 104 qreal fileWriteOpsPerMs = count / fileWriteDuration;
105 105
106 //Db read time 106 // Db read time
107 { 107 {
108 auto transaction = store->createTransaction(Sink::Storage::ReadOnly); 108 auto transaction = store->createTransaction(Sink::Storage::ReadOnly);
109 auto db = transaction.openDatabase(); 109 auto db = transaction.openDatabase();
@@ -127,10 +127,10 @@ private slots:
127 void testSizes() 127 void testSizes()
128 { 128 {
129 Sink::Storage store(testDataPath, dbName); 129 Sink::Storage store(testDataPath, dbName);
130 qDebug() << "Database size [kb]: " << store.diskUsage()/1024; 130 qDebug() << "Database size [kb]: " << store.diskUsage() / 1024;
131 131
132 QFileInfo fileInfo(filePath); 132 QFileInfo fileInfo(filePath);
133 qDebug() << "File size [kb]: " << fileInfo.size()/1024; 133 qDebug() << "File size [kb]: " << fileInfo.size() / 1024;
134 } 134 }
135 135
136 void testScan() 136 void testScan()
@@ -139,13 +139,15 @@ private slots:
139 139
140 QBENCHMARK { 140 QBENCHMARK {
141 int hit = 0; 141 int hit = 0;
142 store->createTransaction(Sink::Storage::ReadOnly).openDatabase().scan("", [&](const QByteArray &key, const QByteArray &value) -> bool { 142 store->createTransaction(Sink::Storage::ReadOnly)
143 if (key == "key10000") { 143 .openDatabase()
144 //qDebug() << "hit"; 144 .scan("", [&](const QByteArray &key, const QByteArray &value) -> bool {
145 hit++; 145 if (key == "key10000") {
146 } 146 // qDebug() << "hit";
147 return true; 147 hit++;
148 }); 148 }
149 return true;
150 });
149 QCOMPARE(hit, 1); 151 QCOMPARE(hit, 1);
150 } 152 }
151 } 153 }
diff --git a/tests/storagetest.cpp b/tests/storagetest.cpp
index ebd9b8f..31809ce 100644
--- a/tests/storagetest.cpp
+++ b/tests/storagetest.cpp
@@ -24,7 +24,7 @@ private:
24 Sink::Storage storage(testDataPath, dbName, Sink::Storage::ReadWrite); 24 Sink::Storage storage(testDataPath, dbName, Sink::Storage::ReadWrite);
25 auto transaction = storage.createTransaction(Sink::Storage::ReadWrite); 25 auto transaction = storage.createTransaction(Sink::Storage::ReadWrite);
26 for (int i = 0; i < count; i++) { 26 for (int i = 0; i < count; i++) {
27 //This should perhaps become an implementation detail of the db? 27 // This should perhaps become an implementation detail of the db?
28 if (i % 10000 == 0) { 28 if (i % 10000 == 0) {
29 if (i > 0) { 29 if (i > 0) {
30 transaction.commit(); 30 transaction.commit();
@@ -41,19 +41,20 @@ private:
41 bool success = true; 41 bool success = true;
42 bool keyMatch = true; 42 bool keyMatch = true;
43 const auto reference = keyPrefix + QByteArray::number(i); 43 const auto reference = keyPrefix + QByteArray::number(i);
44 storage.createTransaction(Sink::Storage::ReadOnly).openDatabase().scan(keyPrefix + QByteArray::number(i), 44 storage.createTransaction(Sink::Storage::ReadOnly)
45 [&keyMatch, &reference](const QByteArray &key, const QByteArray &value) -> bool { 45 .openDatabase()
46 if (value != reference) { 46 .scan(keyPrefix + QByteArray::number(i),
47 qDebug() << "Mismatch while reading"; 47 [&keyMatch, &reference](const QByteArray &key, const QByteArray &value) -> bool {
48 keyMatch = false; 48 if (value != reference) {
49 } 49 qDebug() << "Mismatch while reading";
50 return keyMatch; 50 keyMatch = false;
51 }, 51 }
52 [&success](const Sink::Storage::Error &error) { 52 return keyMatch;
53 qDebug() << error.message; 53 },
54 success = false; 54 [&success](const Sink::Storage::Error &error) {
55 } 55 qDebug() << error.message;
56 ); 56 success = false;
57 });
57 return success && keyMatch; 58 return success && keyMatch;
58 } 59 }
59 60
@@ -87,7 +88,7 @@ private slots:
87 88
88 populate(count); 89 populate(count);
89 90
90 //ensure we can read everything back correctly 91 // ensure we can read everything back correctly
91 { 92 {
92 Sink::Storage storage(testDataPath, dbName); 93 Sink::Storage storage(testDataPath, dbName);
93 for (int i = 0; i < count; i++) { 94 for (int i = 0; i < count; i++) {
@@ -101,31 +102,35 @@ private slots:
101 const int count = 100; 102 const int count = 100;
102 populate(count); 103 populate(count);
103 104
104 //ensure we can scan for values 105 // ensure we can scan for values
105 { 106 {
106 int hit = 0; 107 int hit = 0;
107 Sink::Storage store(testDataPath, dbName); 108 Sink::Storage store(testDataPath, dbName);
108 store.createTransaction(Sink::Storage::ReadOnly).openDatabase().scan("", [&](const QByteArray &key, const QByteArray &value) -> bool { 109 store.createTransaction(Sink::Storage::ReadOnly)
109 if (key == "key50") { 110 .openDatabase()
110 hit++; 111 .scan("", [&](const QByteArray &key, const QByteArray &value) -> bool {
111 } 112 if (key == "key50") {
112 return true; 113 hit++;
113 }); 114 }
115 return true;
116 });
114 QCOMPARE(hit, 1); 117 QCOMPARE(hit, 1);
115 } 118 }
116 119
117 //ensure we can read a single value 120 // ensure we can read a single value
118 { 121 {
119 int hit = 0; 122 int hit = 0;
120 bool foundInvalidValue = false; 123 bool foundInvalidValue = false;
121 Sink::Storage store(testDataPath, dbName); 124 Sink::Storage store(testDataPath, dbName);
122 store.createTransaction(Sink::Storage::ReadOnly).openDatabase().scan("key50", [&](const QByteArray &key, const QByteArray &value) -> bool { 125 store.createTransaction(Sink::Storage::ReadOnly)
123 if (key != "key50") { 126 .openDatabase()
124 foundInvalidValue = true; 127 .scan("key50", [&](const QByteArray &key, const QByteArray &value) -> bool {
125 } 128 if (key != "key50") {
126 hit++; 129 foundInvalidValue = true;
127 return true; 130 }
128 }); 131 hit++;
132 return true;
133 });
129 QVERIFY(!foundInvalidValue); 134 QVERIFY(!foundInvalidValue);
130 QCOMPARE(hit, 1); 135 QCOMPARE(hit, 1);
131 } 136 }
@@ -137,9 +142,7 @@ private slots:
137 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 142 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
138 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 143 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
139 transaction.openDatabase().scan("key1", [&](const QByteArray &key, const QByteArray &value) -> bool { 144 transaction.openDatabase().scan("key1", [&](const QByteArray &key, const QByteArray &value) -> bool {
140 transaction.openDatabase().remove(key, [](const Sink::Storage::Error &) { 145 transaction.openDatabase().remove(key, [](const Sink::Storage::Error &) { QVERIFY(false); });
141 QVERIFY(false);
142 });
143 return false; 146 return false;
144 }); 147 });
145 } 148 }
@@ -148,12 +151,12 @@ private slots:
148 { 151 {
149 populate(3); 152 populate(3);
150 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 153 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
151 store.createTransaction(Sink::Storage::ReadOnly).openDatabase().scan("key1", [&](const QByteArray &key, const QByteArray &value) -> bool { 154 store.createTransaction(Sink::Storage::ReadOnly)
152 store.createTransaction(Sink::Storage::ReadWrite).openDatabase().remove(key, [](const Sink::Storage::Error &) { 155 .openDatabase()
153 QVERIFY(false); 156 .scan("key1", [&](const QByteArray &key, const QByteArray &value) -> bool {
157 store.createTransaction(Sink::Storage::ReadWrite).openDatabase().remove(key, [](const Sink::Storage::Error &) { QVERIFY(false); });
158 return false;
154 }); 159 });
155 return false;
156 });
157 } 160 }
158 161
159 void testReadEmptyDb() 162 void testReadEmptyDb()
@@ -166,14 +169,15 @@ private slots:
166 qDebug() << error.message; 169 qDebug() << error.message;
167 gotError = true; 170 gotError = true;
168 }); 171 });
169 int numValues = db.scan("", [&](const QByteArray &key, const QByteArray &value) -> bool { 172 int numValues = db.scan("",
170 gotResult = true; 173 [&](const QByteArray &key, const QByteArray &value) -> bool {
171 return false; 174 gotResult = true;
172 }, 175 return false;
173 [&](const Sink::Storage::Error &error) { 176 },
174 qDebug() << error.message; 177 [&](const Sink::Storage::Error &error) {
175 gotError = true; 178 qDebug() << error.message;
176 }); 179 gotError = true;
180 });
177 QCOMPARE(numValues, 0); 181 QCOMPARE(numValues, 0);
178 QVERIFY(!gotResult); 182 QVERIFY(!gotResult);
179 QVERIFY(!gotError); 183 QVERIFY(!gotError);
@@ -181,20 +185,20 @@ private slots:
181 185
182 void testConcurrentRead() 186 void testConcurrentRead()
183 { 187 {
184 //With a count of 10000 this test is more likely to expose problems, but also takes some time to execute. 188 // With a count of 10000 this test is more likely to expose problems, but also takes some time to execute.
185 const int count = 1000; 189 const int count = 1000;
186 190
187 populate(count); 191 populate(count);
188 // QTest::qWait(500); 192 // QTest::qWait(500);
189 193
190 //We repeat the test a bunch of times since failing is relatively random 194 // We repeat the test a bunch of times since failing is relatively random
191 for (int tries = 0; tries < 10; tries++) { 195 for (int tries = 0; tries < 10; tries++) {
192 bool error = false; 196 bool error = false;
193 //Try to concurrently read 197 // Try to concurrently read
194 QList<QFuture<void> > futures; 198 QList<QFuture<void>> futures;
195 const int concurrencyLevel = 20; 199 const int concurrencyLevel = 20;
196 for (int num = 0; num < concurrencyLevel; num++) { 200 for (int num = 0; num < concurrencyLevel; num++) {
197 futures << QtConcurrent::run([this, count, &error](){ 201 futures << QtConcurrent::run([this, count, &error]() {
198 Sink::Storage storage(testDataPath, dbName, Sink::Storage::ReadOnly); 202 Sink::Storage storage(testDataPath, dbName, Sink::Storage::ReadOnly);
199 Sink::Storage storage2(testDataPath, dbName + "2", Sink::Storage::ReadOnly); 203 Sink::Storage storage2(testDataPath, dbName + "2", Sink::Storage::ReadOnly);
200 for (int i = 0; i < count; i++) { 204 for (int i = 0; i < count; i++) {
@@ -205,7 +209,7 @@ private slots:
205 } 209 }
206 }); 210 });
207 } 211 }
208 for(auto future : futures) { 212 for (auto future : futures) {
209 future.waitForFinished(); 213 future.waitForFinished();
210 } 214 }
211 QVERIFY(!error); 215 QVERIFY(!error);
@@ -226,17 +230,18 @@ private slots:
226 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 230 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
227 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 231 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
228 auto db = transaction.openDatabase("default", nullptr, false); 232 auto db = transaction.openDatabase("default", nullptr, false);
229 db.write("key","value"); 233 db.write("key", "value");
230 db.write("key","value"); 234 db.write("key", "value");
231 235
232 int numValues = db.scan("", [&](const QByteArray &key, const QByteArray &value) -> bool { 236 int numValues = db.scan("",
233 gotResult = true; 237 [&](const QByteArray &key, const QByteArray &value) -> bool {
234 return true; 238 gotResult = true;
235 }, 239 return true;
236 [&](const Sink::Storage::Error &error) { 240 },
237 qDebug() << error.message; 241 [&](const Sink::Storage::Error &error) {
238 gotError = true; 242 qDebug() << error.message;
239 }); 243 gotError = true;
244 });
240 245
241 QCOMPARE(numValues, 1); 246 QCOMPARE(numValues, 1);
242 QVERIFY(!gotError); 247 QVERIFY(!gotError);
@@ -249,16 +254,17 @@ private slots:
249 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 254 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
250 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 255 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
251 auto db = transaction.openDatabase("default", nullptr, true); 256 auto db = transaction.openDatabase("default", nullptr, true);
252 db.write("key","value1"); 257 db.write("key", "value1");
253 db.write("key","value2"); 258 db.write("key", "value2");
254 int numValues = db.scan("key", [&](const QByteArray &key, const QByteArray &value) -> bool { 259 int numValues = db.scan("key",
255 gotResult = true; 260 [&](const QByteArray &key, const QByteArray &value) -> bool {
256 return true; 261 gotResult = true;
257 }, 262 return true;
258 [&](const Sink::Storage::Error &error) { 263 },
259 qDebug() << error.message; 264 [&](const Sink::Storage::Error &error) {
260 gotError = true; 265 qDebug() << error.message;
261 }); 266 gotError = true;
267 });
262 268
263 QCOMPARE(numValues, 2); 269 QCOMPARE(numValues, 2);
264 QVERIFY(!gotError); 270 QVERIFY(!gotError);
@@ -269,14 +275,17 @@ private slots:
269 bool gotResult = false; 275 bool gotResult = false;
270 bool gotError = false; 276 bool gotError = false;
271 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadOnly); 277 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadOnly);
272 int numValues = store.createTransaction(Sink::Storage::ReadOnly).openDatabase("test").scan("", [&](const QByteArray &key, const QByteArray &value) -> bool { 278 int numValues = store.createTransaction(Sink::Storage::ReadOnly)
273 gotResult = true; 279 .openDatabase("test")
274 return false; 280 .scan("",
275 }, 281 [&](const QByteArray &key, const QByteArray &value) -> bool {
276 [&](const Sink::Storage::Error &error) { 282 gotResult = true;
277 qDebug() << error.message; 283 return false;
278 gotError = true; 284 },
279 }); 285 [&](const Sink::Storage::Error &error) {
286 qDebug() << error.message;
287 gotError = true;
288 });
280 QCOMPARE(numValues, 0); 289 QCOMPARE(numValues, 0);
281 QVERIFY(!gotResult); 290 QVERIFY(!gotResult);
282 QVERIFY(!gotError); 291 QVERIFY(!gotError);
@@ -286,10 +295,12 @@ private slots:
286 { 295 {
287 bool gotError = false; 296 bool gotError = false;
288 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 297 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
289 store.createTransaction(Sink::Storage::ReadWrite).openDatabase("test").write("key1", "value1", [&](const Sink::Storage::Error &error) { 298 store.createTransaction(Sink::Storage::ReadWrite)
290 qDebug() << error.message; 299 .openDatabase("test")
291 gotError = true; 300 .write("key1", "value1", [&](const Sink::Storage::Error &error) {
292 }); 301 qDebug() << error.message;
302 gotError = true;
303 });
293 QVERIFY(!gotError); 304 QVERIFY(!gotError);
294 } 305 }
295 306
@@ -297,24 +308,24 @@ private slots:
297 { 308 {
298 bool gotError = false; 309 bool gotError = false;
299 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 310 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
300 store.createTransaction(Sink::Storage::ReadWrite).openDatabase("test", nullptr, true).write("key1", "value1", [&](const Sink::Storage::Error &error) { 311 store.createTransaction(Sink::Storage::ReadWrite)
301 qDebug() << error.message; 312 .openDatabase("test", nullptr, true)
302 gotError = true; 313 .write("key1", "value1", [&](const Sink::Storage::Error &error) {
303 }); 314 qDebug() << error.message;
315 gotError = true;
316 });
304 QVERIFY(!gotError); 317 QVERIFY(!gotError);
305 } 318 }
306 319
307 //By default we want only exact matches 320 // By default we want only exact matches
308 void testSubstringKeys() 321 void testSubstringKeys()
309 { 322 {
310 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 323 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
311 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 324 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
312 auto db = transaction.openDatabase("test", nullptr, true); 325 auto db = transaction.openDatabase("test", nullptr, true);
313 db.write("sub","value1"); 326 db.write("sub", "value1");
314 db.write("subsub","value2"); 327 db.write("subsub", "value2");
315 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { 328 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; });
316 return true;
317 });
318 329
319 QCOMPARE(numValues, 1); 330 QCOMPARE(numValues, 1);
320 } 331 }
@@ -324,12 +335,10 @@ private slots:
324 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 335 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
325 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 336 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
326 auto db = transaction.openDatabase("test", nullptr, false); 337 auto db = transaction.openDatabase("test", nullptr, false);
327 db.write("sub","value1"); 338 db.write("sub", "value1");
328 db.write("subsub","value2"); 339 db.write("subsub", "value2");
329 db.write("wubsub","value3"); 340 db.write("wubsub", "value3");
330 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { 341 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }, nullptr, true);
331 return true;
332 }, nullptr, true);
333 342
334 QCOMPARE(numValues, 2); 343 QCOMPARE(numValues, 2);
335 } 344 }
@@ -339,12 +348,10 @@ private slots:
339 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 348 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
340 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 349 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
341 auto db = transaction.openDatabase("test", nullptr, true); 350 auto db = transaction.openDatabase("test", nullptr, true);
342 db.write("sub","value1"); 351 db.write("sub", "value1");
343 db.write("subsub","value2"); 352 db.write("subsub", "value2");
344 db.write("wubsub","value3"); 353 db.write("wubsub", "value3");
345 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { 354 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; }, nullptr, true);
346 return true;
347 }, nullptr, true);
348 355
349 QCOMPARE(numValues, 2); 356 QCOMPARE(numValues, 2);
350 } 357 }
@@ -354,9 +361,9 @@ private slots:
354 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 361 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
355 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 362 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
356 auto db = transaction.openDatabase("test", nullptr, false); 363 auto db = transaction.openDatabase("test", nullptr, false);
357 db.write("sub_2","value2"); 364 db.write("sub_2", "value2");
358 db.write("sub_1","value1"); 365 db.write("sub_1", "value1");
359 db.write("sub_3","value3"); 366 db.write("sub_3", "value3");
360 QList<QByteArray> results; 367 QList<QByteArray> results;
361 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { 368 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool {
362 results << value; 369 results << value;
@@ -369,16 +376,14 @@ private slots:
369 QCOMPARE(results.at(2), QByteArray("value3")); 376 QCOMPARE(results.at(2), QByteArray("value3"));
370 } 377 }
371 378
372 //Ensure we don't retrieve a key that is greater than the current key. We only want equal keys. 379 // Ensure we don't retrieve a key that is greater than the current key. We only want equal keys.
373 void testKeyRange() 380 void testKeyRange()
374 { 381 {
375 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 382 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
376 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 383 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
377 auto db = transaction.openDatabase("test", nullptr, true); 384 auto db = transaction.openDatabase("test", nullptr, true);
378 db.write("sub1","value1"); 385 db.write("sub1", "value1");
379 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { 386 int numValues = db.scan("sub", [&](const QByteArray &key, const QByteArray &value) -> bool { return true; });
380 return true;
381 });
382 387
383 QCOMPARE(numValues, 0); 388 QCOMPARE(numValues, 0);
384 } 389 }
@@ -388,14 +393,12 @@ private slots:
388 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 393 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
389 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 394 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
390 auto db = transaction.openDatabase("test", nullptr, false); 395 auto db = transaction.openDatabase("test", nullptr, false);
391 db.write("sub1","value1"); 396 db.write("sub1", "value1");
392 db.write("sub2","value2"); 397 db.write("sub2", "value2");
393 db.write("wub3","value3"); 398 db.write("wub3", "value3");
394 db.write("wub4","value4"); 399 db.write("wub4", "value4");
395 QByteArray result; 400 QByteArray result;
396 db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { 401 db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { result = value; });
397 result = value;
398 });
399 402
400 QCOMPARE(result, QByteArray("value2")); 403 QCOMPARE(result, QByteArray("value2"));
401 } 404 }
@@ -405,11 +408,9 @@ private slots:
405 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 408 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
406 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 409 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
407 auto db = transaction.openDatabase("test", nullptr, false); 410 auto db = transaction.openDatabase("test", nullptr, false);
408 db.write("sub2","value2"); 411 db.write("sub2", "value2");
409 QByteArray result; 412 QByteArray result;
410 db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { 413 db.findLatest("sub", [&](const QByteArray &key, const QByteArray &value) { result = value; });
411 result = value;
412 });
413 414
414 QCOMPARE(result, QByteArray("value2")); 415 QCOMPARE(result, QByteArray("value2"));
415 } 416 }
@@ -419,12 +420,10 @@ private slots:
419 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite); 420 Sink::Storage store(testDataPath, dbName, Sink::Storage::ReadWrite);
420 auto transaction = store.createTransaction(Sink::Storage::ReadWrite); 421 auto transaction = store.createTransaction(Sink::Storage::ReadWrite);
421 auto db = transaction.openDatabase("test", nullptr, false); 422 auto db = transaction.openDatabase("test", nullptr, false);
422 db.write("sub2","value2"); 423 db.write("sub2", "value2");
423 db.write("wub3","value3"); 424 db.write("wub3", "value3");
424 QByteArray result; 425 QByteArray result;
425 db.findLatest("wub", [&](const QByteArray &key, const QByteArray &value) { 426 db.findLatest("wub", [&](const QByteArray &key, const QByteArray &value) { result = value; });
426 result = value;
427 });
428 427
429 QCOMPARE(result, QByteArray("value3")); 428 QCOMPARE(result, QByteArray("value3"));
430 } 429 }
diff --git a/tests/testimplementations.h b/tests/testimplementations.h
index adfdab3..688875d 100644
--- a/tests/testimplementations.h
+++ b/tests/testimplementations.h
@@ -28,7 +28,7 @@
28#include <common/genericresource.h> 28#include <common/genericresource.h>
29#include <common/commands.h> 29#include <common/commands.h>
30 30
31//Replace with something different 31// Replace with something different
32#include "event_generated.h" 32#include "event_generated.h"
33#include "mail_generated.h" 33#include "mail_generated.h"
34#include "createentity_generated.h" 34#include "createentity_generated.h"
@@ -36,37 +36,48 @@
36class TestEventAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Event, Sink::ApplicationDomain::Buffer::Event, Sink::ApplicationDomain::Buffer::EventBuilder> 36class TestEventAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Event, Sink::ApplicationDomain::Buffer::Event, Sink::ApplicationDomain::Buffer::EventBuilder>
37{ 37{
38public: 38public:
39 TestEventAdaptorFactory() 39 TestEventAdaptorFactory() : DomainTypeAdaptorFactory()
40 : DomainTypeAdaptorFactory()
41 { 40 {
42 } 41 }
43 42
44 virtual ~TestEventAdaptorFactory() {}; 43 virtual ~TestEventAdaptorFactory(){};
45}; 44};
46 45
47class TestMailAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Mail, Sink::ApplicationDomain::Buffer::Mail, Sink::ApplicationDomain::Buffer::MailBuilder> 46class TestMailAdaptorFactory : public DomainTypeAdaptorFactory<Sink::ApplicationDomain::Mail, Sink::ApplicationDomain::Buffer::Mail, Sink::ApplicationDomain::Buffer::MailBuilder>
48{ 47{
49public: 48public:
50 TestMailAdaptorFactory() 49 TestMailAdaptorFactory() : DomainTypeAdaptorFactory()
51 : DomainTypeAdaptorFactory()
52 { 50 {
53 } 51 }
54 52
55 virtual ~TestMailAdaptorFactory() {}; 53 virtual ~TestMailAdaptorFactory(){};
56}; 54};
57 55
58class TestResourceAccess : public Sink::ResourceAccessInterface 56class TestResourceAccess : public Sink::ResourceAccessInterface
59{ 57{
60 Q_OBJECT 58 Q_OBJECT
61public: 59public:
62 virtual ~TestResourceAccess() {}; 60 virtual ~TestResourceAccess(){};
63 KAsync::Job<void> sendCommand(int commandId) Q_DECL_OVERRIDE { return KAsync::null<void>(); } 61 KAsync::Job<void> sendCommand(int commandId) Q_DECL_OVERRIDE
64 KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) Q_DECL_OVERRIDE { return KAsync::null<void>(); } 62 {
65 KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) Q_DECL_OVERRIDE { return KAsync::null<void>(); } 63 return KAsync::null<void>();
64 }
65 KAsync::Job<void> sendCommand(int commandId, flatbuffers::FlatBufferBuilder &fbb) Q_DECL_OVERRIDE
66 {
67 return KAsync::null<void>();
68 }
69 KAsync::Job<void> synchronizeResource(bool remoteSync, bool localSync) Q_DECL_OVERRIDE
70 {
71 return KAsync::null<void>();
72 }
66 73
67public slots: 74public slots:
68 void open() Q_DECL_OVERRIDE {} 75 void open() Q_DECL_OVERRIDE
69 void close() Q_DECL_OVERRIDE {} 76 {
77 }
78 void close() Q_DECL_OVERRIDE
79 {
80 }
70}; 81};
71 82
72class TestResourceFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Event> 83class TestResourceFacade : public Sink::GenericFacade<Sink::ApplicationDomain::Event>
@@ -75,11 +86,9 @@ public:
75 TestResourceFacade(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess) 86 TestResourceFacade(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess)
76 : Sink::GenericFacade<Sink::ApplicationDomain::Event>(instanceIdentifier, QSharedPointer<TestEventAdaptorFactory>::create(), resourceAccess) 87 : Sink::GenericFacade<Sink::ApplicationDomain::Event>(instanceIdentifier, QSharedPointer<TestEventAdaptorFactory>::create(), resourceAccess)
77 { 88 {
78
79 } 89 }
80 virtual ~TestResourceFacade() 90 virtual ~TestResourceFacade()
81 { 91 {
82
83 } 92 }
84}; 93};
85 94
@@ -89,19 +98,16 @@ public:
89 TestMailResourceFacade(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess) 98 TestMailResourceFacade(const QByteArray &instanceIdentifier, const QSharedPointer<Sink::ResourceAccessInterface> resourceAccess)
90 : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(instanceIdentifier, QSharedPointer<TestMailAdaptorFactory>::create(), resourceAccess) 99 : Sink::GenericFacade<Sink::ApplicationDomain::Mail>(instanceIdentifier, QSharedPointer<TestMailAdaptorFactory>::create(), resourceAccess)
91 { 100 {
92
93 } 101 }
94 virtual ~TestMailResourceFacade() 102 virtual ~TestMailResourceFacade()
95 { 103 {
96
97 } 104 }
98}; 105};
99 106
100class TestResource : public Sink::GenericResource 107class TestResource : public Sink::GenericResource
101{ 108{
102public: 109public:
103 TestResource(const QByteArray &instanceIdentifier, QSharedPointer<Sink::Pipeline> pipeline) 110 TestResource(const QByteArray &instanceIdentifier, QSharedPointer<Sink::Pipeline> pipeline) : Sink::GenericResource(instanceIdentifier, pipeline)
104 : Sink::GenericResource(instanceIdentifier, pipeline)
105 { 111 {
106 } 112 }
107 113
@@ -126,4 +132,3 @@ QByteArray createCommand(const DomainType &domainObject, DomainTypeAdaptorFactor
126 Sink::Commands::FinishCreateEntityBuffer(fbb, location); 132 Sink::Commands::FinishCreateEntityBuffer(fbb, location);
127 return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); 133 return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize());
128} 134}
129