2019-08-05 17:50:55 +02:00
|
|
|
//
|
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
|
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
2019-08-07 13:01:22 +02:00
|
|
|
#include "td/db/binlog/Binlog.h"
|
|
|
|
#include "td/db/binlog/BinlogEvent.h"
|
|
|
|
#include "td/db/binlog/BinlogHelper.h"
|
|
|
|
#include "td/db/TQueue.h"
|
|
|
|
|
2019-08-05 17:50:55 +02:00
|
|
|
#include "td/utils/int_types.h"
|
2019-08-07 13:01:22 +02:00
|
|
|
#include "td/utils/misc.h"
|
|
|
|
#include "td/utils/port/path.h"
|
2019-08-05 17:50:55 +02:00
|
|
|
#include "td/utils/Slice.h"
|
|
|
|
#include "td/utils/Span.h"
|
2019-08-07 13:01:22 +02:00
|
|
|
#include "td/utils/Status.h"
|
2019-08-05 17:50:55 +02:00
|
|
|
#include "td/utils/tests.h"
|
2019-08-07 13:01:22 +02:00
|
|
|
#include "td/utils/VectorQueue.h"
|
|
|
|
|
2019-08-06 16:30:15 +02:00
|
|
|
#include <map>
|
|
|
|
#include <set>
|
|
|
|
|
2019-08-05 17:50:55 +02:00
|
|
|
namespace td {
|
|
|
|
|
|
|
|
TEST(TQueue, hands) {
|
2019-08-06 16:30:15 +02:00
|
|
|
TQueue::Event events[100];
|
|
|
|
auto events_span = MutableSpan<TQueue::Event>(events, 100);
|
2019-08-05 17:50:55 +02:00
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
auto tqueue = TQueue::create();
|
2019-08-05 17:50:55 +02:00
|
|
|
auto qid = 12;
|
2019-08-07 13:01:22 +02:00
|
|
|
ASSERT_EQ(true, tqueue->get_head(qid).empty());
|
|
|
|
ASSERT_EQ(true, tqueue->get_tail(qid).empty());
|
|
|
|
tqueue->push(qid, "hello", 0);
|
|
|
|
auto head = tqueue->get_head(qid);
|
|
|
|
ASSERT_EQ(head.next().ok(), tqueue->get_tail(qid));
|
|
|
|
ASSERT_EQ(1u, tqueue->get(qid, head, 0, events_span).move_as_ok());
|
2019-08-06 16:30:15 +02:00
|
|
|
}
|
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
class TestTQueue {
|
|
|
|
public:
|
|
|
|
CSlice binlog_path() {
|
|
|
|
return "test_binlog";
|
|
|
|
}
|
|
|
|
TestTQueue() {
|
2019-08-07 13:01:22 +02:00
|
|
|
baseline_ = TQueue::create();
|
|
|
|
memory_ = TQueue::create();
|
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
auto memory_storage = td::make_unique<MemoryStorage>();
|
|
|
|
memory_storage_ = memory_storage.get();
|
2019-08-07 13:01:22 +02:00
|
|
|
memory_->set_callback(std::move(memory_storage));
|
2019-08-06 20:24:28 +02:00
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
binlog_ = TQueue::create();
|
2019-08-06 20:24:28 +02:00
|
|
|
auto tqueue_binlog = make_unique<TQueueBinlog<Binlog>>();
|
|
|
|
Binlog::destroy(binlog_path()).ensure();
|
|
|
|
auto binlog = std::make_shared<Binlog>();
|
|
|
|
binlog->init(binlog_path().str(), [&](const BinlogEvent &event) { UNREACHABLE(); }).ensure();
|
|
|
|
tqueue_binlog->set_binlog(binlog);
|
2019-08-07 13:01:22 +02:00
|
|
|
binlog_->set_callback(std::move(tqueue_binlog));
|
2019-08-06 20:24:28 +02:00
|
|
|
}
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
void restart(Random::Xorshift128plus &rnd) {
|
2019-08-07 17:29:47 +02:00
|
|
|
baseline_->emulate_restart();
|
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
memory_->extract_callback().release();
|
2019-08-06 20:24:28 +02:00
|
|
|
auto memory_storage = unique_ptr<MemoryStorage>(memory_storage_);
|
2019-08-07 13:01:22 +02:00
|
|
|
memory_ = TQueue::create();
|
|
|
|
memory_storage->replay(*memory_);
|
|
|
|
memory_->set_callback(std::move(memory_storage));
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
if (rnd.fast(0, 100) != 0) {
|
2019-08-07 17:29:47 +02:00
|
|
|
binlog_->emulate_restart();
|
2019-08-06 20:24:28 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
LOG(ERROR) << "RESTART BINLOG";
|
2019-08-07 13:01:22 +02:00
|
|
|
binlog_ = TQueue::create();
|
2019-08-06 20:24:28 +02:00
|
|
|
auto tqueue_binlog = make_unique<TQueueBinlog<Binlog>>();
|
|
|
|
auto binlog = std::make_shared<Binlog>();
|
2019-08-07 13:01:22 +02:00
|
|
|
binlog->init(binlog_path().str(), [&](const BinlogEvent &event) { tqueue_binlog->replay(event, *binlog_); })
|
2019-08-06 20:24:28 +02:00
|
|
|
.ensure();
|
|
|
|
tqueue_binlog->set_binlog(binlog);
|
2019-08-07 13:01:22 +02:00
|
|
|
binlog_->set_callback(std::move(tqueue_binlog));
|
2019-08-06 20:24:28 +02:00
|
|
|
}
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
TQueue::EventId push(TQueue::QueueId queue_id, string data, double expire_at,
|
|
|
|
TQueue::EventId new_id = TQueue::EventId()) {
|
2019-08-07 17:36:37 +02:00
|
|
|
auto a_id = baseline_->push(queue_id, data, expire_at, new_id).move_as_ok();
|
|
|
|
auto b_id = memory_->push(queue_id, data, expire_at, new_id).move_as_ok();
|
|
|
|
auto c_id = binlog_->push(queue_id, data, expire_at, new_id).move_as_ok();
|
2019-08-06 20:24:28 +02:00
|
|
|
ASSERT_EQ(a_id, b_id);
|
|
|
|
ASSERT_EQ(a_id, c_id);
|
|
|
|
return a_id;
|
|
|
|
}
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
void check_head_tail(TQueue::QueueId qid) {
|
|
|
|
ASSERT_EQ(baseline_->get_head(qid), memory_->get_head(qid));
|
|
|
|
ASSERT_EQ(baseline_->get_head(qid), binlog_->get_head(qid));
|
|
|
|
ASSERT_EQ(baseline_->get_tail(qid), memory_->get_tail(qid));
|
|
|
|
ASSERT_EQ(baseline_->get_tail(qid), binlog_->get_tail(qid));
|
2019-08-06 20:24:28 +02:00
|
|
|
}
|
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
void check_get(TQueue::QueueId qid, Random::Xorshift128plus &rnd) {
|
2019-08-06 20:24:28 +02:00
|
|
|
TQueue::Event a[10];
|
|
|
|
MutableSpan<TQueue::Event> a_span(a, 10);
|
|
|
|
TQueue::Event b[10];
|
|
|
|
MutableSpan<TQueue::Event> b_span(b, 10);
|
|
|
|
TQueue::Event c[10];
|
|
|
|
MutableSpan<TQueue::Event> c_span(b, 10);
|
|
|
|
|
2019-08-07 13:01:22 +02:00
|
|
|
auto a_from = baseline_->get_head(qid);
|
|
|
|
auto b_from = memory_->get_head(qid);
|
|
|
|
auto c_from = binlog_->get_head(qid);
|
2019-08-06 16:30:15 +02:00
|
|
|
ASSERT_EQ(a_from, b_from);
|
2019-08-06 20:24:28 +02:00
|
|
|
ASSERT_EQ(a_from, c_from);
|
2019-08-06 16:30:15 +02:00
|
|
|
|
|
|
|
auto tmp = a_from.advance(rnd.fast(-10, 10));
|
|
|
|
if (tmp.is_ok()) {
|
|
|
|
a_from = tmp.move_as_ok();
|
|
|
|
}
|
2019-08-07 17:13:10 +02:00
|
|
|
baseline_->get(qid, a_from, 0, a_span).move_as_ok();
|
|
|
|
memory_->get(qid, a_from, 0, b_span).move_as_ok();
|
|
|
|
binlog_->get(qid, a_from, 0, c_span).move_as_ok();
|
|
|
|
ASSERT_EQ(a_span.size(), b_span.size());
|
|
|
|
ASSERT_EQ(a_span.size(), c_span.size());
|
|
|
|
for (size_t i = 0; i < a_span.size(); i++) {
|
2019-08-06 20:24:28 +02:00
|
|
|
ASSERT_EQ(a_span[i].id, b_span[i].id);
|
|
|
|
ASSERT_EQ(a_span[i].id, c_span[i].id);
|
|
|
|
ASSERT_EQ(a_span[i].data, b_span[i].data);
|
|
|
|
ASSERT_EQ(a_span[i].data, c_span[i].data);
|
2019-08-06 16:30:15 +02:00
|
|
|
}
|
2019-08-06 20:24:28 +02:00
|
|
|
}
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
private:
|
2019-08-07 13:01:22 +02:00
|
|
|
unique_ptr<TQueue> baseline_;
|
|
|
|
unique_ptr<TQueue> memory_;
|
|
|
|
unique_ptr<TQueue> binlog_;
|
2019-08-06 20:24:28 +02:00
|
|
|
MemoryStorage *memory_storage_{nullptr};
|
|
|
|
};
|
2019-08-06 16:30:15 +02:00
|
|
|
|
2019-08-06 20:24:28 +02:00
|
|
|
TEST(TQueue, random) {
|
2019-08-07 13:01:22 +02:00
|
|
|
using EventId = TQueue::EventId;
|
2019-08-06 20:24:28 +02:00
|
|
|
Random::Xorshift128plus rnd(123);
|
2019-08-07 13:01:22 +02:00
|
|
|
auto next_qid = [&] {
|
|
|
|
return rnd.fast(1, 10);
|
|
|
|
};
|
2019-08-06 20:24:28 +02:00
|
|
|
auto next_first_id = [&] {
|
|
|
|
if (rnd.fast(0, 3) == 0) {
|
|
|
|
return EventId::from_int32(EventId::MAX_ID - 20).move_as_ok();
|
|
|
|
}
|
|
|
|
return EventId::from_int32(rnd.fast(1000000000, 1500000000)).move_as_ok();
|
|
|
|
};
|
|
|
|
TestTQueue q;
|
|
|
|
auto push_event = [&] {
|
|
|
|
auto data = PSTRING() << rnd();
|
|
|
|
q.push(next_qid(), data, 0, next_first_id());
|
|
|
|
};
|
2019-08-07 13:01:22 +02:00
|
|
|
auto check_head_tail = [&] {
|
|
|
|
q.check_head_tail(next_qid());
|
|
|
|
};
|
|
|
|
auto restart = [&] {
|
|
|
|
q.restart(rnd);
|
|
|
|
};
|
|
|
|
auto get = [&] {
|
|
|
|
q.check_get(next_qid(), rnd);
|
|
|
|
};
|
2019-08-06 20:24:28 +02:00
|
|
|
RandomSteps steps({{push_event, 100}, {check_head_tail, 10}, {get, 40}, {restart, 1}});
|
2019-08-06 16:30:15 +02:00
|
|
|
for (int i = 0; i < 1000000; i++) {
|
|
|
|
steps.step(rnd);
|
|
|
|
}
|
2019-08-05 17:50:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace td
|