summaryrefslogtreecommitdiff
path: root/libs/tdlib/td/test/db.cpp
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
committeraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
commite1ec72eab6d00b3ba38e5932bc88920f103b6e4a (patch)
tree999de2725a83e30fbbf6576200525d4ef0c5fe38 /libs/tdlib/td/test/db.cpp
parentb9ce1d4d98525490ca1a38e2d9fd4f3369adb3e0 (diff)
Telegram: initial commit
- tdlib moved to telegram dir
Diffstat (limited to 'libs/tdlib/td/test/db.cpp')
-rw-r--r--libs/tdlib/td/test/db.cpp575
1 files changed, 0 insertions, 575 deletions
diff --git a/libs/tdlib/td/test/db.cpp b/libs/tdlib/td/test/db.cpp
deleted file mode 100644
index 8917dd65b8..0000000000
--- a/libs/tdlib/td/test/db.cpp
+++ /dev/null
@@ -1,575 +0,0 @@
-//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
-//
-// 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 "td/db/binlog/BinlogHelper.h"
-#include "td/db/BinlogKeyValue.h"
-#include "td/db/SeqKeyValue.h"
-#include "td/db/SqliteKeyValue.h"
-#include "td/db/SqliteKeyValueSafe.h"
-#include "td/db/TsSeqKeyValue.h"
-
-#include "td/utils/common.h"
-#include "td/utils/logging.h"
-#include "td/utils/port/FileFd.h"
-#include "td/utils/port/thread.h"
-#include "td/utils/Random.h"
-#include "td/utils/Slice.h"
-#include "td/utils/Status.h"
-#include "td/utils/tests.h"
-
-#include <limits>
-#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)];
-}
-
-TEST(DB, binlog_encryption) {
- CSlice binlog_name = "test_binlog";
- 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');
- {
- 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)));
- 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.close().ensure();
- }
-
- auto add_suffix = [&] {
- auto fd = FileFd::open(binlog_name, FileFd::Flags::Write | FileFd::Flags::Append).move_as_ok();
- fd.write("abacabadaba").ensure();
- };
-
- add_suffix();
-
- {
- std::vector<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"}));
- }
-
- add_suffix();
-
- {
- std::vector<string> v;
- LOG(INFO) << "RESTART";
- Binlog binlog;
- auto status = binlog.init(binlog_name.str(), [&](const BinlogEvent &x) { v.push_back(x.data_.str()); }, cucumber);
- CHECK(status.is_error());
- }
-
- add_suffix();
-
- {
- std::vector<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"}));
- }
-};
-
-TEST(DB, sqlite_lfs) {
- string path = "test_sqlite_db";
- SqliteDb::destroy(path).ignore();
- SqliteDb db;
- db.init(path).ensure();
- db.exec("PRAGMA journal_mode=WAL").ensure();
- db.exec("PRAGMA user_version").ensure();
-}
-
-TEST(DB, sqlite_encryption) {
- string path = "test_sqlite_db";
- SqliteDb::destroy(path).ignore();
-
- auto empty = DbKey::empty();
- auto cucumber = DbKey::password("cucumber");
- auto tomato = DbKey::raw_key(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");
- kv.set("a", "b");
- }
- SqliteDb::open_with_key(path, cucumber).ensure_error(); // key was set...
-
- SqliteDb::change_key(path, cucumber, empty).ensure();
-
- SqliteDb::open_with_key(path, tomato).ensure_error();
- {
- auto db = SqliteDb::open_with_key(path, cucumber).move_as_ok();
- auto kv = SqliteKeyValue();
- kv.init_with_connection(db.clone(), "kv");
- 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();
-
- SqliteDb::open_with_key(path, cucumber).ensure_error();
- {
- auto db = SqliteDb::open_with_key(path, tomato).move_as_ok();
- auto kv = SqliteKeyValue();
- kv.init_with_connection(db.clone(), "kv");
- 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();
-
- {
- auto db = SqliteDb::open_with_key(path, empty).move_as_ok();
- auto kv = SqliteKeyValue();
- kv.init_with_connection(db.clone(), "kv");
- CHECK(kv.get("a") == "b");
- CHECK(db.user_version().ok() == 123);
- }
- SqliteDb::open_with_key(path, cucumber).ensure_error();
-}
-
-using SeqNo = uint64;
-struct DbQuery {
- enum Type { Get, Set, Erase } type;
- SeqNo tid = 0;
- int32 id = 0;
- string key;
- string value;
-};
-
-template <class ImplT>
-class QueryHandler {
- public:
- ImplT &impl() {
- return impl_;
- }
- void do_query(DbQuery &query) {
- switch (query.type) {
- case DbQuery::Get:
- query.value = impl_.get(query.key);
- return;
- case DbQuery::Set:
- query.tid = impl_.set(query.key, query.value);
- return;
- case DbQuery::Erase:
- query.tid = impl_.erase(query.key);
- return;
- }
- }
-
- private:
- ImplT impl_;
-};
-
-class SqliteKV {
- public:
- string get(string key) {
- return kv_->get().get(key);
- }
- SeqNo set(string key, string value) {
- kv_->get().set(key, value);
- return 0;
- }
- SeqNo erase(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();
- }
- void close() {
- kv_.reset();
- }
-
- private:
- std::shared_ptr<SqliteKeyValueSafe> kv_;
-};
-
-class BaselineKV {
- public:
- string get(string key) {
- return map_[key];
- }
- SeqNo set(string key, string value) {
- map_[key] = value;
- return ++current_tid_;
- }
- SeqNo erase(string key) {
- map_.erase(key);
- return ++current_tid_;
- }
-
- private:
- std::map<string, 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;
-
- for (int i = 0; i < 100; i++) {
- keys.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
- for (int i = 0; i < 1000; i++) {
- values.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
-
- int queries_n = 300000;
- std::vector<DbQuery> queries(queries_n);
- for (auto &q : queries) {
- int op = Random::fast(0, 2);
- const auto &key = rand_elem(keys);
- const auto &value = rand_elem(values);
- if (op == 0) {
- q.type = DbQuery::Get;
- q.key = key;
- } else if (op == 1) {
- q.type = DbQuery::Erase;
- q.key = key;
- } else if (op == 2) {
- q.type = DbQuery::Set;
- q.key = key;
- q.value = value;
- }
- }
-
- QueryHandler<BaselineKV> baseline;
- QueryHandler<SeqKeyValue> kv;
- QueryHandler<TsSeqKeyValue> ts_kv;
- QueryHandler<BinlogKeyValue<Binlog>> new_kv;
-
- CSlice new_kv_name = "test_new_kv";
- 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();
-
- int cnt = 0;
- for (auto &q : queries) {
- DbQuery a = q;
- DbQuery b = q;
- DbQuery c = q;
- DbQuery d = q;
- DbQuery e = q;
- baseline.do_query(a);
- kv.do_query(b);
- ts_kv.do_query(c);
- sqlite_kv.do_query(d);
- new_kv.do_query(e);
- ASSERT_EQ(a.value, b.value);
- ASSERT_EQ(a.value, c.value);
- ASSERT_EQ(a.value, d.value);
- ASSERT_EQ(a.value, e.value);
- if (cnt++ % 10000 == 0) {
- new_kv.impl().init(new_kv_name.str()).ensure();
- }
- }
-}
-
-TEST(DB, thread_key_value) {
-#if !TD_THREAD_UNSUPPORTED
- std::vector<std::string> keys;
- std::vector<std::string> values;
-
- for (int i = 0; i < 100; i++) {
- keys.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
- for (int i = 0; i < 1000; i++) {
- values.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
-
- int threads_n = 4;
- int queries_n = 100000;
-
- std::vector<std::vector<DbQuery>> queries(threads_n, std::vector<DbQuery>(queries_n));
- for (auto &qs : queries) {
- for (auto &q : qs) {
- int op = Random::fast(0, 10);
- const auto &key = rand_elem(keys);
- const auto &value = rand_elem(values);
- if (op > 1) {
- q.type = DbQuery::Get;
- q.key = key;
- } else if (op == 0) {
- q.type = DbQuery::Erase;
- q.key = key;
- } else if (op == 1) {
- q.type = DbQuery::Set;
- q.key = key;
- q.value = value;
- }
- }
- }
-
- QueryHandler<BaselineKV> baseline;
- QueryHandler<TsSeqKeyValue> ts_kv;
-
- std::vector<thread> threads(threads_n);
- std::vector<std::vector<DbQuery>> res(threads_n);
- for (int i = 0; i < threads_n; i++) {
- threads[i] = thread([&ts_kv, &queries, &res, i]() {
- for (auto q : queries[i]) {
- ts_kv.do_query(q);
- res[i].push_back(q);
- }
- });
- }
- for (auto &thread : threads) {
- thread.join();
- }
-
- std::vector<std::size_t> pos(threads_n);
- while (true) {
- bool was = false;
- for (int i = 0; i < threads_n; i++) {
- auto p = pos[i];
- if (p == res[i].size()) {
- continue;
- }
- auto &q = res[i][p];
- if (q.tid == 0) {
- if (q.type == DbQuery::Get) {
- auto nq = q;
- baseline.do_query(nq);
- if (nq.value == q.value) {
- was = true;
- pos[i]++;
- }
- } else {
- was = true;
- pos[i]++;
- }
- }
- }
- if (was) {
- continue;
- }
-
- int best = -1;
- SeqNo best_tid = 0;
- for (int i = 0; i < threads_n; i++) {
- auto p = pos[i];
- if (p == res[i].size()) {
- continue;
- }
- was = true;
- auto &q = res[i][p];
- if (q.tid != 0) {
- if (best == -1 || q.tid < best_tid) {
- best = i;
- best_tid = q.tid;
- }
- }
- }
- if (!was) {
- break;
- }
- ASSERT_TRUE(best != -1);
- baseline.do_query(res[best][pos[best]]);
- pos[best]++;
- }
-#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();
-
- for (int i = 0; i < 100; i++) {
- keys.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
- for (int i = 0; i < 1000; i++) {
- values.push_back(rand_string('a', 'b', Random::fast(1, 10)));
- }
-
- QueryHandler<BaselineKV> baseline;
-
- for (int iter = 0; iter < 25; iter++) {
- int threads_n = 4;
- int queries_n = 3000 / threads_n;
-
- std::vector<std::vector<DbQuery>> queries(threads_n, std::vector<DbQuery>(queries_n));
- for (auto &qs : queries) {
- for (auto &q : qs) {
- int op = Random::fast(0, 10);
- const auto &key = rand_elem(keys);
- const auto &value = rand_elem(values);
- if (op > 1) {
- q.type = DbQuery::Get;
- q.key = key;
- } else if (op == 0) {
- q.type = DbQuery::Erase;
- q.key = key;
- } else if (op == 1) {
- q.type = DbQuery::Set;
- q.key = key;
- q.value = value;
- }
- }
- }
-
- std::vector<std::vector<DbQuery>> res(threads_n);
- class Worker : public Actor {
- public:
- Worker(ActorShared<> parent, std::shared_ptr<QueryHandler<KeyValue>> kv, const std::vector<DbQuery> *queries,
- std::vector<DbQuery> *res)
- : parent_(std::move(parent)), kv_(std::move(kv)), queries_(queries), res_(res) {
- }
- void loop() override {
- for (auto q : *queries_) {
- kv_->do_query(q);
- res_->push_back(q);
- }
- stop();
- }
-
- private:
- ActorShared<> parent_;
- std::shared_ptr<QueryHandler<KeyValue>> kv_;
- const std::vector<DbQuery> *queries_;
- std::vector<DbQuery> *res_;
- };
- class Main : public 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) {
- }
-
- void start_up() override {
- 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))
- .release();
- }
- }
-
- void tear_down() override {
- LOG(INFO) << "tear_down";
- // kv_->impl().close();
- }
- void hangup_shared() override {
- LOG(INFO) << "hangup";
- ref_cnt_--;
- if (ref_cnt_ == 0) {
- kv_->impl().close();
- Scheduler::instance()->finish();
- stop();
- }
- }
- void hangup() override {
- LOG(ERROR) << "BAD HANGUP";
- }
-
- private:
- int threads_n_;
- const std::vector<std::vector<DbQuery>> *queries_;
- std::vector<std::vector<DbQuery>> *res_;
-
- std::shared_ptr<QueryHandler<KeyValue>> kv_{new QueryHandler<KeyValue>()};
- int ref_cnt_;
- };
-
- ConcurrentScheduler sched;
- sched.init(threads_n);
- sched.create_actor_unsafe<Main>(0, "Main", threads_n, &queries, &res).release();
- sched.start();
- while (sched.run_main(10)) {
- // empty
- }
- sched.finish();
-
- std::vector<std::size_t> pos(threads_n);
- while (true) {
- bool was = false;
- for (int i = 0; i < threads_n; i++) {
- auto p = pos[i];
- if (p == res[i].size()) {
- continue;
- }
- auto &q = res[i][p];
- if (q.tid == 0) {
- if (q.type == DbQuery::Get) {
- auto nq = q;
- baseline.do_query(nq);
- if (nq.value == q.value) {
- was = true;
- pos[i]++;
- }
- } else {
- was = true;
- pos[i]++;
- }
- }
- }
- if (was) {
- continue;
- }
-
- int best = -1;
- SeqNo best_tid = 0;
- for (int i = 0; i < threads_n; i++) {
- auto p = pos[i];
- if (p == res[i].size()) {
- continue;
- }
- was = true;
- auto &q = res[i][p];
- if (q.tid != 0) {
- if (best == -1 || q.tid < best_tid) {
- best = i;
- best_tid = q.tid;
- }
- }
- }
- if (!was) {
- break;
- }
- ASSERT_TRUE(best != -1);
- baseline.do_query(res[best][pos[best]]);
- pos[best]++;
- }
- }
-}