Files
oceanbase/src/storage/multi_data_source/mds_table_base.h
2023-08-17 12:19:21 +00:00

314 lines
12 KiB
C++

/**
* Copyright (c) 2023 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_BASE_H
#define STORAGE_MULTI_DATA_SOURCE_MDS_TABLE_BASE_H
#include "lib/container/ob_array.h"
#include "lib/ob_define.h"
#include "lib/profile/ob_trace_id.h"
#include "storage/checkpoint/ob_common_checkpoint.h"
#include "lib/function/ob_function.h"
#include "runtime_utility/mds_lock.h"
#include "storage/multi_data_source/mds_table_mgr.h"
#include "observer/virtual_table/ob_mds_event_buffer.h"
#include "storage/multi_data_source/runtime_utility/list_helper.h"
namespace oceanbase
{
namespace share
{
class SCN;
}
namespace storage
{
class ObTabletPointer;
namespace mds
{
template <typename K, typename V>
class MdsRow;
template <typename K, typename V>
class MdsUnit;
template <typename K, typename V>
class UserMdsNode;
class MdsNode;
class MdsCtx;
class MdsWriter;
class MdsDumpKV;
class MdsNodeInfoForVirtualTable;
enum class MdsTableType {
LS_INNER_TABLE = 1,
NORMAL_TABLE = 2,
UNKNOWN = 3,
};
struct ObMdsGlobalSequencer
{
static int64_t generate_senquence() { return ATOMIC_AAF(&get_instance().sequence_, 1); }
static ObMdsGlobalSequencer &get_instance() {
static ObMdsGlobalSequencer instance;
return instance;
}
private:
ObMdsGlobalSequencer() : sequence_(0) {}
int64_t sequence_;
};
class MdsTableBase : public ListNode<MdsTableBase>
{
template <typename K, typename V>
friend class MdsRow;
template <typename K, typename V>
friend class MdsUnit;
friend class MdsNode;
template <typename K, typename V>
friend class UserMdsNode;
protected:
enum State : uint8_t {
UNKNOWN = 0,
INIT,
WRITTING,// replay or set
END,
};
const char *state_to_string(State state) const {
switch (state) {
case State::UNKNOWN: return "UNKNOWN";
case State::INIT: return "INIT";
case State::WRITTING: return "WRITTING";
default: return "UNEXPECTED";
}
}
static constexpr bool StateChecker[static_cast<int>(State::END)][static_cast<int>(State::END)] = {
{0, 1, 0},// from UNKNOWN, only allowed to switch to INIT
{0, 0, 1},// from INIT, allowed to switch to WRITTING
{0, 0, 1},// from WRITTING, not allowed to switch to any state
};
int advance_state_to(State new_state) const;
public:
MdsTableBase()
: state_(State::UNKNOWN),
ls_id_(),
tablet_id_(),
flushing_scn_(),
last_inner_recycled_scn_(share::SCN::min_scn()),
rec_scn_(share::SCN::max_scn()),
total_node_cnt_(0),
construct_sequence_(0),
lock_() { construct_sequence_ = ObMdsGlobalSequencer::generate_senquence(); }
virtual ~MdsTableBase() {}
int init(const ObTabletID tablet_id,
const share::ObLSID ls_id,
ObTabletPointer *pointer,
ObMdsTableMgr *p_mgr);
virtual int set(int64_t unit_id,
void *key,
void *data,
bool is_rvalue,
MdsCtx &ctx,
const int64_t lock_timeout_us) = 0;
virtual int replay(int64_t unit_id,
void *key,
void *data,
bool is_rvalue,
MdsCtx &ctx,
const share::SCN &scn) = 0;
virtual int remove(int64_t unit_id,
void *key,
MdsCtx &ctx,
const int64_t lock_timeout_us) = 0;
virtual int replay_remove(int64_t unit_id,
void *key,
MdsCtx &ctx,
const share::SCN &scn) = 0;
virtual int get_latest(int64_t unit_id,
void *key,
ObFunction<int(void *)> &op,
bool &is_committed,
const int64_t read_seq) const = 0;
virtual int get_snapshot(int64_t unit_id,
void *key,
ObFunction<int(void *)> &op,
const share::SCN &snapshot,
const int64_t read_seq,
const int64_t timeout_us) const = 0;
virtual int get_by_writer(int64_t unit_id,
void *key,
ObFunction<int(void *)> &op,
const MdsWriter &writer,
const share::SCN &snapshot,
const int64_t read_seq,
const int64_t timeout_us) const = 0;
virtual int is_locked_by_others(int64_t unit_id,
void *key,
bool &is_locked,
const MdsWriter &self) const = 0;
virtual int for_each_unit_from_small_key_to_big_from_old_node_to_new_to_dump(
ObFunction<int(const MdsDumpKV&)> &for_each_op,
const int64_t mds_construct_sequence,
const bool for_flush) const = 0;
virtual void on_flush(const share::SCN &flushed_scn, const int flush_ret) = 0;
virtual int try_recycle(const share::SCN recycle_scn) = 0;
share::ObLSID get_ls_id() const;
int64_t get_node_cnt() const;
virtual share::SCN get_rec_scn();
virtual int operate(const ObFunction<int(MdsTableBase &)> &operation) = 0;
virtual int flush(share::SCN need_advanced_rec_scn_lower_limit) = 0;
virtual ObTabletID get_tablet_id() const;
virtual bool is_flushing() const;
virtual int fill_virtual_info(ObIArray<MdsNodeInfoForVirtualTable> &mds_node_info_array) const = 0;
virtual int forcely_reset_mds_table(const char *reason) = 0;
void mark_removed_from_t3m(ObTabletPointer *pointer);// need called in del tablet phase
void mark_switched_to_empty_shell();
bool is_switched_to_empty_shell() const;
bool is_removed_from_t3m() const;
int64_t get_removed_from_t3m_ts() const;
VIRTUAL_TO_STRING_KV(KP(this));
protected:
void inc_valid_node_cnt();
void dec_valid_node_cnt();
void try_advance_rec_scn(const share::SCN scn);
void try_decline_rec_scn(const share::SCN scn);
int get_ls_max_consequent_callbacked_scn_(share::SCN &max_consequent_callbacked_scn) const;
int register_to_mds_table_mgr();
int unregister_from_mds_table_mgr();// call when marked deleted or released directly
int unregister_from_removed_recorder();// call when marked deleted
int merge(const int64_t construct_sequence, const share::SCN &flushing_scn);
template <int N>
void report_rec_scn_event_(const char (&event_str)[N],
share::SCN old_scn,
share::SCN new_scn,
const char *file = __builtin_FILE(),
const uint32_t line = __builtin_LINE(),
const char *function_name = __builtin_FUNCTION()) {
int ret = OB_SUCCESS;
observer::MdsEvent event;
constexpr int64_t buffer_size = 1_KB;
char stack_buffer[buffer_size] = { 0 };
int64_t pos = 0;
if (FALSE_IT(databuff_printf(stack_buffer, buffer_size, pos, "%s -> %s", to_cstring(old_scn), to_cstring(new_scn)))) {
} else {
event.record_thread_info_();
event.info_str_.assign(stack_buffer, pos);
event.event_ = event_str;
observer::MdsEventKey key(MTL_ID(),
ls_id_,
tablet_id_);
observer::ObMdsEventBuffer::append(key, event, file, line, function_name);
}
}
template <int N>
void report_flush_event_(const char (&event_str)[N],
share::SCN flush_scn,
const char *file = __builtin_FILE(),
const uint32_t line = __builtin_LINE(),
const char *function_name = __builtin_FUNCTION()) {
int ret = OB_SUCCESS;
observer::MdsEvent event;
constexpr int64_t buffer_size = 1_KB;
char stack_buffer[buffer_size] = { 0 };
int64_t pos = 0;
if (FALSE_IT(databuff_printf(stack_buffer, buffer_size, pos,
"flush_scn:%s", to_cstring(flush_scn)))) {
} else {
event.record_thread_info_();
event.info_str_.assign(stack_buffer, pos);
event.event_ = event_str;
observer::MdsEventKey key(MTL_ID(),
ls_id_,
tablet_id_);
observer::ObMdsEventBuffer::append(key, event, file, line, function_name);
}
}
template <int N>
void report_on_flush_event_(const char (&event_str)[N],
share::SCN flush_scn,
const char *file = __builtin_FILE(),
const uint32_t line = __builtin_LINE(),
const char *function_name = __builtin_FUNCTION()) {
int ret = OB_SUCCESS;
observer::MdsEvent event;
constexpr int64_t buffer_size = 1_KB;
char stack_buffer[buffer_size] = { 0 };
int64_t pos = 0;
if (FALSE_IT(databuff_printf(stack_buffer, buffer_size, pos,
"flush_scn:%s", to_cstring(flush_scn)))) {
} else {
event.record_thread_info_();
event.info_str_.assign(stack_buffer, pos);
event.event_ = event_str;
observer::MdsEventKey key(MTL_ID(),
ls_id_,
tablet_id_);
observer::ObMdsEventBuffer::append(key, event, file, line, function_name);
}
}
void report_recycle_event_(share::SCN recycle_scn,
const char *file = __builtin_FILE(),
const uint32_t line = __builtin_LINE(),
const char *function_name = __builtin_FUNCTION()) {
int ret = OB_SUCCESS;
observer::MdsEvent event;
constexpr int64_t buffer_size = 1_KB;
char stack_buffer[buffer_size] = { 0 };
int64_t pos = 0;
if (FALSE_IT(databuff_printf(stack_buffer, buffer_size, pos, "recycle_scn:%s", to_cstring(recycle_scn)))) {
} else {
event.record_thread_info_();
event.info_str_.assign(stack_buffer, pos);
event.event_ = "RECYCLE";
observer::MdsEventKey key(MTL_ID(),
ls_id_,
tablet_id_);
observer::ObMdsEventBuffer::append(key, event, file, line, function_name);
}
}
protected:
struct DebugInfo {
DebugInfo()
: do_init_tablet_pointer_(nullptr),
do_remove_tablet_pointer_(nullptr),
init_ts_(0),
last_reset_ts_(0),
remove_ts_(0),
switch_to_empty_shell_ts_(0),
last_flush_ts_(0),
init_trace_id_(),
remove_trace_id_() {}
TO_STRING_KV(KP_(do_init_tablet_pointer), KP_(do_remove_tablet_pointer), KTIME_(init_ts), KTIME_(last_reset_ts),
KTIME_(remove_ts), KTIME_(last_flush_ts), KTIME_(switch_to_empty_shell_ts), K_(init_trace_id), K_(remove_trace_id));
ObTabletPointer *do_init_tablet_pointer_;// can not be accessed, just record it to debug
ObTabletPointer *do_remove_tablet_pointer_;// can not be accessed, just record it to debug
int64_t init_ts_;
int64_t last_reset_ts_;
int64_t remove_ts_;
int64_t switch_to_empty_shell_ts_;
int64_t last_flush_ts_;
ObCurTraceId::TraceId init_trace_id_;
ObCurTraceId::TraceId remove_trace_id_;
} debug_info_;// 120B
mutable State state_;
share::ObLSID ls_id_;
ObTabletID tablet_id_;
share::SCN flushing_scn_;// To tell if this mds table is flushing
share::SCN last_inner_recycled_scn_;// To filter repeated release operation
share::SCN rec_scn_;// To CLOG to recycle
int64_t total_node_cnt_;// To tell if this mds table is safety to destroy
int64_t construct_sequence_;// To filter invalid dump DAG
MdsTableMgrHandle mgr_handle_;
mutable MdsLock lock_;
};
bool check_node_scn_beflow_flush(const MdsNode &node, const share::SCN &flush_scn);
}
}
}
#endif