2018-12-31 20:04:05 +01:00
|
|
|
//
|
2018-01-02 14:42:31 +01:00
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
2018-12-31 20:04:05 +01:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "td/db/binlog/BinlogEvent.h"
|
|
|
|
#include "td/db/DbKey.h"
|
|
|
|
|
|
|
|
#include "td/utils/AesCtrByteFlow.h"
|
|
|
|
#include "td/utils/buffer.h"
|
|
|
|
#include "td/utils/BufferedFd.h"
|
|
|
|
#include "td/utils/ByteFlow.h"
|
|
|
|
#include "td/utils/common.h"
|
|
|
|
#include "td/utils/crypto.h"
|
|
|
|
#include "td/utils/port/FileFd.h"
|
|
|
|
#include "td/utils/Slice.h"
|
|
|
|
#include "td/utils/Status.h"
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
namespace td {
|
|
|
|
struct BinlogInfo {
|
|
|
|
bool was_created;
|
|
|
|
uint64 last_id;
|
|
|
|
bool is_encrypted{false};
|
|
|
|
bool wrong_password{false};
|
|
|
|
bool is_opened{false};
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
class BinlogReader;
|
|
|
|
class BinlogEventsProcessor;
|
|
|
|
class BinlogEventsBuffer;
|
|
|
|
}; // namespace detail
|
|
|
|
|
|
|
|
class Binlog {
|
|
|
|
public:
|
2018-03-10 15:52:27 +01:00
|
|
|
enum Error : int { WrongPassword = -1 };
|
2018-12-31 20:04:05 +01:00
|
|
|
static bool IGNORE_ERASE_HACK;
|
|
|
|
Binlog();
|
|
|
|
Binlog(const Binlog &other) = delete;
|
|
|
|
Binlog &operator=(const Binlog &other) = delete;
|
|
|
|
Binlog(Binlog &&other) = delete;
|
|
|
|
Binlog &operator=(Binlog &&other) = delete;
|
|
|
|
~Binlog();
|
|
|
|
|
|
|
|
using Callback = std::function<void(const BinlogEvent &)>;
|
|
|
|
Status init(string path, const Callback &callback, DbKey db_key = DbKey::empty(), DbKey old_db_key = DbKey::empty(),
|
|
|
|
int32 dummy = -1, const Callback &debug_callback = Callback()) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
|
|
|
uint64 next_id() {
|
|
|
|
return ++last_id_;
|
|
|
|
}
|
|
|
|
uint64 next_id(int32 shift) {
|
|
|
|
auto res = last_id_ + 1;
|
|
|
|
last_id_ += shift;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
uint64 peek_next_id() const {
|
|
|
|
return last_id_ + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const {
|
|
|
|
return fd_.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_raw_event(BufferSlice &&raw_event) {
|
|
|
|
add_event(BinlogEvent(std::move(raw_event)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void add_event(BinlogEvent &&event);
|
|
|
|
void sync();
|
|
|
|
void flush();
|
|
|
|
void lazy_flush();
|
|
|
|
double need_flush_since() const {
|
|
|
|
return need_flush_since_;
|
|
|
|
}
|
|
|
|
void change_key(DbKey new_db_key);
|
|
|
|
|
|
|
|
Status close(bool need_sync = true) TD_WARN_UNUSED_RESULT;
|
|
|
|
Status close_and_destroy() TD_WARN_UNUSED_RESULT;
|
|
|
|
static Status destroy(Slice path) TD_WARN_UNUSED_RESULT;
|
|
|
|
|
|
|
|
CSlice get_path() const {
|
|
|
|
return path_;
|
|
|
|
}
|
|
|
|
|
|
|
|
BinlogInfo get_info() const { // works even after binlog was closed
|
|
|
|
return info_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BufferedFdBase<FileFd> fd_;
|
|
|
|
ChainBufferWriter buffer_writer_;
|
|
|
|
ChainBufferReader buffer_reader_;
|
|
|
|
detail::BinlogReader *binlog_reader_ptr_;
|
|
|
|
|
|
|
|
BinlogInfo info_;
|
|
|
|
DbKey db_key_;
|
|
|
|
bool db_key_used_ = false;
|
|
|
|
DbKey old_db_key_;
|
|
|
|
enum class EncryptionType { None, AesCtr } encryption_type_ = EncryptionType::None;
|
|
|
|
|
|
|
|
// AesCtrEncryption
|
|
|
|
BufferSlice aes_ctr_key_salt_;
|
|
|
|
UInt256 aes_ctr_key_;
|
|
|
|
AesCtrState aes_ctr_state_;
|
|
|
|
|
|
|
|
bool byte_flow_flag_ = false;
|
|
|
|
ByteFlowSource byte_flow_source_;
|
|
|
|
ByteFlowSink byte_flow_sink_;
|
|
|
|
AesCtrByteFlow aes_xcode_byte_flow_;
|
|
|
|
|
|
|
|
int64 fd_size_{0};
|
|
|
|
uint64 fd_events_{0};
|
|
|
|
string path_;
|
|
|
|
std::vector<BinlogEvent> pending_events_;
|
|
|
|
std::unique_ptr<detail::BinlogEventsProcessor> processor_;
|
|
|
|
std::unique_ptr<detail::BinlogEventsBuffer> events_buffer_;
|
|
|
|
bool in_flush_events_buffer_{false};
|
|
|
|
uint64 last_id_{0};
|
|
|
|
double need_flush_since_ = 0;
|
2018-02-16 10:13:04 +01:00
|
|
|
bool need_sync_{false};
|
2018-12-31 20:04:05 +01:00
|
|
|
enum class State { Empty, Load, Reindex, Run } state_{State::Empty};
|
|
|
|
|
|
|
|
static constexpr uint32 MAX_EVENT_SIZE = 65536;
|
|
|
|
|
|
|
|
Result<FileFd> open_binlog(CSlice path, int32 flags);
|
|
|
|
size_t flush_events_buffer(bool force);
|
|
|
|
void do_add_event(BinlogEvent &&event);
|
|
|
|
void do_event(BinlogEvent &&event);
|
|
|
|
Status load_binlog(const Callback &callback, const Callback &debug_callback = Callback()) TD_WARN_UNUSED_RESULT;
|
|
|
|
void do_reindex();
|
|
|
|
|
|
|
|
void update_encryption(Slice key, Slice iv);
|
|
|
|
void reset_encryption();
|
|
|
|
void update_read_encryption();
|
|
|
|
void update_write_encryption();
|
|
|
|
};
|
|
|
|
} // namespace td
|