Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/windirstat/llfio.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2017-09-04 05:23:35 +0300
committerNiall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) <spamtrap@nedprod.com>2017-09-04 05:23:35 +0300
commit199f94231af6c9cde101995911fab8f8efa7a441 (patch)
treeec8e81344206318bf9b8d242478b653d5b8c6590 /programs
parent22417f35fdc10142a1bb18e6ecbc5e3ae1df021b (diff)
Enabled integrity checking in toy key value store, was fairly amazed to see it worked first time
Diffstat (limited to 'programs')
-rw-r--r--programs/key-value-store/Readme.md7
-rw-r--r--programs/key-value-store/include/key_value_store.hpp37
-rw-r--r--programs/key-value-store/main.cpp188
3 files changed, 146 insertions, 86 deletions
diff --git a/programs/key-value-store/Readme.md b/programs/key-value-store/Readme.md
index bc6dfd3e..d9d81cb8 100644
--- a/programs/key-value-store/Readme.md
+++ b/programs/key-value-store/Readme.md
@@ -34,6 +34,13 @@ index update.
Retrieving 1M key-value pairs ...
Fetched at 1945525 items per sec
```
+- 1Kb values Linux with ext4, integrity, no durability:
+ ```
+ Inserting 1M key-value pairs ...
+ Inserted at 581057 items per sec
+ Retrieving 1M key-value pairs ...
+ Fetched at 1519756 items per sec
+ ```
- 16 byte values Windows with NTFS, no integrity, no durability:
```
Inserting 1M key-value pairs ...
diff --git a/programs/key-value-store/include/key_value_store.hpp b/programs/key-value-store/include/key_value_store.hpp
index 111e0e04..dc83add4 100644
--- a/programs/key-value-store/include/key_value_store.hpp
+++ b/programs/key-value-store/include/key_value_store.hpp
@@ -186,7 +186,7 @@ namespace key_value_store
afio::file_handle::mode::read
#else
// Linux won't allow taking an exclusive lock on a read only file
- afio::file_handle::mode::write
+ mode
#endif
;
if(_smallfiles.read.empty())
@@ -239,12 +239,13 @@ namespace key_value_store
throw maximum_writers_reached();
}
// Set up the index, either r/w or read only with copy on write
- afio::section_handle sh = afio::section_handle::section(_indexfile, 0, (mode == afio::file_handle::mode::write) ? afio::section_handle::flag::readwrite : (afio::section_handle::flag::read | afio::section_handle::flag::cow)).value();
+ afio::section_handle::flag mapflags = (mode == afio::file_handle::mode::write) ? afio::section_handle::flag::readwrite : (afio::section_handle::flag::read | afio::section_handle::flag::cow);
+ afio::section_handle sh = afio::section_handle::section(_indexfile, 0, mapflags).value();
afio::file_handle::extent_type len = sh.length();
len -= sizeof(index::index);
len /= sizeof(index::open_hash_index::value_type);
size_t offset = sizeof(index::index);
- _index.emplace(sh, len, offset);
+ _index.emplace(sh, len, offset, mapflags);
_indexheader = reinterpret_cast<index::index *>((char *) _index->container().data() - offset);
if(_indexheader->writes_occurring[_mysmallfileidx] != 0)
{
@@ -260,7 +261,7 @@ namespace key_value_store
basic_key_value_store &operator=(const basic_key_value_store &) = delete;
basic_key_value_store &operator=(basic_key_value_store &&) = delete;
- basic_key_value_store(const afio::path_handle &dir, size_t hashtableentries, afio::file_handle::mode mode = afio::file_handle::mode::write, afio::file_handle::caching caching = afio::file_handle::caching::temporary)
+ basic_key_value_store(const afio::path_handle &dir, size_t hashtableentries, bool enable_integrity = false, afio::file_handle::mode mode = afio::file_handle::mode::write, afio::file_handle::caching caching = afio::file_handle::caching::temporary)
: _indexfile(afio::file_handle::file(dir, "index", mode, (mode == afio::file_handle::mode::write) ? afio::file_handle::creation::if_needed : afio::file_handle::creation::open_existing, caching).value())
{
if(mode == afio::file_handle::mode::write)
@@ -275,8 +276,12 @@ namespace key_value_store
afio::file_handle::extent_type size = sizeof(index::index) + (hashtableentries) * sizeof(index::open_hash_index::value_type);
size = afio::utils::round_up_to_page_size(size);
_indexfile.truncate(size).value();
- auto goodmagic = _goodmagic;
- _indexfile.write(0, (const char *) &goodmagic, 8).value();
+ index::index i;
+ memset(&i, 0, sizeof(i));
+ i.magic = _goodmagic;
+ i.all_writes_synced = _indexfile.are_writes_durable();
+ i.contents_hashed = enable_integrity;
+ _indexfile.write(0, (char *) &i, sizeof(i)).value();
}
else
{
@@ -290,14 +295,14 @@ namespace key_value_store
if(_indexheader->contents_hashed)
{
}
+ // Now we've finished the checks, reset writes_occurring and all_writes_synced
+ index::index i;
+ _indexfile.read(0, (char *) &i, sizeof(i)).value();
+ memset(i.writes_occurring, 0, sizeof(i.writes_occurring));
+ i.all_writes_synced = _indexfile.are_writes_durable();
+ memset(&i.hash, 0, sizeof(i.hash));
+ _indexfile.write(0, (char *) &i, sizeof(i)).value();
}
- // Reset writes_occurring and all_writes_synced
- index::index i;
- _indexfile.read(0, (char *) &i, sizeof(i)).value();
- memset(i.writes_occurring, 0, sizeof(i.writes_occurring));
- i.all_writes_synced = _indexfile.are_writes_durable();
- memset(&i.hash, 0, sizeof(i.hash));
- _indexfile.write(0, (char *) &i, sizeof(i)).value();
}
}
// Take a shared lock, blocking if someone is still setting things up
@@ -320,13 +325,13 @@ namespace key_value_store
}
}
//! \overload
- basic_key_value_store(const afio::path_view &dir, size_t hashtableentries, afio::file_handle::mode mode = afio::file_handle::mode::write, afio::file_handle::caching caching = afio::file_handle::caching::temporary)
- : basic_key_value_store(afio::directory_handle::directory({}, dir, afio::directory_handle::mode::write, afio::directory_handle::creation::if_needed).value(), hashtableentries, mode, caching)
+ basic_key_value_store(const afio::path_view &dir, size_t hashtableentries, bool enable_integrity = false, afio::file_handle::mode mode = afio::file_handle::mode::write, afio::file_handle::caching caching = afio::file_handle::caching::temporary)
+ : basic_key_value_store(afio::directory_handle::directory({}, dir, afio::directory_handle::mode::write, afio::directory_handle::creation::if_needed).value(), hashtableentries, enable_integrity, mode, caching)
{
}
//! Opens the store for read only access
basic_key_value_store(const afio::path_view &dir)
- : basic_key_value_store(afio::path_handle::path(dir).value(), 0, afio::file_handle::mode::read)
+ : basic_key_value_store(afio::path_handle::path(dir).value(), 0, false, afio::file_handle::mode::read)
{
}
~basic_key_value_store()
diff --git a/programs/key-value-store/main.cpp b/programs/key-value-store/main.cpp
index aa8a608f..a03059a3 100644
--- a/programs/key-value-store/main.cpp
+++ b/programs/key-value-store/main.cpp
@@ -24,6 +24,53 @@ Distributed under the Boost Software License, Version 1.0.
#include "include/key_value_store.hpp"
+void benchmark(key_value_store::basic_key_value_store &store, const char *desc)
+{
+ std::cout << "\n" << desc << ":" << std::endl;
+ // Write 1M values and see how long it takes
+ static std::vector<std::pair<uint64_t, std::string>> values;
+ if(values.empty())
+ {
+ std::cout << " Generating 1M key-value pairs ..." << std::endl;
+ for(size_t n = 0; n < 1000000; n++)
+ {
+ std::string randomvalue = AFIO_V2_NAMESPACE::utils::random_string(1024 / 2);
+ values.push_back({100 + n, randomvalue});
+ }
+ }
+ std::cout << " Inserting 1M key-value pairs ..." << std::endl;
+ {
+ auto begin = std::chrono::high_resolution_clock::now();
+ for(size_t n = 0; n < values.size(); n += 1024)
+ {
+ key_value_store::transaction tr(store);
+ for(size_t m = 0; m < 1024; m++)
+ {
+ if(n + m >= values.size())
+ break;
+ auto &i = values[n + m];
+ tr.update_unsafe(i.first, i.second);
+ }
+ tr.commit();
+ }
+ auto end = std::chrono::high_resolution_clock::now();
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
+ std::cout << " Inserted at " << (1000000000ULL / diff) << " items per sec" << std::endl;
+ }
+ std::cout << " Retrieving 1M key-value pairs ..." << std::endl;
+ {
+ auto begin = std::chrono::high_resolution_clock::now();
+ for(auto &i : values)
+ {
+ if(!store.find(i.first))
+ abort();
+ }
+ auto end = std::chrono::high_resolution_clock::now();
+ auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
+ std::cout << " Fetched at " << (1000000000ULL / diff) << " items per sec" << std::endl;
+ }
+}
+
int main()
{
#ifdef _WIN32
@@ -35,27 +82,66 @@ int main()
std::error_code ec;
AFIO_V2_NAMESPACE::filesystem::remove_all("teststore", ec);
}
- key_value_store::basic_key_value_store store("teststore", 2000000);
{
- key_value_store::transaction tr(store);
- tr.fetch(78);
- tr.update(78, "niall");
- tr.commit();
- auto kvi = store.find(78);
- if(kvi)
+ key_value_store::basic_key_value_store store("teststore", 10);
{
- std::cout << "Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
+ key_value_store::transaction tr(store);
+ tr.fetch(78);
+ tr.update(78, "niall");
+ tr.commit();
+ auto kvi = store.find(78);
+ if(kvi)
+ {
+ std::cout << "Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
+ }
+ else
+ {
+ std::cerr << "FAILURE: Key 78 was not found!" << std::endl;
+ }
}
- else
{
- std::cerr << "FAILURE: Key 78 was not found!" << std::endl;
+ key_value_store::transaction tr(store);
+ tr.fetch(79);
+ tr.update(79, "douglas");
+ tr.commit();
+ auto kvi = store.find(79);
+ if(kvi)
+ {
+ std::cout << "Key 79 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
+ }
+ else
+ {
+ std::cerr << "FAILURE: Key 79 was not found!" << std::endl;
+ }
+ }
+ {
+ key_value_store::transaction tr(store);
+ tr.fetch(78);
+ tr.remove(78);
+ tr.commit();
+ auto kvi = store.find(78, 0);
+ if(kvi)
+ {
+ std::cerr << "FAILURE: Revision 0 of Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
+ }
+ else
+ {
+ std::cout << "Revision 0 of key 78 was not found!" << std::endl;
+ }
+ kvi = store.find(78, 1);
+ if(kvi)
+ {
+ std::cout << "Revision 1 of Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
+ }
+ else
+ {
+ std::cerr << "FAILURE: Revision 1Key 78 was not found!" << std::endl;
+ }
}
}
+ // test read only
{
- key_value_store::transaction tr(store);
- tr.fetch(79);
- tr.update(79, "douglas");
- tr.commit();
+ key_value_store::basic_key_value_store store("teststore");
auto kvi = store.find(79);
if(kvi)
{
@@ -67,69 +153,31 @@ int main()
}
}
{
- key_value_store::transaction tr(store);
- tr.fetch(78);
- tr.remove(78);
- tr.commit();
- auto kvi = store.find(78, 0);
- if(kvi)
- {
- std::cerr << "FAILURE: Revision 0 of Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
- }
- else
- {
- std::cout << "Revision 0 of key 78 was not found!" << std::endl;
- }
- kvi = store.find(78, 1);
- if(kvi)
- {
- std::cout << "Revision 1 of Key 78 has value " << kvi.value << " and it was last updated at " << kvi.transaction_counter << std::endl;
- }
- else
- {
- std::cerr << "FAILURE: Revision 1Key 78 was not found!" << std::endl;
- }
+ std::error_code ec;
+ AFIO_V2_NAMESPACE::filesystem::remove_all("teststore", ec);
}
-
- // Write 1M values and see how long it takes
- std::vector<std::pair<uint64_t, std::string>> values;
- std::cout << "\nGenerating 1M key-value pairs ..." << std::endl;
- for(size_t n = 0; n < 1000000; n++)
{
- std::string randomvalue = AFIO_V2_NAMESPACE::utils::random_string(1024 / 2);
- values.push_back({100 + n, randomvalue});
+ key_value_store::basic_key_value_store store("teststore", 2000000);
+ benchmark(store, "no integrity, no durability");
}
- std::cout << "Inserting 1M key-value pairs ..." << std::endl;
{
- auto begin = std::chrono::high_resolution_clock::now();
- for(size_t n = 0; n < values.size(); n += 1024)
- {
- key_value_store::transaction tr(store);
- for(size_t m = 0; m < 1024; m++)
- {
- if(n + m >= values.size())
- break;
- auto &i = values[n + m];
- tr.update_unsafe(i.first, i.second);
- }
- tr.commit();
- }
- auto end = std::chrono::high_resolution_clock::now();
- auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
- std::cout << "Inserted at " << (1000000000ULL / diff) << " items per sec" << std::endl;
+ std::error_code ec;
+ AFIO_V2_NAMESPACE::filesystem::remove_all("teststore", ec);
}
- std::cout << "Retrieving 1M key-value pairs ..." << std::endl;
{
- auto begin = std::chrono::high_resolution_clock::now();
- for(auto &i : values)
- {
- if(!store.find(i.first))
- abort();
- }
- auto end = std::chrono::high_resolution_clock::now();
- auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
- std::cout << "Fetched at " << (1000000000ULL / diff) << " items per sec" << std::endl;
+ key_value_store::basic_key_value_store store("teststore", 2000000, true);
+ benchmark(store, "integrity, no durability");
}
+#if 0
+ {
+ std::error_code ec;
+ AFIO_V2_NAMESPACE::filesystem::remove_all("teststore", ec);
+ }
+ {
+ key_value_store::basic_key_value_store store("teststore", 2000000, true, AFIO_V2_NAMESPACE::file_handle::mode::write, AFIO_V2_NAMESPACE::file_handle::caching::reads);
+ benchmark(store, "integrity, durability");
+ }
+#endif
}
catch(const std::exception &e)
{