diff options
Diffstat (limited to 'protocols/Telegram/tdlib/td/test/db.cpp')
-rw-r--r-- | protocols/Telegram/tdlib/td/test/db.cpp | 512 |
1 files changed, 342 insertions, 170 deletions
diff --git a/protocols/Telegram/tdlib/td/test/db.cpp b/protocols/Telegram/tdlib/td/test/db.cpp index 8917dd65b8..61757e9893 100644 --- a/protocols/Telegram/tdlib/td/test/db.cpp +++ b/protocols/Telegram/tdlib/td/test/db.cpp @@ -1,17 +1,29 @@ // -// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018 +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#include "data.h" + #include "td/db/binlog/BinlogHelper.h" +#include "td/db/binlog/ConcurrentBinlog.h" #include "td/db/BinlogKeyValue.h" +#include "td/db/DbKey.h" #include "td/db/SeqKeyValue.h" +#include "td/db/SqliteConnectionSafe.h" +#include "td/db/SqliteDb.h" #include "td/db/SqliteKeyValue.h" #include "td/db/SqliteKeyValueSafe.h" #include "td/db/TsSeqKeyValue.h" +#include "td/actor/actor.h" +#include "td/actor/ConcurrentScheduler.h" + +#include "td/utils/base64.h" #include "td/utils/common.h" +#include "td/utils/filesystem.h" +#include "td/utils/FlatHashMap.h" #include "td/utils/logging.h" #include "td/utils/port/FileFd.h" #include "td/utils/port/thread.h" @@ -24,144 +36,239 @@ #include <map> #include <memory> -REGISTER_TESTS(db); - -using namespace td; - template <class ContainerT> static typename ContainerT::value_type &rand_elem(ContainerT &cont) { - CHECK(0 < cont.size() && cont.size() <= static_cast<size_t>(std::numeric_limits<int>::max())); - return cont[Random::fast(0, static_cast<int>(cont.size()) - 1)]; + CHECK(0 < cont.size() && cont.size() <= static_cast<std::size_t>(std::numeric_limits<int>::max())); + return cont[td::Random::fast(0, static_cast<int>(cont.size()) - 1)]; +} + +TEST(DB, binlog_encryption_bug) { + td::CSlice binlog_name = "test_binlog"; + td::Binlog::destroy(binlog_name).ignore(); + + auto cucumber = td::DbKey::password("cucu'\"mb er"); + auto empty = td::DbKey::empty(); + { + td::Binlog binlog; + binlog + .init( + binlog_name.str(), [&](const td::BinlogEvent &x) {}, cucumber) + .ensure(); + } + { + td::Binlog binlog; + binlog + .init( + binlog_name.str(), [&](const td::BinlogEvent &x) {}, cucumber) + .ensure(); + } } TEST(DB, binlog_encryption) { - CSlice binlog_name = "test_binlog"; - Binlog::destroy(binlog_name).ignore(); + td::CSlice binlog_name = "test_binlog"; + td::Binlog::destroy(binlog_name).ignore(); - auto hello = DbKey::raw_key(std::string(32, 'A')); - auto cucumber = DbKey::password("cucumber"); - auto empty = DbKey::empty(); - auto long_data = string(10000, 'Z'); + auto hello = td::DbKey::raw_key(td::string(32, 'A')); + auto cucumber = td::DbKey::password("cucu'\"mb er"); + auto empty = td::DbKey::empty(); + auto long_data = td::string(10000, 'Z'); { - Binlog binlog; - binlog.init(binlog_name.str(), [](const BinlogEvent &x) {}).ensure(); - binlog.add_raw_event(BinlogEvent::create_raw(binlog.next_id(), 1, 0, create_storer("AAAA"))); - binlog.add_raw_event(BinlogEvent::create_raw(binlog.next_id(), 1, 0, create_storer("BBBB"))); - binlog.add_raw_event(BinlogEvent::create_raw(binlog.next_id(), 1, 0, create_storer(long_data))); + td::Binlog binlog; + binlog.init(binlog_name.str(), [](const td::BinlogEvent &x) {}).ensure(); + binlog.add_raw_event(td::BinlogEvent::create_raw(binlog.next_id(), 1, 0, td::create_storer("AAAA")), + td::BinlogDebugInfo{__FILE__, __LINE__}); + binlog.add_raw_event(td::BinlogEvent::create_raw(binlog.next_id(), 1, 0, td::create_storer("BBBB")), + td::BinlogDebugInfo{__FILE__, __LINE__}); + binlog.add_raw_event(td::BinlogEvent::create_raw(binlog.next_id(), 1, 0, td::create_storer(long_data)), + td::BinlogDebugInfo{__FILE__, __LINE__}); LOG(INFO) << "SET PASSWORD"; binlog.change_key(cucumber); binlog.change_key(hello); LOG(INFO) << "OK"; - binlog.add_raw_event(BinlogEvent::create_raw(binlog.next_id(), 1, 0, create_storer("CCCC"))); + binlog.add_raw_event(td::BinlogEvent::create_raw(binlog.next_id(), 1, 0, td::create_storer("CCCC")), + td::BinlogDebugInfo{__FILE__, __LINE__}); binlog.close().ensure(); } + return; + auto add_suffix = [&] { - auto fd = FileFd::open(binlog_name, FileFd::Flags::Write | FileFd::Flags::Append).move_as_ok(); + auto fd = td::FileFd::open(binlog_name, td::FileFd::Flags::Write | td::FileFd::Flags::Append).move_as_ok(); fd.write("abacabadaba").ensure(); }; add_suffix(); { - std::vector<string> v; + td::vector<td::string> v; LOG(INFO) << "RESTART"; - Binlog binlog; - binlog.init(binlog_name.str(), [&](const BinlogEvent &x) { v.push_back(x.data_.str()); }, hello).ensure(); - CHECK(v == std::vector<string>({"AAAA", "BBBB", long_data, "CCCC"})); + td::Binlog binlog; + binlog + .init( + binlog_name.str(), [&](const td::BinlogEvent &x) { v.push_back(x.data_.str()); }, hello) + .ensure(); + CHECK(v == td::vector<td::string>({"AAAA", "BBBB", long_data, "CCCC"})); } add_suffix(); { - std::vector<string> v; + td::vector<td::string> v; LOG(INFO) << "RESTART"; - Binlog binlog; - auto status = binlog.init(binlog_name.str(), [&](const BinlogEvent &x) { v.push_back(x.data_.str()); }, cucumber); + td::Binlog binlog; + auto status = binlog.init( + binlog_name.str(), [&](const td::BinlogEvent &x) { v.push_back(x.data_.str()); }, cucumber); CHECK(status.is_error()); } add_suffix(); { - std::vector<string> v; + td::vector<td::string> v; LOG(INFO) << "RESTART"; - Binlog binlog; - auto status = - binlog.init(binlog_name.str(), [&](const BinlogEvent &x) { v.push_back(x.data_.str()); }, cucumber, hello); - CHECK(v == std::vector<string>({"AAAA", "BBBB", long_data, "CCCC"})); + td::Binlog binlog; + auto status = binlog.init( + binlog_name.str(), [&](const td::BinlogEvent &x) { v.push_back(x.data_.str()); }, cucumber, hello); + CHECK(v == td::vector<td::string>({"AAAA", "BBBB", long_data, "CCCC"})); } -}; +} TEST(DB, sqlite_lfs) { - string path = "test_sqlite_db"; - SqliteDb::destroy(path).ignore(); - SqliteDb db; - db.init(path).ensure(); + td::string path = "test_sqlite_db"; + td::SqliteDb::destroy(path).ignore(); + auto db = td::SqliteDb::open_with_key(path, true, td::DbKey::empty()).move_as_ok(); db.exec("PRAGMA journal_mode=WAL").ensure(); db.exec("PRAGMA user_version").ensure(); + td::SqliteDb::destroy(path).ignore(); } TEST(DB, sqlite_encryption) { - string path = "test_sqlite_db"; - SqliteDb::destroy(path).ignore(); + td::string path = "test_sqlite_db"; + td::SqliteDb::destroy(path).ignore(); - auto empty = DbKey::empty(); - auto cucumber = DbKey::password("cucumber"); - auto tomato = DbKey::raw_key(string(32, 'a')); + auto empty = td::DbKey::empty(); + auto cucumber = td::DbKey::password("cucu'\"mb er"); + auto tomato = td::DbKey::raw_key(td::string(32, 'a')); { - auto db = SqliteDb::open_with_key(path, empty).move_as_ok(); - db.set_user_version(123); - auto kv = SqliteKeyValue(); - kv.init_with_connection(db.clone(), "kv"); + auto db = td::SqliteDb::open_with_key(path, true, empty).move_as_ok(); + db.set_user_version(123).ensure(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); kv.set("a", "b"); } - SqliteDb::open_with_key(path, cucumber).ensure_error(); // key was set... + td::SqliteDb::open_with_key(path, false, cucumber).ensure_error(); - SqliteDb::change_key(path, cucumber, empty).ensure(); + td::SqliteDb::change_key(path, false, cucumber, empty).ensure(); + td::SqliteDb::change_key(path, false, cucumber, empty).ensure(); - SqliteDb::open_with_key(path, tomato).ensure_error(); + td::SqliteDb::open_with_key(path, false, tomato).ensure_error(); { - auto db = SqliteDb::open_with_key(path, cucumber).move_as_ok(); - auto kv = SqliteKeyValue(); - kv.init_with_connection(db.clone(), "kv"); + auto db = td::SqliteDb::open_with_key(path, false, cucumber).move_as_ok(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); CHECK(kv.get("a") == "b"); CHECK(db.user_version().ok() == 123); } - SqliteDb::change_key(path, tomato, cucumber).ensure(); - SqliteDb::change_key(path, tomato, cucumber).ensure(); + td::SqliteDb::change_key(path, false, tomato, cucumber).ensure(); + td::SqliteDb::change_key(path, false, tomato, cucumber).ensure(); - SqliteDb::open_with_key(path, cucumber).ensure_error(); + td::SqliteDb::open_with_key(path, false, cucumber).ensure_error(); { - auto db = SqliteDb::open_with_key(path, tomato).move_as_ok(); - auto kv = SqliteKeyValue(); - kv.init_with_connection(db.clone(), "kv"); + auto db = td::SqliteDb::open_with_key(path, false, tomato).move_as_ok(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); CHECK(kv.get("a") == "b"); CHECK(db.user_version().ok() == 123); } - SqliteDb::change_key(path, empty, tomato).ensure(); - SqliteDb::change_key(path, empty, tomato).ensure(); + td::SqliteDb::change_key(path, false, empty, tomato).ensure(); + td::SqliteDb::change_key(path, false, empty, tomato).ensure(); { - auto db = SqliteDb::open_with_key(path, empty).move_as_ok(); - auto kv = SqliteKeyValue(); - kv.init_with_connection(db.clone(), "kv"); + auto db = td::SqliteDb::open_with_key(path, false, empty).move_as_ok(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); CHECK(kv.get("a") == "b"); CHECK(db.user_version().ok() == 123); } - SqliteDb::open_with_key(path, cucumber).ensure_error(); + td::SqliteDb::open_with_key(path, false, cucumber).ensure_error(); + td::SqliteDb::destroy(path).ignore(); +} + +TEST(DB, sqlite_encryption_migrate_v3) { + td::string path = "test_sqlite_db"; + td::SqliteDb::destroy(path).ignore(); + auto cucumber = td::DbKey::password("cucumber"); + auto empty = td::DbKey::empty(); + if (false) { + // sqlite_sample_db was generated by the following code using SQLCipher based on SQLite 3.15.2 + { + auto db = td::SqliteDb::change_key(path, true, cucumber, empty).move_as_ok(); + db.set_user_version(123).ensure(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); + kv.set("hello", "world"); + } + LOG(ERROR) << td::base64_encode(td::read_file(path).move_as_ok()); + } + td::write_file(path, td::base64_decode(td::Slice(sqlite_sample_db_v3, sqlite_sample_db_v3_size)).move_as_ok()) + .ensure(); + { + auto db = td::SqliteDb::open_with_key(path, true, cucumber).move_as_ok(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); + CHECK(kv.get("hello") == "world"); + CHECK(db.user_version().ok() == 123); + } + td::SqliteDb::destroy(path).ignore(); +} + +TEST(DB, sqlite_encryption_migrate_v4) { + td::string path = "test_sqlite_db"; + td::SqliteDb::destroy(path).ignore(); + auto cucumber = td::DbKey::password("cucu'\"mb er"); + auto empty = td::DbKey::empty(); + if (false) { + // sqlite_sample_db was generated by the following code using SQLCipher 4.4.0 + { + auto db = td::SqliteDb::change_key(path, true, cucumber, empty).move_as_ok(); + db.set_user_version(123).ensure(); + auto kv = td::SqliteKeyValue(); + kv.init_with_connection(db.clone(), "kv").ensure(); + kv.set("hello", "world"); + } + LOG(ERROR) << td::base64_encode(td::read_file(path).move_as_ok()); + } + td::write_file(path, td::base64_decode(td::Slice(sqlite_sample_db_v4, sqlite_sample_db_v4_size)).move_as_ok()) + .ensure(); + { + auto r_db = td::SqliteDb::open_with_key(path, true, cucumber); + if (r_db.is_error()) { + LOG(ERROR) << r_db.error(); + return; + } + auto db = r_db.move_as_ok(); + auto kv = td::SqliteKeyValue(); + auto status = kv.init_with_connection(db.clone(), "kv"); + if (status.is_error()) { + LOG(ERROR) << status; + } else { + CHECK(kv.get("hello") == "world"); + CHECK(db.user_version().ok() == 123); + } + } + td::SqliteDb::destroy(path).ignore(); } -using SeqNo = uint64; +using SeqNo = td::uint64; struct DbQuery { - enum Type { Get, Set, Erase } type; + enum class Type { Get, Set, Erase } type = Type::Get; SeqNo tid = 0; - int32 id = 0; - string key; - string value; + td::int32 id = 0; + td::string key; + td::string value; }; template <class ImplT> @@ -172,13 +279,39 @@ class QueryHandler { } void do_query(DbQuery &query) { switch (query.type) { - case DbQuery::Get: + case DbQuery::Type::Get: + query.value = impl_.get(query.key); + return; + case DbQuery::Type::Set: + impl_.set(query.key, query.value); + query.tid = 1; + return; + case DbQuery::Type::Erase: + impl_.erase(query.key); + query.tid = 1; + return; + } + } + + private: + ImplT impl_; +}; + +template <class ImplT> +class SeqQueryHandler { + public: + ImplT &impl() { + return impl_; + } + void do_query(DbQuery &query) { + switch (query.type) { + case DbQuery::Type::Get: query.value = impl_.get(query.key); return; - case DbQuery::Set: + case DbQuery::Type::Set: query.tid = impl_.set(query.key, query.value); return; - case DbQuery::Erase: + case DbQuery::Type::Erase: query.tid = impl_.erase(query.key); return; } @@ -190,93 +323,93 @@ class QueryHandler { class SqliteKV { public: - string get(string key) { + td::string get(const td::string &key) { return kv_->get().get(key); } - SeqNo set(string key, string value) { + SeqNo set(const td::string &key, const td::string &value) { kv_->get().set(key, value); return 0; } - SeqNo erase(string key) { + SeqNo erase(const td::string &key) { kv_->get().erase(key); return 0; } - Status init(string name) { - auto sql_connection = std::make_shared<SqliteConnectionSafe>(name); - kv_ = std::make_shared<SqliteKeyValueSafe>("kv", sql_connection); - return Status::OK(); + td::Status init(const td::string &name) { + auto sql_connection = std::make_shared<td::SqliteConnectionSafe>(name, td::DbKey::empty()); + kv_ = std::make_shared<td::SqliteKeyValueSafe>("kv", sql_connection); + return td::Status::OK(); } void close() { kv_.reset(); } private: - std::shared_ptr<SqliteKeyValueSafe> kv_; + std::shared_ptr<td::SqliteKeyValueSafe> kv_; }; class BaselineKV { public: - string get(string key) { + td::string get(const td::string &key) { return map_[key]; } - SeqNo set(string key, string value) { - map_[key] = value; + SeqNo set(const td::string &key, td::string value) { + map_[key] = std::move(value); return ++current_tid_; } - SeqNo erase(string key) { + SeqNo erase(const td::string &key) { map_.erase(key); return ++current_tid_; } private: - std::map<string, string> map_; + std::map<td::string, td::string> map_; SeqNo current_tid_ = 0; }; TEST(DB, key_value) { - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(INFO)); - std::vector<std::string> keys; - std::vector<std::string> values; + td::vector<td::string> keys; + td::vector<td::string> values; for (int i = 0; i < 100; i++) { - keys.push_back(rand_string('a', 'b', Random::fast(1, 10))); + keys.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } - for (int i = 0; i < 1000; i++) { - values.push_back(rand_string('a', 'b', Random::fast(1, 10))); + for (int i = 0; i < 10; i++) { + values.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } - int queries_n = 300000; - std::vector<DbQuery> queries(queries_n); + int queries_n = 1000; + td::vector<DbQuery> queries(queries_n); for (auto &q : queries) { - int op = Random::fast(0, 2); + int op = td::Random::fast(0, 2); const auto &key = rand_elem(keys); const auto &value = rand_elem(values); if (op == 0) { - q.type = DbQuery::Get; + q.type = DbQuery::Type::Get; q.key = key; } else if (op == 1) { - q.type = DbQuery::Erase; + q.type = DbQuery::Type::Erase; q.key = key; } else if (op == 2) { - q.type = DbQuery::Set; + q.type = DbQuery::Type::Set; q.key = key; q.value = value; } } QueryHandler<BaselineKV> baseline; - QueryHandler<SeqKeyValue> kv; - QueryHandler<TsSeqKeyValue> ts_kv; - QueryHandler<BinlogKeyValue<Binlog>> new_kv; + QueryHandler<td::SeqKeyValue> kv; + QueryHandler<td::TsSeqKeyValue> ts_kv; + QueryHandler<td::BinlogKeyValue<td::Binlog>> new_kv; - CSlice new_kv_name = "test_new_kv"; - Binlog::destroy(new_kv_name).ignore(); + td::CSlice new_kv_name = "test_new_kv"; + td::Binlog::destroy(new_kv_name).ignore(); new_kv.impl().init(new_kv_name.str()).ensure(); - QueryHandler<SqliteKeyValue> sqlite_kv; - CSlice name = "test_sqlite_kv"; - SqliteDb::destroy(name).ignore(); - sqlite_kv.impl().init(name.str()).ensure(); + QueryHandler<td::SqliteKeyValue> sqlite_kv; + td::CSlice path = "test_sqlite_kv"; + td::SqliteDb::destroy(path).ignore(); + auto db = td::SqliteDb::open_with_key(path, true, td::DbKey::empty()).move_as_ok(); + sqlite_kv.impl().init_with_connection(std::move(db), "KV").ensure(); int cnt = 0; for (auto &q : queries) { @@ -294,41 +427,82 @@ TEST(DB, key_value) { ASSERT_EQ(a.value, c.value); ASSERT_EQ(a.value, d.value); ASSERT_EQ(a.value, e.value); - if (cnt++ % 10000 == 0) { + if (cnt++ % 200 == 0) { new_kv.impl().init(new_kv_name.str()).ensure(); } } + td::SqliteDb::destroy(path).ignore(); + td::Binlog::destroy(new_kv_name).ignore(); +} + +TEST(DB, key_value_set_all) { + td::vector<td::string> keys; + td::vector<td::string> values; + + for (int i = 0; i < 100; i++) { + keys.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); + } + for (int i = 0; i < 10; i++) { + values.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); + } + + td::SqliteKeyValue sqlite_kv; + td::CSlice sqlite_kv_name = "test_sqlite_kv"; + td::SqliteDb::destroy(sqlite_kv_name).ignore(); + auto db = td::SqliteDb::open_with_key(sqlite_kv_name, true, td::DbKey::empty()).move_as_ok(); + sqlite_kv.init_with_connection(std::move(db), "KV").ensure(); + + BaselineKV kv; + + int queries_n = 100; + while (queries_n-- > 0) { + int cnt = td::Random::fast(0, 10); + td::FlatHashMap<td::string, td::string> key_values; + for (int i = 0; i < cnt; i++) { + auto key = rand_elem(keys); + auto value = rand_elem(values); + key_values[key] = value; + kv.set(key, value); + } + + sqlite_kv.set_all(key_values); + + for (auto &key : keys) { + CHECK(kv.get(key) == sqlite_kv.get(key)); + } + } + td::SqliteDb::destroy(sqlite_kv_name).ignore(); } -TEST(DB, thread_key_value) { #if !TD_THREAD_UNSUPPORTED - std::vector<std::string> keys; - std::vector<std::string> values; +TEST(DB, thread_key_value) { + td::vector<td::string> keys; + td::vector<td::string> values; for (int i = 0; i < 100; i++) { - keys.push_back(rand_string('a', 'b', Random::fast(1, 10))); + keys.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } for (int i = 0; i < 1000; i++) { - values.push_back(rand_string('a', 'b', Random::fast(1, 10))); + values.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } int threads_n = 4; - int queries_n = 100000; + int queries_n = 10000; - std::vector<std::vector<DbQuery>> queries(threads_n, std::vector<DbQuery>(queries_n)); + td::vector<td::vector<DbQuery>> queries(threads_n, td::vector<DbQuery>(queries_n)); for (auto &qs : queries) { for (auto &q : qs) { - int op = Random::fast(0, 10); + int op = td::Random::fast(0, 10); const auto &key = rand_elem(keys); const auto &value = rand_elem(values); if (op > 1) { - q.type = DbQuery::Get; + q.type = DbQuery::Type::Get; q.key = key; } else if (op == 0) { - q.type = DbQuery::Erase; + q.type = DbQuery::Type::Erase; q.key = key; } else if (op == 1) { - q.type = DbQuery::Set; + q.type = DbQuery::Type::Set; q.key = key; q.value = value; } @@ -336,12 +510,12 @@ TEST(DB, thread_key_value) { } QueryHandler<BaselineKV> baseline; - QueryHandler<TsSeqKeyValue> ts_kv; + SeqQueryHandler<td::TsSeqKeyValue> ts_kv; - std::vector<thread> threads(threads_n); - std::vector<std::vector<DbQuery>> res(threads_n); + td::vector<td::thread> threads(threads_n); + td::vector<td::vector<DbQuery>> res(threads_n); for (int i = 0; i < threads_n; i++) { - threads[i] = thread([&ts_kv, &queries, &res, i]() { + threads[i] = td::thread([&ts_kv, &queries, &res, i] { for (auto q : queries[i]) { ts_kv.do_query(q); res[i].push_back(q); @@ -352,7 +526,7 @@ TEST(DB, thread_key_value) { thread.join(); } - std::vector<std::size_t> pos(threads_n); + td::vector<std::size_t> pos(threads_n); while (true) { bool was = false; for (int i = 0; i < threads_n; i++) { @@ -362,7 +536,7 @@ TEST(DB, thread_key_value) { } auto &q = res[i][p]; if (q.tid == 0) { - if (q.type == DbQuery::Get) { + if (q.type == DbQuery::Type::Get) { auto nq = q; baseline.do_query(nq); if (nq.value == q.value) { @@ -402,25 +576,23 @@ TEST(DB, thread_key_value) { baseline.do_query(res[best][pos[best]]); pos[best]++; } -#endif } +#endif TEST(DB, persistent_key_value) { - using KeyValue = BinlogKeyValue<ConcurrentBinlog>; - // using KeyValue = PersistentKeyValue; - // using KeyValue = SqliteKV; - SET_VERBOSITY_LEVEL(VERBOSITY_NAME(WARNING)); - std::vector<std::string> keys; - std::vector<std::string> values; - CSlice name = "test_pmc"; - Binlog::destroy(name).ignore(); - SqliteDb::destroy(name).ignore(); + using KeyValue = td::BinlogKeyValue<td::ConcurrentBinlog>; + // using KeyValue = td::SqliteKeyValue; + td::vector<td::string> keys; + td::vector<td::string> values; + td::CSlice path = "test_pmc"; + td::Binlog::destroy(path).ignore(); + td::SqliteDb::destroy(path).ignore(); for (int i = 0; i < 100; i++) { - keys.push_back(rand_string('a', 'b', Random::fast(1, 10))); + keys.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } for (int i = 0; i < 1000; i++) { - values.push_back(rand_string('a', 'b', Random::fast(1, 10))); + values.push_back(td::rand_string('a', 'b', td::Random::fast(1, 10))); } QueryHandler<BaselineKV> baseline; @@ -429,34 +601,34 @@ TEST(DB, persistent_key_value) { int threads_n = 4; int queries_n = 3000 / threads_n; - std::vector<std::vector<DbQuery>> queries(threads_n, std::vector<DbQuery>(queries_n)); + td::vector<td::vector<DbQuery>> queries(threads_n, td::vector<DbQuery>(queries_n)); for (auto &qs : queries) { for (auto &q : qs) { - int op = Random::fast(0, 10); + int op = td::Random::fast(0, 10); const auto &key = rand_elem(keys); const auto &value = rand_elem(values); if (op > 1) { - q.type = DbQuery::Get; + q.type = DbQuery::Type::Get; q.key = key; } else if (op == 0) { - q.type = DbQuery::Erase; + q.type = DbQuery::Type::Erase; q.key = key; } else if (op == 1) { - q.type = DbQuery::Set; + q.type = DbQuery::Type::Set; q.key = key; q.value = value; } } } - std::vector<std::vector<DbQuery>> res(threads_n); - class Worker : public Actor { + td::vector<td::vector<DbQuery>> res(threads_n); + class Worker final : public td::Actor { public: - Worker(ActorShared<> parent, std::shared_ptr<QueryHandler<KeyValue>> kv, const std::vector<DbQuery> *queries, - std::vector<DbQuery> *res) + Worker(td::ActorShared<> parent, std::shared_ptr<SeqQueryHandler<KeyValue>> kv, + const td::vector<DbQuery> *queries, td::vector<DbQuery> *res) : parent_(std::move(parent)), kv_(std::move(kv)), queries_(queries), res_(res) { } - void loop() override { + void loop() final { for (auto q : *queries_) { kv_->do_query(q); res_->push_back(q); @@ -465,55 +637,54 @@ TEST(DB, persistent_key_value) { } private: - ActorShared<> parent_; - std::shared_ptr<QueryHandler<KeyValue>> kv_; - const std::vector<DbQuery> *queries_; - std::vector<DbQuery> *res_; + td::ActorShared<> parent_; + std::shared_ptr<SeqQueryHandler<KeyValue>> kv_; + const td::vector<DbQuery> *queries_; + td::vector<DbQuery> *res_; }; - class Main : public Actor { + class Main final : public td::Actor { public: - Main(int threads_n, const std::vector<std::vector<DbQuery>> *queries, std::vector<std::vector<DbQuery>> *res) - : threads_n_(threads_n), queries_(queries), res_(res) { + Main(int threads_n, const td::vector<td::vector<DbQuery>> *queries, td::vector<td::vector<DbQuery>> *res) + : threads_n_(threads_n), queries_(queries), res_(res), ref_cnt_(threads_n) { } - void start_up() override { - LOG(INFO) << "start_up"; + void start_up() final { + LOG(INFO) << "Start up"; kv_->impl().init("test_pmc").ensure(); - ref_cnt_ = threads_n_; for (int i = 0; i < threads_n_; i++) { - create_actor_on_scheduler<Worker>("Worker", i + 1, actor_shared(this, 2), kv_, &queries_->at(i), &res_->at(i)) + td::create_actor_on_scheduler<Worker>("Worker", i + 1, actor_shared(this, 2), kv_, &queries_->at(i), + &res_->at(i)) .release(); } } - void tear_down() override { - LOG(INFO) << "tear_down"; + void tear_down() final { + LOG(INFO) << "Tear down"; // kv_->impl().close(); } - void hangup_shared() override { - LOG(INFO) << "hangup"; + void hangup_shared() final { + LOG(INFO) << "Hang up"; ref_cnt_--; if (ref_cnt_ == 0) { kv_->impl().close(); - Scheduler::instance()->finish(); + td::Scheduler::instance()->finish(); stop(); } } - void hangup() override { + void hangup() final { LOG(ERROR) << "BAD HANGUP"; } private: int threads_n_; - const std::vector<std::vector<DbQuery>> *queries_; - std::vector<std::vector<DbQuery>> *res_; + const td::vector<td::vector<DbQuery>> *queries_; + td::vector<td::vector<DbQuery>> *res_; - std::shared_ptr<QueryHandler<KeyValue>> kv_{new QueryHandler<KeyValue>()}; + std::shared_ptr<SeqQueryHandler<KeyValue>> kv_{new SeqQueryHandler<KeyValue>()}; int ref_cnt_; }; - ConcurrentScheduler sched; - sched.init(threads_n); + td::ConcurrentScheduler sched(threads_n, 0); sched.create_actor_unsafe<Main>(0, "Main", threads_n, &queries, &res).release(); sched.start(); while (sched.run_main(10)) { @@ -521,7 +692,7 @@ TEST(DB, persistent_key_value) { } sched.finish(); - std::vector<std::size_t> pos(threads_n); + td::vector<std::size_t> pos(threads_n); while (true) { bool was = false; for (int i = 0; i < threads_n; i++) { @@ -531,7 +702,7 @@ TEST(DB, persistent_key_value) { } auto &q = res[i][p]; if (q.tid == 0) { - if (q.type == DbQuery::Get) { + if (q.type == DbQuery::Type::Get) { auto nq = q; baseline.do_query(nq); if (nq.value == q.value) { @@ -572,4 +743,5 @@ TEST(DB, persistent_key_value) { pos[best]++; } } + td::SqliteDb::destroy(path).ignore(); } |