summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/storage.h19
-rw-r--r--common/storage_lmdb.cpp81
-rw-r--r--tests/dummyresourcewritebenchmark.cpp93
3 files changed, 187 insertions, 6 deletions
diff --git a/common/storage.h b/common/storage.h
index c39b904..1967a5e 100644
--- a/common/storage.h
+++ b/common/storage.h
@@ -123,6 +123,16 @@ public:
123 123
124 qint64 getSize(); 124 qint64 getSize();
125 125
126 struct Stat {
127 size_t branchPages;
128 size_t leafPages;
129 size_t overflowPages;
130 size_t numEntries;
131 };
132 Stat stat();
133
134 bool allowsDuplicates() const;
135
126 private: 136 private:
127 friend Transaction; 137 friend Transaction;
128 NamedDatabase(NamedDatabase &other); 138 NamedDatabase(NamedDatabase &other);
@@ -150,6 +160,15 @@ public:
150 160
151 operator bool() const; 161 operator bool() const;
152 162
163 struct Stat {
164 size_t totalPages;
165 size_t freePages;
166 size_t pageSize;
167 NamedDatabase::Stat mainDbStat;
168 NamedDatabase::Stat freeDbStat;
169 };
170 Stat stat();
171
153 private: 172 private:
154 Transaction(Transaction &other); 173 Transaction(Transaction &other);
155 Transaction &operator=(Transaction &other); 174 Transaction &operator=(Transaction &other);
diff --git a/common/storage_lmdb.cpp b/common/storage_lmdb.cpp
index 2745a14..392ac0a 100644
--- a/common/storage_lmdb.cpp
+++ b/common/storage_lmdb.cpp
@@ -496,13 +496,39 @@ qint64 DataStore::NamedDatabase::getSize()
496 if (rc) { 496 if (rc) {
497 SinkWarning() << "Something went wrong " << QByteArray(mdb_strerror(rc)); 497 SinkWarning() << "Something went wrong " << QByteArray(mdb_strerror(rc));
498 } 498 }
499 // std::cout << "overflow_pages: " << stat.ms_overflow_pages << std::endl; 499 return stat.ms_psize * (stat.ms_leaf_pages + stat.ms_branch_pages + stat.ms_overflow_pages);
500}
501
502DataStore::NamedDatabase::Stat DataStore::NamedDatabase::stat()
503{
504 if (!d || !d->transaction) {
505 return {};
506 }
507
508 int rc;
509 MDB_stat stat;
510 rc = mdb_stat(d->transaction, d->dbi, &stat);
511 if (rc) {
512 SinkWarning() << "Something went wrong " << QByteArray(mdb_strerror(rc));
513 return {};
514 }
515 return {stat.ms_branch_pages,
516 stat.ms_leaf_pages,
517 stat.ms_overflow_pages,
518 stat.ms_entries};
500 // std::cout << "page size: " << stat.ms_psize << std::endl; 519 // std::cout << "page size: " << stat.ms_psize << std::endl;
501 // std::cout << "branch_pages: " << stat.ms_branch_pages << std::endl;
502 // std::cout << "leaf_pages: " << stat.ms_leaf_pages << std::endl; 520 // std::cout << "leaf_pages: " << stat.ms_leaf_pages << std::endl;
521 // std::cout << "branch_pages: " << stat.ms_branch_pages << std::endl;
522 // std::cout << "overflow_pages: " << stat.ms_overflow_pages << std::endl;
503 // std::cout << "depth: " << stat.ms_depth << std::endl; 523 // std::cout << "depth: " << stat.ms_depth << std::endl;
504 // std::cout << "entries: " << stat.ms_entries << std::endl; 524 // std::cout << "entries: " << stat.ms_entries << std::endl;
505 return stat.ms_psize * (stat.ms_leaf_pages + stat.ms_branch_pages + stat.ms_overflow_pages); 525}
526
527bool DataStore::NamedDatabase::allowsDuplicates() const
528{
529 unsigned int flags;
530 mdb_dbi_flags(d->transaction, d->dbi, &flags);
531 return flags & MDB_DUPSORT;
506} 532}
507 533
508 534
@@ -708,6 +734,55 @@ QList<QByteArray> DataStore::Transaction::getDatabaseNames() const
708} 734}
709 735
710 736
737DataStore::Transaction::Stat DataStore::Transaction::stat()
738{
739 const int freeDbi = 0;
740 const int mainDbi = 1;
741
742 MDB_envinfo mei;
743 mdb_env_info(d->env, &mei);
744
745 MDB_stat mst;
746 mdb_stat(d->transaction, freeDbi, &mst);
747 auto freeStat = NamedDatabase::Stat{mst.ms_branch_pages,
748 mst.ms_leaf_pages,
749 mst.ms_overflow_pages,
750 mst.ms_entries};
751
752 mdb_stat(d->transaction, mainDbi, &mst);
753 auto mainStat = NamedDatabase::Stat{mst.ms_branch_pages,
754 mst.ms_leaf_pages,
755 mst.ms_overflow_pages,
756 mst.ms_entries};
757
758 MDB_cursor *cursor;
759 MDB_val key, data;
760 size_t freePages = 0, *iptr;
761
762 int rc = mdb_cursor_open(d->transaction, freeDbi, &cursor);
763 if (rc) {
764 fprintf(stderr, "mdb_cursor_open failed, error %d %s\n", rc, mdb_strerror(rc));
765 return {};
766 }
767
768 while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {
769 iptr = static_cast<size_t*>(data.mv_data);
770 freePages += *iptr;
771 size_t pg, prev;
772 ssize_t i, j, span = 0;
773 j = *iptr++;
774 for (i = j, prev = 1; --i >= 0; ) {
775 pg = iptr[i];
776 prev = pg;
777 pg += span;
778 for (; i >= span && iptr[i-span] == pg; span++, pg++) ;
779 }
780 }
781 mdb_cursor_close(cursor);
782 return {mei.me_last_pgno + 1, freePages, mst.ms_psize, mainStat, freeStat};
783}
784
785
711class DataStore::Private 786class DataStore::Private
712{ 787{
713public: 788public:
diff --git a/tests/dummyresourcewritebenchmark.cpp b/tests/dummyresourcewritebenchmark.cpp
index 87bb57a..07f57f6 100644
--- a/tests/dummyresourcewritebenchmark.cpp
+++ b/tests/dummyresourcewritebenchmark.cpp
@@ -27,16 +27,21 @@
27#include "getrssusage.h" 27#include "getrssusage.h"
28#include "utils.h" 28#include "utils.h"
29 29
30static QByteArray createEntityBuffer(int &bufferSize) 30static QByteArray createEntityBuffer(size_t attachmentSize, int &bufferSize)
31{ 31{
32 uint8_t rawData[attachmentSize];
32 flatbuffers::FlatBufferBuilder eventFbb; 33 flatbuffers::FlatBufferBuilder eventFbb;
33 eventFbb.Clear(); 34 eventFbb.Clear();
34 { 35 {
36 uint8_t *rawDataPtr = Q_NULLPTR;
37 auto data = eventFbb.CreateUninitializedVector<uint8_t>(attachmentSize, &rawDataPtr);
35 auto summary = eventFbb.CreateString("summary"); 38 auto summary = eventFbb.CreateString("summary");
36 Sink::ApplicationDomain::Buffer::EventBuilder eventBuilder(eventFbb); 39 Sink::ApplicationDomain::Buffer::EventBuilder eventBuilder(eventFbb);
37 eventBuilder.add_summary(summary); 40 eventBuilder.add_summary(summary);
41 eventBuilder.add_attachment(data);
38 auto eventLocation = eventBuilder.Finish(); 42 auto eventLocation = eventBuilder.Finish();
39 Sink::ApplicationDomain::Buffer::FinishEventBuffer(eventFbb, eventLocation); 43 Sink::ApplicationDomain::Buffer::FinishEventBuffer(eventFbb, eventLocation);
44 memcpy((void *)rawDataPtr, rawData, attachmentSize);
40 } 45 }
41 46
42 flatbuffers::FlatBufferBuilder localFbb; 47 flatbuffers::FlatBufferBuilder localFbb;
@@ -84,7 +89,7 @@ class DummyResourceWriteBenchmark : public QObject
84 DummyResource resource(Sink::ResourceContext{"sink.dummy.instance1", "sink.dummy", Sink::AdaptorFactoryRegistry::instance().getFactories("sink.dummy")}); 89 DummyResource resource(Sink::ResourceContext{"sink.dummy.instance1", "sink.dummy", Sink::AdaptorFactoryRegistry::instance().getFactories("sink.dummy")});
85 90
86 int bufferSize = 0; 91 int bufferSize = 0;
87 auto command = createEntityBuffer(bufferSize); 92 auto command = createEntityBuffer(0, bufferSize);
88 93
89 const auto startingRss = getCurrentRSS(); 94 const auto startingRss = getCurrentRSS();
90 for (int i = 0; i < num; i++) { 95 for (int i = 0; i < num; i++) {
@@ -114,7 +119,7 @@ class DummyResourceWriteBenchmark : public QObject
114 std::cout << "Rss without db [kb]: " << rssWithoutDb / 1024 << std::endl; 119 std::cout << "Rss without db [kb]: " << rssWithoutDb / 1024 << std::endl;
115 std::cout << "Percentage peak rss error: " << percentageRssError << std::endl; 120 std::cout << "Percentage peak rss error: " << percentageRssError << std::endl;
116 121
117 auto onDisk = DummyResource::diskUsage("sink.dummy.instance1"); 122 auto onDisk = Sink::Storage::DataStore(Sink::storageLocation(), "sink.dummy.instance1", Sink::Storage::DataStore::ReadOnly).diskUsage();
118 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal); 123 auto writeAmplification = static_cast<double>(onDisk) / static_cast<double>(bufferSizeTotal);
119 std::cout << "On disk [kb]: " << onDisk / 1024 << std::endl; 124 std::cout << "On disk [kb]: " << onDisk / 1024 << std::endl;
120 std::cout << "Buffer size total [kb]: " << bufferSizeTotal / 1024 << std::endl; 125 std::cout << "Buffer size total [kb]: " << bufferSizeTotal / 1024 << std::endl;
@@ -165,6 +170,84 @@ class DummyResourceWriteBenchmark : public QObject
165 // std::system("exec pmap -x \"$PPID\""); 170 // std::system("exec pmap -x \"$PPID\"");
166 } 171 }
167 172
173 void testDiskUsage(int num)
174 {
175 auto resourceId = "testDiskUsage";
176 DummyResource::removeFromDisk(resourceId);
177
178 {
179 DummyResource resource(Sink::ResourceContext{resourceId, "sink.dummy", Sink::AdaptorFactoryRegistry::instance().getFactories("sink.dummy")});
180
181 int bufferSize = 0;
182 auto command = createEntityBuffer(1000, bufferSize);
183
184 for (int i = 0; i < num; i++) {
185 resource.processCommand(Sink::Commands::CreateEntityCommand, command);
186 }
187
188 // Wait until all messages have been processed
189 resource.processAllMessages().exec().waitForFinished();
190 }
191
192 qint64 totalDbSizes = 0;
193 qint64 totalKeysAndValues = 0;
194 QMap<QByteArray, qint64> dbSizes;
195 Sink::Storage::DataStore storage(Sink::storageLocation(), resourceId, Sink::Storage::DataStore::ReadOnly);
196 auto transaction = storage.createTransaction(Sink::Storage::DataStore::ReadOnly);
197 auto stat = transaction.stat();
198
199 std::cout << "Free pages: " << stat.freePages << std::endl;
200 std::cout << "Total pages: " << stat.totalPages << std::endl;
201 auto totalUsedSize = stat.pageSize * (stat.totalPages - stat.freePages);
202 std::cout << "Used size: " << totalUsedSize << std::endl;
203
204 auto freeDbSize = stat.pageSize * (stat.freeDbStat.leafPages + stat.freeDbStat.overflowPages + stat.freeDbStat.branchPages);
205 std::cout << "Free db size: " << freeDbSize << std::endl;
206 auto mainDbSize = stat.pageSize * (stat.mainDbStat.leafPages + stat.mainDbStat.overflowPages + stat.mainDbStat.branchPages);
207 std::cout << "Main db size: " << mainDbSize << std::endl;
208
209 totalDbSizes += mainDbSize;
210 QList<QByteArray> databases = transaction.getDatabaseNames();
211 for (const auto &databaseName : databases) {
212 auto db = transaction.openDatabase(databaseName);
213 const auto size = db.getSize();
214 dbSizes.insert(databaseName, size);
215 totalDbSizes += size;
216
217 qint64 keySizes = 0;
218 qint64 valueSizes = 0;
219 db.scan({}, [&] (const QByteArray &key, const QByteArray &data) {
220 keySizes += key.size();
221 valueSizes += data.size();
222 return true;
223 },
224 [&](const Sink::Storage::DataStore::Error &e) {
225 qWarning() << "Error while reading" << e;
226 },
227 false, false);
228
229 auto s = db.stat();
230 auto usedPages = (s.leafPages + s.branchPages + s.overflowPages);
231
232 std::cout << std::endl;
233 std::cout << "Db: " << databaseName.toStdString() << (db.allowsDuplicates() ? " DUP" : "") << std::endl;
234 std::cout << "Used pages " << usedPages << std::endl;
235 std::cout << "Used size " << (keySizes + valueSizes) / 4096.0 << std::endl;
236 std::cout << "Entries " << s.numEntries << std::endl;
237 totalKeysAndValues += (keySizes + valueSizes);
238 }
239 std::cout << std::endl;
240
241 auto mainStoreOnDisk = Sink::Storage::DataStore(Sink::storageLocation(), resourceId, Sink::Storage::DataStore::ReadOnly).diskUsage();
242 auto totalOnDisk = DummyResource::diskUsage(resourceId);
243 std::cout << "Calculated key + value size: " << totalKeysAndValues << std::endl;
244 std::cout << "Calculated total db sizes: " << totalDbSizes << std::endl;
245 std::cout << "Main store on disk: " << mainStoreOnDisk << std::endl;
246 std::cout << "Total on disk: " << totalOnDisk << std::endl;
247 std::cout << "Used size amplification: " << static_cast<double>(totalUsedSize) / static_cast<double>(totalKeysAndValues) << std::endl;
248 std::cout << "Write amplification: " << static_cast<double>(mainStoreOnDisk) / static_cast<double>(totalKeysAndValues) << std::endl;
249 std::cout << std::endl;
250 }
168 251
169private slots: 252private slots:
170 void initTestCase() 253 void initTestCase()
@@ -201,6 +284,10 @@ private slots:
201 HAWD::Formatter::print(dataset); 284 HAWD::Formatter::print(dataset);
202 } 285 }
203 286
287 void testDiskUsage()
288 {
289 testDiskUsage(1000);
290 }
204 291
205 // This allows to run individual parts without doing a cleanup, but still cleaning up normally 292 // This allows to run individual parts without doing a cleanup, but still cleaning up normally
206 void testCleanupForCompleteTest() 293 void testCleanupForCompleteTest()