[FEAT MERGE] Implement Resource Throttle
This commit is contained in:
@ -13,8 +13,9 @@
|
||||
#define USING_LOG_PREFIX STORAGE
|
||||
|
||||
#include "storage/ob_storage_table_guard.h"
|
||||
#include "share/allocator/ob_memstore_allocator_mgr.h"
|
||||
#include "share/allocator/ob_shared_memory_allocator_mgr.h"
|
||||
#include "share/throttle/ob_throttle_common.h"
|
||||
#include "share/throttle/ob_share_throttle_define.h"
|
||||
#include "storage/memtable/ob_memtable.h"
|
||||
#include "storage/ob_i_table.h"
|
||||
#include "storage/ob_relative_table.h"
|
||||
@ -47,116 +48,121 @@ ObStorageTableGuard::ObStorageTableGuard(
|
||||
for_multi_source_data_(for_multi_source_data)
|
||||
{
|
||||
init_ts_ = ObTimeUtility::current_time();
|
||||
get_thread_alloc_stat() = 0;
|
||||
share::memstore_throttled_alloc() = 0;
|
||||
}
|
||||
|
||||
ObStorageTableGuard::~ObStorageTableGuard()
|
||||
{
|
||||
bool &need_speed_limit = tl_need_speed_limit();
|
||||
ObThrottleStat &stat = get_throttle_stat();
|
||||
int64_t total_expected_wait_us = 0;
|
||||
int64_t user_timeout_skip_us = 0;
|
||||
int64_t frozen_memtable_skip_us = 0;
|
||||
int64_t replay_frozen_skip_us = 0;
|
||||
int64_t from_user_skip_us = 0; // does not used now
|
||||
if (need_control_mem_ && need_speed_limit) {
|
||||
bool need_sleep = true;
|
||||
int64_t left_interval = INT64_MAX;
|
||||
if (!for_replay_) {
|
||||
left_interval = min(left_interval, store_ctx_.timeout_ - ObTimeUtility::current_time());
|
||||
}
|
||||
if (NULL != memtable_) {
|
||||
need_sleep = memtable_->is_active_memtable();
|
||||
}
|
||||
uint64_t timeout = 10000;//10s
|
||||
common::ObWaitEventGuard wait_guard(common::ObWaitEventIds::MEMSTORE_MEM_PAGE_ALLOC_WAIT, timeout, 0, 0, left_interval);
|
||||
|
||||
reset();
|
||||
int ret = OB_SUCCESS;
|
||||
int tmp_ret = OB_SUCCESS;
|
||||
bool has_sleep = false;
|
||||
int64_t sleep_time = 0;
|
||||
int time = 0;
|
||||
const int64_t &seq = get_seq();
|
||||
int64_t clock = 0;
|
||||
ObGMemstoreAllocator* memstore_allocator = NULL;
|
||||
if (OB_SUCCESS != (tmp_ret = ObMemstoreAllocatorMgr::get_instance().get_tenant_memstore_allocator(
|
||||
MTL_ID(), memstore_allocator))) {
|
||||
} else if (OB_ISNULL(memstore_allocator)) {
|
||||
LOG_WARN_RET(OB_ALLOCATE_MEMORY_FAILED, "get_tenant_mutil_allocator failed", K(store_ctx_.tablet_id_), K(tmp_ret));
|
||||
} else {
|
||||
clock = memstore_allocator->get_clock();
|
||||
total_expected_wait_us = memstore_allocator->expected_wait_time(seq);
|
||||
user_timeout_skip_us = max(0, total_expected_wait_us - left_interval);
|
||||
frozen_memtable_skip_us = need_sleep ? 0 : max(0, total_expected_wait_us - user_timeout_skip_us);
|
||||
while (need_sleep &&
|
||||
!memstore_allocator->check_clock_over_seq(seq) &&
|
||||
(left_interval > 0)) {
|
||||
if (for_replay_) {
|
||||
if(MTL(ObTenantFreezer *)->exist_ls_freezing()) {
|
||||
replay_frozen_skip_us = max(0, total_expected_wait_us - user_timeout_skip_us - sleep_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
int64_t expected_wait_time = memstore_allocator->expected_wait_time(seq);
|
||||
if (expected_wait_time < 0) {
|
||||
LOG_ERROR("expected wait time should not smaller than 0", K(expected_wait_time), K(seq), K(clock), K(left_interval));
|
||||
}
|
||||
if (expected_wait_time <= 0) {
|
||||
break;
|
||||
}
|
||||
int64_t sleep_interval = min(min(left_interval, SLEEP_INTERVAL_PER_TIME), expected_wait_time);
|
||||
// don't use ob_usleep, as we are already in the scope of 'wait_guard'
|
||||
if (sleep_interval < 0) {
|
||||
LOG_ERROR("sleep interval should not smaller than 0", K(expected_wait_time), K(seq), K(clock), K(left_interval));
|
||||
}
|
||||
if (sleep_interval > 10 * 60 * 1000 * 1000L) {
|
||||
LOG_WARN("sleep interval greater than 10 minutes, pay attention", K(expected_wait_time), K(seq), K(clock), K(left_interval));
|
||||
}
|
||||
if (sleep_interval <= 0) {
|
||||
break;
|
||||
}
|
||||
::usleep(sleep_interval);
|
||||
sleep_time += sleep_interval;
|
||||
time++;
|
||||
left_interval -= sleep_interval;
|
||||
has_sleep = true;
|
||||
need_sleep = memstore_allocator->need_do_writing_throttle();
|
||||
}
|
||||
const int64_t finish_clock = memstore_allocator->get_clock();
|
||||
if (finish_clock < seq) { // we has skip some time, need make the clock skip too.
|
||||
const int64_t skip_clock = MIN(seq - finish_clock, get_thread_alloc_stat());
|
||||
memstore_allocator->skip_clock(skip_clock);
|
||||
}
|
||||
}
|
||||
|
||||
if (REACH_TIME_INTERVAL(100 * 1000L) &&
|
||||
sleep_time > 0) {
|
||||
int64_t cost_time = ObTimeUtility::current_time() - init_ts_;
|
||||
LOG_INFO("throttle situation", K(sleep_time), K(clock), K(time), K(seq), K(for_replay_), K(cost_time));
|
||||
}
|
||||
|
||||
if (for_replay_ && has_sleep) {
|
||||
// avoid print replay_timeout
|
||||
get_replay_is_writing_throttling() = true;
|
||||
}
|
||||
}
|
||||
(void)throttle_if_needed_();
|
||||
reset();
|
||||
stat.update(total_expected_wait_us,
|
||||
from_user_skip_us,
|
||||
user_timeout_skip_us,
|
||||
frozen_memtable_skip_us,
|
||||
replay_frozen_skip_us);
|
||||
const bool last_throttle_status = stat.last_throttle_status;
|
||||
const int64_t last_print_log_time = stat.last_log_timestamp;
|
||||
if (stat.need_log(need_speed_limit)) {
|
||||
LOG_INFO("throttle statics", K(need_speed_limit), K(last_throttle_status), K(last_print_log_time), K(stat));
|
||||
if (!need_speed_limit && last_throttle_status) {
|
||||
stat.reset();
|
||||
}
|
||||
|
||||
void ObStorageTableGuard::throttle_if_needed_()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (!need_control_mem_) {
|
||||
// skip throttle
|
||||
} else {
|
||||
TxShareThrottleTool &throttle_tool = MTL(ObSharedMemAllocMgr *)->share_resource_throttle_tool();
|
||||
ObThrottleInfoGuard share_ti_guard;
|
||||
ObThrottleInfoGuard module_ti_guard;
|
||||
int64_t thread_idx = common::get_itid();
|
||||
if (throttle_tool.is_throttling<ObMemstoreAllocator>(share_ti_guard, module_ti_guard)) {
|
||||
|
||||
// only do throttle on active memtable
|
||||
if (OB_NOT_NULL(memtable_) && memtable_->is_active_memtable()) {
|
||||
reset();
|
||||
(void)do_throttle_(throttle_tool, share_ti_guard, module_ti_guard);
|
||||
}
|
||||
|
||||
// if throttle is skipped due to some reasons, advance clock by call skip_throttle() and clean throttle status
|
||||
// record in throttle info
|
||||
if (throttle_tool.still_throttling<ObMemstoreAllocator>(share_ti_guard, module_ti_guard)){
|
||||
int64_t skip_size = share::memstore_throttled_alloc();
|
||||
(void)throttle_tool.skip_throttle<ObMemstoreAllocator>(skip_size, share_ti_guard, module_ti_guard);
|
||||
|
||||
if (OB_NOT_NULL(module_ti_guard.throttle_info())) {
|
||||
module_ti_guard.throttle_info()->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define PRINT_THROTTLE_WARN \
|
||||
do { \
|
||||
const int64_t WARN_LOG_INTERVAL = 60L * 1000L * 1000L /* one minute */; \
|
||||
if (sleep_time > (WARN_LOG_INTERVAL) && TC_REACH_TIME_INTERVAL(WARN_LOG_INTERVAL)) { \
|
||||
SHARE_LOG(WARN, \
|
||||
"[Throttling] Attention!! Sleep More Than One Minute!!", \
|
||||
K(sleep_time), \
|
||||
K(left_interval), \
|
||||
K(expected_wait_time)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PRINT_THROTTLE_STATISTIC \
|
||||
do { \
|
||||
const int64_t MEMSTORE_THROTTLE_LOG_INTERVAL = 1L * 1000L * 1000L; /*one seconds*/ \
|
||||
if (sleep_time > 0 && REACH_TIME_INTERVAL(MEMSTORE_THROTTLE_LOG_INTERVAL)) { \
|
||||
SHARE_LOG(INFO, \
|
||||
"[Throttling] Time Info", \
|
||||
"Throttle Unit Name", \
|
||||
ObMemstoreAllocator::throttle_unit_name(), \
|
||||
"Throttle Sleep Time(us)", \
|
||||
sleep_time); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
void ObStorageTableGuard::do_throttle_(TxShareThrottleTool &throttle_tool,
|
||||
ObThrottleInfoGuard &share_ti_guard,
|
||||
ObThrottleInfoGuard &module_ti_guard)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t sleep_time = 0;
|
||||
int64_t left_interval = INT64_MAX;
|
||||
|
||||
if (!for_replay_) {
|
||||
left_interval = min(left_interval, store_ctx_.timeout_ - ObClockGenerator::getCurrentTime());
|
||||
}
|
||||
|
||||
while (throttle_tool.still_throttling<ObMemstoreAllocator>(share_ti_guard, module_ti_guard) && (left_interval > 0)) {
|
||||
int64_t expected_wait_time = 0;
|
||||
if (for_replay_ && MTL(ObTenantFreezer *)->exist_ls_freezing()) {
|
||||
// skip throttle if ls freeze exists
|
||||
break;
|
||||
} else if ((expected_wait_time =
|
||||
throttle_tool.expected_wait_time<ObMemstoreAllocator>(share_ti_guard, module_ti_guard)) <= 0) {
|
||||
if (expected_wait_time < 0) {
|
||||
LOG_ERROR("expected wait time should not smaller than 0",
|
||||
K(expected_wait_time),
|
||||
KPC(share_ti_guard.throttle_info()),
|
||||
KPC(module_ti_guard.throttle_info()),
|
||||
K(clock),
|
||||
K(left_interval));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// do sleep when expected_wait_time and left_interval are not equal to 0
|
||||
int64_t sleep_interval = min(SLEEP_INTERVAL_PER_TIME, expected_wait_time);
|
||||
::usleep(sleep_interval);
|
||||
sleep_time += sleep_interval;
|
||||
left_interval -= sleep_interval;
|
||||
|
||||
PRINT_THROTTLE_WARN;
|
||||
}
|
||||
PRINT_THROTTLE_STATISTIC;
|
||||
|
||||
if (for_replay_ && sleep_time > 0) {
|
||||
// avoid print replay_timeout
|
||||
get_replay_is_writing_throttling() = true;
|
||||
}
|
||||
}
|
||||
|
||||
#undef PRINT_THROTTLE_WARN
|
||||
#undef PRINT_THROTTLE_STATISTIC
|
||||
|
||||
int ObStorageTableGuard::refresh_and_protect_table(ObRelativeTable &relative_table)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
@ -264,6 +270,7 @@ void ObStorageTableGuard::reset()
|
||||
memtable_->dec_write_ref();
|
||||
memtable_ = NULL;
|
||||
}
|
||||
share::memstore_throttled_alloc() = 0;
|
||||
}
|
||||
|
||||
void ObStorageTableGuard::double_check_inc_write_ref(
|
||||
|
||||
Reference in New Issue
Block a user