[FEAT MERGE] IO_Scheduler_v2
Co-authored-by: zhaoyiping0622 <zhaoyiping0622@gmail.com>
This commit is contained in:
parent
86e1a736fe
commit
d909a01a95
7
deps/oblib/src/lib/CMakeLists.txt
vendored
7
deps/oblib/src/lib/CMakeLists.txt
vendored
@ -41,6 +41,11 @@ ob_set_subtarget(oblib_lib charset
|
||||
charset/ob_ctype_extra.cc
|
||||
)
|
||||
|
||||
ob_set_subtarget(oblib_lib sched
|
||||
tc/ob_tc_wrapper.cpp
|
||||
)
|
||||
|
||||
|
||||
ob_set_subtarget(oblib_lib common
|
||||
ob_abort.cpp
|
||||
ob_date_unit_type.cpp
|
||||
@ -468,4 +473,4 @@ else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
5
deps/oblib/src/lib/ob_define.h
vendored
5
deps/oblib/src/lib/ob_define.h
vendored
@ -193,7 +193,10 @@ OB_INLINE bool is_resource_manager_group(const uint64_t group_id)
|
||||
{
|
||||
return group_id >= USER_RESOURCE_GROUP_START_ID && group_id != OB_INVALID_GROUP_ID;
|
||||
}
|
||||
|
||||
OB_INLINE bool is_sys_group(const uint64_t group_id)
|
||||
{
|
||||
return group_id >= 0 && group_id < USER_RESOURCE_GROUP_START_ID;
|
||||
}
|
||||
OB_INLINE bool is_valid_resource_group(const uint64_t group_id)
|
||||
{
|
||||
//other group or user group
|
||||
|
17
deps/oblib/src/lib/tc/README.md
vendored
Normal file
17
deps/oblib/src/lib/tc/README.md
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# obtc
|
||||
traffic control for OB. `man tc` if you do not know traffic control.
|
||||
|
||||
本项目是一个用户态库,目的是仿照tc的思想,通过提供各种队列, 并允许用户拼接这些队列实现灵活的流控,并不是真的和tc对标。
|
||||
|
||||
当然目前只支持三种队列:
|
||||
1. BufferQueue: 就是fifo队列。
|
||||
2. WeightedQueue: 支持权重的队列。
|
||||
3. QDiscRoot: 本质是个WeightedQueue,只是新增了timer, 另外封装了refresh逻辑。
|
||||
|
||||
## quick start
|
||||
copy `obtc` to where you like, configure include path properlly, add ob-tc.cpp to your build list.
|
||||
|
||||
use `test/test-tc.cpp` as a demo.
|
||||
|
||||
## test notes
|
||||
test-plimit2: tt1和tt2权重是1:2, 同时tt1有一个较小的limit,tt2下面有一个group受同样的limit,另两个group不受limit,tt2下面受limit的group会被饿死。
|
21
deps/oblib/src/lib/tc/deps/atomic.h
vendored
Normal file
21
deps/oblib/src/lib/tc/deps/atomic.h
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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 ATOMIC_LOAD
|
||||
#define ATOMIC_LOAD(x) __atomic_load_n((x), __ATOMIC_ACQUIRE)
|
||||
#define ATOMIC_STORE(x, v) __atomic_store_n((x), (v), __ATOMIC_RELEASE)
|
||||
#define ATOMIC_FAA(val, addv) __sync_fetch_and_add((val), (addv))
|
||||
#define ATOMIC_AAF(val, addv) __sync_add_and_fetch((val), (addv))
|
||||
#define ATOMIC_TAS(val, newv) __sync_lock_test_and_set((val), (newv))
|
||||
#define ATOMIC_VCAS(val, cmpv, newv) __sync_val_compare_and_swap((val), (cmpv), (newv))
|
||||
#define ATOMIC_BCAS(val, cmpv, newv) __sync_bool_compare_and_swap((val), (cmpv), (newv))
|
||||
#define PAUSE() __asm__("pause\n")
|
||||
#endif
|
41
deps/oblib/src/lib/tc/deps/batch_pop_queue.h
vendored
Normal file
41
deps/oblib/src/lib/tc/deps/batch_pop_queue.h
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
class BatchPopQueue
|
||||
{
|
||||
public:
|
||||
BatchPopQueue(): top_(NULL) {}
|
||||
~BatchPopQueue() {}
|
||||
void push(TCLink* p) {
|
||||
TCLink *nv = NULL;
|
||||
p->next_ = ATOMIC_LOAD(&top_);
|
||||
while(p->next_ != (nv = ATOMIC_VCAS(&top_, p->next_, p))) {
|
||||
p->next_ = nv;
|
||||
}
|
||||
}
|
||||
TCLink* pop() {
|
||||
TCLink* h = ATOMIC_TAS(&top_, NULL);
|
||||
return link_reverse(h);
|
||||
}
|
||||
private:
|
||||
static TCLink* link_reverse(TCLink* h) {
|
||||
TCLink* nh = NULL;
|
||||
while(h) {
|
||||
TCLink* next = h->next_;
|
||||
h->next_ = nh;
|
||||
nh = h;
|
||||
h = next;
|
||||
}
|
||||
return nh;
|
||||
}
|
||||
private:
|
||||
TCLink* top_ CACHE_ALIGNED;
|
||||
};
|
39
deps/oblib/src/lib/tc/deps/define.h
vendored
Normal file
39
deps/oblib/src/lib/tc/deps/define.h
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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 TC_INFO
|
||||
#define TC_INFO(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifndef CACHE_ALIGNED
|
||||
#define CACHE_ALIGNED __attribute__((aligned(64)))
|
||||
#endif
|
||||
|
||||
#ifndef structof
|
||||
#define structof(p, T, m) (T*)((char*)p - __builtin_offsetof(T, m))
|
||||
#endif
|
||||
|
||||
#ifndef MAX_CPU_NUM
|
||||
#define MAX_CPU_NUM 128
|
||||
#endif
|
||||
|
||||
#define MAX_N_CHAN 16
|
||||
#ifndef tc_itid
|
||||
int next_itid_ = 0;
|
||||
__thread int itid_ = -1;
|
||||
int tc_itid() {
|
||||
if (itid_ >= 0) return itid_;
|
||||
itid_ = ATOMIC_FAA(&next_itid_, 1);
|
||||
return itid_;
|
||||
}
|
||||
#define tc_itid tc_itid
|
||||
#endif
|
||||
#define arrlen(x) (sizeof(x)/sizeof(x[0]))
|
30
deps/oblib/src/lib/tc/deps/deps.h
vendored
Normal file
30
deps/oblib/src/lib/tc/deps/deps.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "atomic.h"
|
||||
#include "define.h"
|
||||
#include "futex.h"
|
||||
#include "single_waiter_cond.h"
|
||||
#include "link.h"
|
||||
#include "batch_pop_queue.h"
|
||||
#include "simple_link_queue.h"
|
||||
#include "lock.h"
|
||||
#include "thread_name.h"
|
||||
#include "str_format.h"
|
||||
#include "get_us.h"
|
128
deps/oblib/src/lib/tc/deps/drwlock.h
vendored
Normal file
128
deps/oblib/src/lib/tc/deps/drwlock.h
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
struct QRWLock
|
||||
{
|
||||
public:
|
||||
enum { MAX_UNSAFE_REF = MAX_N_CHAN };
|
||||
class RLockGuard
|
||||
{
|
||||
public:
|
||||
RLockGuard(QRWLock &rwlock): rwlock_(rwlock) { rwlock_.rdlock(); }
|
||||
~RLockGuard() { rwlock_.rdunlock(); }
|
||||
private:
|
||||
QRWLock &rwlock_;
|
||||
};
|
||||
class RLockGuardUnsafe
|
||||
{
|
||||
public:
|
||||
RLockGuardUnsafe(QRWLock &rwlock, int idx): rwlock_(rwlock), idx_(idx) { rwlock_.rdlock_unsafe(idx); }
|
||||
~RLockGuardUnsafe() { rwlock_.rdunlock_unsafe(idx_); }
|
||||
private:
|
||||
QRWLock &rwlock_;
|
||||
int idx_;
|
||||
};
|
||||
|
||||
class WLockGuard
|
||||
{
|
||||
public:
|
||||
WLockGuard(QRWLock &rwlock): rwlock_(rwlock) { rwlock_.wrlock(); }
|
||||
~WLockGuard() { rwlock_.wrunlock(); }
|
||||
private:
|
||||
QRWLock &rwlock_;
|
||||
};
|
||||
private:
|
||||
struct ReadRef
|
||||
{
|
||||
ReadRef(): value_(0) {}
|
||||
~ReadRef() {}
|
||||
int64_t value_;
|
||||
} CACHE_ALIGNED;
|
||||
uint64_t write_uid_ CACHE_ALIGNED;
|
||||
ReadRef read_ref_unsafe_[MAX_UNSAFE_REF];
|
||||
ReadRef read_ref_[MAX_CPU_NUM];
|
||||
ReadRef& get_read_ref() { return read_ref_[tc_itid() % arrlen(read_ref_)]; }
|
||||
public:
|
||||
QRWLock(): write_uid_(0)
|
||||
{}
|
||||
~QRWLock()
|
||||
{}
|
||||
bool try_rdlock_unsafe(int idx)
|
||||
{
|
||||
bool lock_succ = false;
|
||||
int64_t *ref = &read_ref_[idx].value_;
|
||||
if (0 == ATOMIC_LOAD(&write_uid_)) {
|
||||
ATOMIC_STORE(ref, 1);
|
||||
if (0 == ATOMIC_LOAD(&write_uid_)) {
|
||||
lock_succ = true;
|
||||
} else {
|
||||
ATOMIC_STORE(ref, 0);
|
||||
}
|
||||
}
|
||||
return lock_succ;
|
||||
}
|
||||
void rdlock_unsafe(int idx)
|
||||
{
|
||||
while (!try_rdlock_unsafe(idx)) {
|
||||
PAUSE();
|
||||
}
|
||||
}
|
||||
void rdunlock_unsafe(int idx)
|
||||
{
|
||||
int64_t *ref = &read_ref_[idx].value_;
|
||||
ATOMIC_STORE(ref, 0);
|
||||
}
|
||||
bool try_rdlock()
|
||||
{
|
||||
bool lock_succ = false;
|
||||
int64_t *ref = &get_read_ref().value_;
|
||||
if (0 == ATOMIC_LOAD(&write_uid_)) {
|
||||
ATOMIC_FAA(ref, 1);
|
||||
if (0 == ATOMIC_LOAD(&write_uid_)) {
|
||||
lock_succ = true;
|
||||
} else {
|
||||
ATOMIC_FAA(ref, -1);
|
||||
}
|
||||
}
|
||||
return lock_succ;
|
||||
}
|
||||
void rdlock()
|
||||
{
|
||||
while (!try_rdlock()) {
|
||||
PAUSE();
|
||||
}
|
||||
}
|
||||
void rdunlock()
|
||||
{
|
||||
int64_t *ref = &get_read_ref().value_;
|
||||
ATOMIC_FAA(ref, -1);
|
||||
}
|
||||
void wrlock()
|
||||
{
|
||||
while (!ATOMIC_BCAS(&write_uid_, 0, 1))
|
||||
;
|
||||
for (int64_t i = 0; i < (int64_t)arrlen(read_ref_); i++) {
|
||||
while (ATOMIC_LOAD(&read_ref_[i].value_) > 0) {
|
||||
PAUSE();
|
||||
}
|
||||
}
|
||||
for (int64_t i = 0; i < (int64_t)arrlen(read_ref_unsafe_); i++) {
|
||||
while (ATOMIC_LOAD(&read_ref_unsafe_[i].value_) > 0) {
|
||||
PAUSE();
|
||||
}
|
||||
}
|
||||
ATOMIC_STORE(&write_uid_, 2);
|
||||
}
|
||||
void wrunlock()
|
||||
{
|
||||
ATOMIC_STORE(&write_uid_, 0);
|
||||
}
|
||||
};
|
124
deps/oblib/src/lib/tc/deps/fifo_alloc.h
vendored
Normal file
124
deps/oblib/src/lib/tc/deps/fifo_alloc.h
vendored
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
#include <new>
|
||||
#define MAGIC 0xdeadbeafdeadbeafULL
|
||||
class FifoAlloc
|
||||
{
|
||||
private:
|
||||
enum { PAGE_SIZE = 1<<16 };
|
||||
struct Page {
|
||||
Page(int sz): MAGIC_(MAGIC), limit_(sz - sizeof(Page)), pos_(0), alloc_cnt_(0), ref_(0) {}
|
||||
int ref(int x) {
|
||||
int ret = ATOMIC_AAF(&ref_, x);
|
||||
if (0 == ret) {
|
||||
MAGIC_ = MAGIC - 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void* alloc(int sz) {
|
||||
int64_t alloc_sz = sz + sizeof(Page*);
|
||||
void* ret = NULL;
|
||||
if (pos_ + alloc_sz <= limit_) {
|
||||
*(Page**)(base_ + pos_) = this;
|
||||
ret = base_ + pos_ + sizeof(Page*);
|
||||
pos_ += alloc_sz;
|
||||
alloc_cnt_++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int retire() { return ref(alloc_cnt_); }
|
||||
uint64_t MAGIC_;
|
||||
int limit_;
|
||||
int pos_;
|
||||
int alloc_cnt_;
|
||||
int ref_ CACHE_ALIGNED;
|
||||
char base_[0] CACHE_ALIGNED;
|
||||
};
|
||||
struct CacheRef
|
||||
{
|
||||
CacheRef(): page_(NULL), ref_(0) {}
|
||||
Page* page_;
|
||||
int ref_;
|
||||
Page* free(Page* p) {
|
||||
Page* ret = NULL;
|
||||
if (page_ != p) {
|
||||
if (NULL != page_ && 0 == page_->ref(-ref_)) {
|
||||
ret = page_;
|
||||
}
|
||||
page_ = p;
|
||||
ref_ = 1;
|
||||
} else {
|
||||
ref_++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
Page* cur_page_;
|
||||
int64_t limit_;
|
||||
int64_t hold_ CACHE_ALIGNED;
|
||||
CacheRef cache_ref_;
|
||||
public:
|
||||
FifoAlloc(): cur_page_(NULL), limit_(INT64_MAX), hold_(0) {}
|
||||
void set_limit(int64_t limit) { limit_ = limit; }
|
||||
void* alloc(int sz) {
|
||||
void* ret = NULL;
|
||||
if (NULL != cur_page_ && NULL != (ret = cur_page_->alloc(sz))) {
|
||||
return ret;
|
||||
}
|
||||
if (NULL != cur_page_) {
|
||||
retire_page(cur_page_);
|
||||
}
|
||||
if (NULL != (cur_page_ = alloc_page())) {
|
||||
ret = cur_page_->alloc(sz);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void free(void* p) {
|
||||
Page* page = *((Page**)p - 1);
|
||||
if(page->MAGIC_ != MAGIC) {
|
||||
abort();
|
||||
}
|
||||
Page* p2free = cache_ref_.free(page);
|
||||
if (p2free) {
|
||||
free_page(p2free);
|
||||
}
|
||||
/*
|
||||
if (0 == page->ref(-1)) {
|
||||
free_page(page);
|
||||
}
|
||||
*/
|
||||
}
|
||||
private:
|
||||
Page* alloc_page() {
|
||||
Page* p = NULL;
|
||||
if (ATOMIC_LOAD(&hold_) > limit_) {
|
||||
} else if (ATOMIC_AAF(&hold_, PAGE_SIZE) > limit_) {
|
||||
ATOMIC_FAA(&hold_, -PAGE_SIZE);
|
||||
} else {
|
||||
p = (typeof(p))::malloc(PAGE_SIZE);
|
||||
new(p)Page(PAGE_SIZE);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void free_page(Page* p) {
|
||||
ATOMIC_FAA(&hold_, -PAGE_SIZE);
|
||||
::free(p);
|
||||
}
|
||||
void retire_page(Page* p) {
|
||||
if(p->MAGIC_ != MAGIC) {
|
||||
abort();
|
||||
}
|
||||
if (0 == p->retire()) {
|
||||
free_page(p);
|
||||
}
|
||||
}
|
||||
};
|
38
deps/oblib/src/lib/tc/deps/futex.h
vendored
Normal file
38
deps/oblib/src/lib/tc/deps/futex.h
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
#include <linux/futex.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static int tc_futex(int *uaddr, int op, int val, const struct timespec *timeout, int *uaddr2, int val3) {
|
||||
return (int)syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
|
||||
}
|
||||
|
||||
static int tc_futex_wake(int *p, int val) {
|
||||
return tc_futex((int *)p, FUTEX_WAKE_PRIVATE, val, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static struct timespec *tc_make_timespec(struct timespec *ts, int64_t us)
|
||||
{
|
||||
ts->tv_sec = us / 1000000;
|
||||
ts->tv_nsec = 1000 * (us % 1000000);
|
||||
return ts;
|
||||
}
|
||||
|
||||
static int tc_futex_wait(int *p, int val, const int64_t timeout_us) {
|
||||
int err = 0;
|
||||
struct timespec ts;
|
||||
if (0 != tc_futex((int *)p, FUTEX_WAIT_PRIVATE, val, tc_make_timespec(&ts, timeout_us), NULL, 0)) {
|
||||
err = errno;
|
||||
}
|
||||
return err;
|
||||
}
|
26
deps/oblib/src/lib/tc/deps/get_us.h
vendored
Normal file
26
deps/oblib/src/lib/tc/deps/get_us.h
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
// static int64_t tc_get_us()
|
||||
// {
|
||||
// struct timespec tp;
|
||||
// clock_gettime(CLOCK_REALTIME_COARSE, &tp);
|
||||
// //clock_gettime(CLOCK_REALTIME, &tp);
|
||||
// return tp.tv_sec * 1000000 + tp.tv_nsec/1000;
|
||||
// }
|
||||
|
||||
static int64_t tc_get_ns()
|
||||
{
|
||||
struct timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
return tp.tv_sec * 1000000000 + tp.tv_nsec;
|
||||
}
|
65
deps/oblib/src/lib/tc/deps/link.h
vendored
Normal file
65
deps/oblib/src/lib/tc/deps/link.h
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
static void link_del(TCLink* h, TCLink* p)
|
||||
{
|
||||
h->next_ = p->next_;
|
||||
}
|
||||
|
||||
static void link_insert(TCLink* h, TCLink* p)
|
||||
{
|
||||
p->next_ = h->next_;
|
||||
h->next_ = p;
|
||||
}
|
||||
|
||||
typedef bool less_than_t(TCLink* p1, TCLink* p2);
|
||||
static void order_link_insert(TCLink* h, TCLink* t, less_than_t less_than)
|
||||
{
|
||||
TCLink* prev = h;
|
||||
TCLink* cur = NULL;
|
||||
while(h != (cur = prev->next_) && less_than(cur, t)) {
|
||||
prev = cur;
|
||||
}
|
||||
t->next_ = cur;
|
||||
prev->next_ = t;
|
||||
}
|
||||
|
||||
struct TCDLink
|
||||
{
|
||||
TCDLink(TCDLink* p): next_(p), prev_(p) {}
|
||||
~TCDLink() {}
|
||||
TCDLink* next_;
|
||||
TCDLink* prev_;
|
||||
};
|
||||
|
||||
static void dlink_insert(TCDLink* h, TCDLink* p)
|
||||
{
|
||||
TCDLink* n = h->next_;
|
||||
p->next_ = n;
|
||||
p->prev_ = h;
|
||||
h->next_ = p;
|
||||
n->prev_ = p;
|
||||
}
|
||||
|
||||
static void dlink_del(TCDLink* p)
|
||||
{
|
||||
TCDLink* h = p->prev_;
|
||||
TCDLink* n = p->next_;
|
||||
h->next_ = n;
|
||||
n->prev_ = h;
|
||||
}
|
||||
|
||||
/*
|
||||
static bool dlist_is_empty(TCDLink* p)
|
||||
{
|
||||
return p->next_ == p;
|
||||
}*/
|
19
deps/oblib/src/lib/tc/deps/lock.h
vendored
Normal file
19
deps/oblib/src/lib/tc/deps/lock.h
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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 QWGuard
|
||||
#include "drwlock.h"
|
||||
QRWLock qdisc_glock;
|
||||
#define QWGuard(comment) QRWLock::WLockGuard guard(qdisc_glock)
|
||||
#define QRGuard(comment) QRWLock::RLockGuard guard(qdisc_glock)
|
||||
#define QRGuardUnsafe(comment, idx) QRWLock::RLockGuardUnsafe guard(qdisc_glock, idx)
|
||||
#endif
|
47
deps/oblib/src/lib/tc/deps/simple_link_queue.h
vendored
Normal file
47
deps/oblib/src/lib/tc/deps/simple_link_queue.h
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
class SimpleTCLinkQueue
|
||||
{
|
||||
public:
|
||||
SimpleTCLinkQueue(): head_(NULL), tail_(NULL), cnt_(0) {}
|
||||
~SimpleTCLinkQueue() {}
|
||||
public:
|
||||
int64_t cnt() { return cnt_; }
|
||||
TCLink* top() { return head_; }
|
||||
TCLink* pop() {
|
||||
TCLink* p = NULL;
|
||||
if (NULL != head_) {
|
||||
cnt_--;
|
||||
p = head_;
|
||||
head_ = head_->next_;
|
||||
if (NULL == head_) {
|
||||
tail_ = NULL;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
void push(TCLink* p) {
|
||||
cnt_++;
|
||||
p->next_ = NULL;
|
||||
if (NULL == tail_) {
|
||||
head_ = tail_ = p;
|
||||
} else {
|
||||
tail_->next_ = p;
|
||||
tail_ = p;
|
||||
}
|
||||
}
|
||||
private:
|
||||
TCLink* head_;
|
||||
TCLink* tail_;
|
||||
int64_t cnt_;
|
||||
};
|
32
deps/oblib/src/lib/tc/deps/single_waiter_cond.h
vendored
Normal file
32
deps/oblib/src/lib/tc/deps/single_waiter_cond.h
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
class SingleWaiterCond
|
||||
{
|
||||
public:
|
||||
SingleWaiterCond(): stock_(0) {}
|
||||
~SingleWaiterCond() {}
|
||||
void wait(int64_t timeout_us) {
|
||||
if (0 == ATOMIC_LOAD(&stock_)) {
|
||||
tc_futex_wait(&stock_, 0, timeout_us);
|
||||
} else {
|
||||
ATOMIC_STORE(&stock_, 0);
|
||||
}
|
||||
}
|
||||
void signal() {
|
||||
if (0 == ATOMIC_LOAD(&stock_) && ATOMIC_BCAS(&stock_, 0, 1)) {
|
||||
tc_futex_wake(&stock_, 1);
|
||||
}
|
||||
}
|
||||
private:
|
||||
int stock_;
|
||||
};
|
51
deps/oblib/src/lib/tc/deps/str_format.h
vendored
Normal file
51
deps/oblib/src/lib/tc/deps/str_format.h
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
class StrFormat
|
||||
{
|
||||
public:
|
||||
StrFormat(char* b, int64_t limit): buf_(b), limit_(limit), pos_(0) {
|
||||
buf_[0] = 0;
|
||||
}
|
||||
~StrFormat() {}
|
||||
char* cstr() { return buf_; }
|
||||
void append(const char* fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
private:
|
||||
char* buf_;
|
||||
int64_t limit_;
|
||||
int64_t pos_;
|
||||
};
|
||||
|
||||
void StrFormat::append(const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int cnt = vsnprintf(buf_ + pos_, limit_ - pos_, fmt, ap);
|
||||
if (cnt > 0 && pos_ + cnt < limit_) {
|
||||
pos_ += cnt;
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static char* format_bytes(char* buf, int64_t limit, int64_t bytes)
|
||||
{
|
||||
if (bytes >= (INT64_MAX / 16)) {
|
||||
snprintf(buf, limit, "x");
|
||||
} else if (bytes > 1024 * 1024 * 9) {
|
||||
snprintf(buf, limit, "%ldM", bytes/1024/1024);
|
||||
} else if (bytes > 1024 * 9) {
|
||||
snprintf(buf, limit, "%ldK", bytes/1024);
|
||||
} else {
|
||||
snprintf(buf, limit, "%ld", bytes);
|
||||
}
|
||||
return buf;
|
||||
}
|
29
deps/oblib/src/lib/tc/deps/thread_name.h
vendored
Normal file
29
deps/oblib/src/lib/tc/deps/thread_name.h
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <stdarg.h>
|
||||
static void tc_set_thread_name(const char* name)
|
||||
{
|
||||
prctl(PR_SET_NAME, name, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void tc_format_thread_name(const char* fmt, ...) __attribute__((format(printf, 1, 2)));
|
||||
static void tc_format_thread_name(const char* fmt, ...)
|
||||
{
|
||||
char buf[16];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
tc_set_thread_name(buf);
|
||||
}
|
739
deps/oblib/src/lib/tc/ob_tc.cpp
vendored
Normal file
739
deps/oblib/src/lib/tc/ob_tc.cpp
vendored
Normal file
@ -0,0 +1,739 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#include "ob_tc.h"
|
||||
#include "deps/deps.h"
|
||||
|
||||
static void* imap_fetch(int id);
|
||||
struct QStat
|
||||
{
|
||||
QStat(): count_(0), bytes_(0), delay_(0) {}
|
||||
void inc(QStat& that) {
|
||||
count_ += that.count_;
|
||||
bytes_ += that.bytes_;
|
||||
delay_ += that.delay_;
|
||||
}
|
||||
int64_t count_;
|
||||
int64_t bytes_;
|
||||
int64_t delay_;
|
||||
};
|
||||
|
||||
class IQD
|
||||
{
|
||||
public:
|
||||
IQD(int id, int type, const char* name): id_(id), type_(type) {
|
||||
snprintf(name_, sizeof(name_), "%s", name);
|
||||
}
|
||||
virtual ~IQD() {}
|
||||
int get_type() { return type_; }
|
||||
int get_id() { return id_; }
|
||||
const char* get_name() const { return name_; }
|
||||
protected:
|
||||
int id_;
|
||||
int type_;
|
||||
char name_[16]; // for debug
|
||||
};
|
||||
|
||||
class ITCLimiter: public IQD
|
||||
{
|
||||
public:
|
||||
enum { LIMIT_BALANCE_BOUND_MS = 10 };
|
||||
ITCLimiter(int id, int type, const char* name): IQD(id, type, name), limit_per_sec_(INT64_MAX), due_ts_(0) {}
|
||||
virtual ~ITCLimiter() {}
|
||||
virtual int64_t get_cost(TCRequest* req) = 0;
|
||||
void set_limit_per_sec(int64_t limit) { limit_per_sec_ = limit; }
|
||||
int64_t get_limit_per_sec() { return limit_per_sec_; }
|
||||
int64_t inc_due_ns(TCRequest* req)
|
||||
{
|
||||
if (INT64_MAX == limit_per_sec_) {
|
||||
if (due_ts_ != 0) {
|
||||
due_ts_ = 0;
|
||||
}
|
||||
} else if (0 == limit_per_sec_) {
|
||||
if (due_ts_ != INT64_MAX) {
|
||||
due_ts_ = INT64_MAX;
|
||||
}
|
||||
} else {
|
||||
int64_t cur_ns = tc_get_ns();
|
||||
int64_t ts_lower_limit = cur_ns - LIMIT_BALANCE_BOUND_MS * 1000 * 1000;
|
||||
if (due_ts_ < ts_lower_limit) {
|
||||
due_ts_ = ts_lower_limit;
|
||||
}
|
||||
due_ts_ += (get_cost(req) * 1000000000LL)/limit_per_sec_;
|
||||
}
|
||||
return due_ts_;
|
||||
}
|
||||
int64_t get_due_ns() { return due_ts_; }
|
||||
protected:
|
||||
int64_t limit_per_sec_;
|
||||
int64_t due_ts_ CACHE_ALIGNED;
|
||||
};
|
||||
|
||||
#include "ob_tc_limit.cpp"
|
||||
typedef class ITCLimiter Limiter;
|
||||
class TCLimiterList
|
||||
{
|
||||
public:
|
||||
enum { MAX_LIMITER_COUNT = 100 };
|
||||
TCLimiterList(): limiter0_(-1, "builtin") { memset(limiter_, 0, sizeof(limiter_)); }
|
||||
|
||||
void set_limit_per_sec(int64_t limit) { limiter0_.set_limit_per_sec(limit); }
|
||||
int64_t get_limit_per_sec() { return limiter0_.get_limit_per_sec(); }
|
||||
void print_limiters_per_sec(StrFormat& f) {
|
||||
char b[256];
|
||||
for (int i = 0; i < MAX_LIMITER_COUNT && limiter_[i]; i++) {
|
||||
f.append(" %s:%s", limiter_[i]->get_name(), format_bytes(b, sizeof(b), limiter_[i]->get_limit_per_sec()));
|
||||
}
|
||||
}
|
||||
void add_limit(Limiter* limiter) {
|
||||
for(int i = 0; i < MAX_LIMITER_COUNT; i++) {
|
||||
if (NULL == limiter_[i]) {
|
||||
limiter_[i] = limiter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void del_limit(Limiter* limiter) {
|
||||
for(int i = 0; i < MAX_LIMITER_COUNT; i++) {
|
||||
if (limiter == limiter_[i]) {
|
||||
memmove(limiter_ + i, limiter_ + i + 1, (MAX_LIMITER_COUNT - i - 1) * sizeof(limiter_[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int64_t recalc_next_active_ns(TCRequest *req)
|
||||
{
|
||||
int64_t max_ts = limiter0_.get_due_ns();
|
||||
if (req == nullptr) {
|
||||
for(int i = 0; i < MAX_LIMITER_COUNT && limiter_[i]; i++) {
|
||||
int64_t due_ns = limiter_[i]->get_due_ns();
|
||||
if (max_ts < due_ns) {
|
||||
max_ts = due_ns;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < MAX_LIMITER_COUNT && limiter_[i]; i++) {
|
||||
for (int j = 0; (j < MAX_SHARED_DEVICE_LIMIT_COUNT); j++) {
|
||||
if (req->ss_limiter_ids_[j] > 0 && req->ss_limiter_ids_[j] == limiter_[i]->get_id()) {
|
||||
int64_t due_ns = limiter_[i]->get_due_ns();
|
||||
if (max_ts < due_ns) {
|
||||
max_ts = due_ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return max_ts;
|
||||
}
|
||||
void inc_due_ns(TCRequest* req) {
|
||||
limiter0_.inc_due_ns(req);
|
||||
for(int i = 0; i < MAX_LIMITER_COUNT && limiter_[i]; i++) {
|
||||
for (int j = 0; j < MAX_SHARED_DEVICE_LIMIT_COUNT; j++) {
|
||||
if (req->ss_limiter_ids_[j] > 0 && req->ss_limiter_ids_[j] == limiter_[i]->get_id()) {
|
||||
limiter_[i]->inc_due_ns(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
BytesLimiter limiter0_;
|
||||
Limiter* limiter_[MAX_LIMITER_COUNT];
|
||||
};
|
||||
|
||||
TCRequest* link2req(TCLink* p) { return structof(p, TCRequest,link_); }
|
||||
|
||||
typedef class TCLimiterList LimiterList;
|
||||
class OverQuotaList;
|
||||
class QDesc;
|
||||
class IQDisc;
|
||||
|
||||
class QDesc: public IQD
|
||||
{
|
||||
public:
|
||||
enum { SHARE_BALANCE_BOUND_MB = 100 };
|
||||
friend class OverQuotaList;
|
||||
friend class OverReserveList;
|
||||
friend class IQDisc;
|
||||
protected:
|
||||
int parent_;
|
||||
int root_;
|
||||
int64_t weight_;
|
||||
LimiterList reserver_;
|
||||
LimiterList limiter_;
|
||||
public:
|
||||
QDesc(int id, int type, int parent, int root, const char* name): IQD(id, type, name), parent_(parent), root_(root),
|
||||
weight_(1), reserver_(), limiter_()
|
||||
{
|
||||
reserver_.set_limit_per_sec(0);
|
||||
}
|
||||
~QDesc() {}
|
||||
int get_root() { return root_; }
|
||||
int get_parent() { return parent_; }
|
||||
QStat& get_stat(QStat& stat);
|
||||
void set_weight(int64_t w) { weight_ = w; }
|
||||
int64_t get_weight() { return weight_; }
|
||||
void set_limit(int64_t limit) { limiter_.set_limit_per_sec(limit); }
|
||||
int64_t get_limit() { return limiter_.get_limit_per_sec(); }
|
||||
void set_reserve(int64_t limit) { reserver_.set_limit_per_sec(limit); }
|
||||
int64_t get_reserve() { return reserver_.get_limit_per_sec(); }
|
||||
void add_limit(Limiter* limiter) { limiter_.add_limit(limiter); }
|
||||
void del_limit(Limiter* limiter) { limiter_.del_limit(limiter); }
|
||||
void add_reserve(Limiter* limiter) { reserver_.add_limit(limiter); }
|
||||
void del_reserve(Limiter* limiter) { reserver_.del_limit(limiter); }
|
||||
void print_limiters_per_sec(StrFormat& f) { limiter_.print_limiters_per_sec(f); }
|
||||
};
|
||||
|
||||
static IQDisc* fetch_qdisc(int qid, int chan_id);
|
||||
|
||||
class IQDisc
|
||||
{
|
||||
public:
|
||||
enum { SHARE_BALANCE_BOUND_MB = 100 };
|
||||
friend class OverQuotaList;
|
||||
friend class OverReserveList;
|
||||
protected:
|
||||
QDesc* desc_;
|
||||
int chan_id_;
|
||||
IQDisc* parent_;
|
||||
IQDisc* root_;
|
||||
QStat stat_;
|
||||
TCDLink ready_dlink_;
|
||||
TCLink dirty_link_;
|
||||
TCLink over_quota_link_;
|
||||
TCLink over_reserve_link_;
|
||||
int64_t cur_vast_;
|
||||
int64_t max_poped_child_vast_;
|
||||
int64_t refresh_ns_;
|
||||
TCRequest* candinate_req_;
|
||||
bool candinate_is_reserved_;
|
||||
int64_t next_active_ts_;
|
||||
TCDLink ready_list_;
|
||||
TCLink dirty_list_;
|
||||
public:
|
||||
QStat& get_stat() { return stat_; }
|
||||
void inc_stat(TCRequest* req) {
|
||||
stat_.count_ += 1;
|
||||
stat_.bytes_ += req->bytes_;
|
||||
stat_.delay_ += refresh_ns_ - req->start_ns_;
|
||||
}
|
||||
public:
|
||||
static IQDisc* ready2qdisc(TCDLink* p) { return structof(p, IQDisc, ready_dlink_); }
|
||||
static IQDisc* dirty2qdisc(TCLink* p) { return structof(p, IQDisc, dirty_link_); }
|
||||
static IQDisc* OverQuota2Qdisc(TCLink* p) { return structof(p, IQDisc, over_quota_link_); }
|
||||
static IQDisc* OverReserve2Qdisc(TCLink* p) { return structof(p, IQDisc, over_reserve_link_); }
|
||||
static bool next_quota_active_ts_less_than(TCLink* p1, TCLink* p2)
|
||||
{
|
||||
IQDisc* q1 = OverQuota2Qdisc(p1);
|
||||
IQDisc* q2 = OverQuota2Qdisc(p2);
|
||||
return q1->next_active_ts_ < q2->next_active_ts_;
|
||||
}
|
||||
static bool next_reserve_active_ts_less_than(TCLink* p1, TCLink* p2)
|
||||
{
|
||||
IQDisc* q1 = OverReserve2Qdisc(p1);
|
||||
IQDisc* q2 = OverReserve2Qdisc(p2);
|
||||
return q1->next_active_ts_ < q2->next_active_ts_;
|
||||
}
|
||||
|
||||
IQDisc(QDesc* desc, int chan_id): desc_(desc), chan_id_(chan_id),
|
||||
parent_(fetch_qdisc(desc->parent_, chan_id)), root_(fetch_qdisc(desc->root_, chan_id)),
|
||||
ready_dlink_(NULL), dirty_link_(NULL), over_quota_link_(NULL), over_reserve_link_(NULL),
|
||||
cur_vast_(0), max_poped_child_vast_(0),
|
||||
refresh_ns_(0), candinate_req_(NULL), candinate_is_reserved_(false),
|
||||
next_active_ts_(INT64_MAX), ready_list_(&ready_list_), dirty_list_(&dirty_list_) {
|
||||
}
|
||||
virtual ~IQDisc() {}
|
||||
protected:
|
||||
IQDisc* get_parent() { return parent_; }
|
||||
IQDisc* get_root() { return root_; }
|
||||
public:
|
||||
virtual TCRequest* quick_top() {
|
||||
return nullptr;
|
||||
}
|
||||
TCRequest* refresh_candinate(int64_t cur_ns) {
|
||||
if (refresh_ns_ != cur_ns) {
|
||||
candinate_req_ = NULL;
|
||||
candinate_is_reserved_ = false;
|
||||
int64_t next_active_ts = 0;
|
||||
if ((next_active_ts = desc_->limiter_.recalc_next_active_ns(quick_top())) > cur_ns) {
|
||||
if (next_active_ts != INT64_MAX) {
|
||||
on_over_quota(next_active_ts);
|
||||
}
|
||||
} else if (NULL == (candinate_req_ = do_refresh_candinate(cur_ns))) {
|
||||
} else if ((next_active_ts = desc_->reserver_.recalc_next_active_ns(nullptr)) > cur_ns) {
|
||||
if (next_active_ts != INT64_MAX) {
|
||||
on_over_reserve(next_active_ts);
|
||||
}
|
||||
} else {
|
||||
candinate_is_reserved_ = true;
|
||||
}
|
||||
IQDisc* parent = get_parent();
|
||||
if (NULL != parent) {
|
||||
int64_t lower_bound = parent->max_poped_child_vast_ - (1000LL * 1000LL * SHARE_BALANCE_BOUND_MB)/desc_->weight_;
|
||||
if (cur_vast_ < lower_bound) {
|
||||
cur_vast_ = lower_bound;
|
||||
}
|
||||
}
|
||||
refresh_ns_ = cur_ns;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
return candinate_req_;
|
||||
}
|
||||
virtual TCRequest* do_refresh_candinate(int64_t cur_ns) {
|
||||
TCRequest* candinate = NULL;
|
||||
refresh_dirty_list(cur_ns);
|
||||
IQDisc* child = min_vast_child();
|
||||
if (child) {
|
||||
candinate = child->candinate_req_;
|
||||
}
|
||||
return candinate;
|
||||
}
|
||||
|
||||
TCRequest* pop() {
|
||||
TCRequest* req = do_pop();
|
||||
if (req) {
|
||||
cur_vast_ += calc_req_st(req);
|
||||
inc_stat(req);
|
||||
desc_->limiter_.inc_due_ns(req);
|
||||
desc_->reserver_.inc_due_ns(req);
|
||||
IQDisc* parent = get_parent();
|
||||
if (parent) {
|
||||
parent->add_to_dirty_list(this);
|
||||
if (cur_vast_ > parent->max_poped_child_vast_) {
|
||||
parent->max_poped_child_vast_ = cur_vast_;
|
||||
}
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
virtual TCRequest* do_pop() {
|
||||
TCRequest* req = NULL;
|
||||
IQDisc* child = pop_min_vast_child();
|
||||
if (child) {
|
||||
req = child->pop();
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
||||
void mark_dirty(IQDisc* child) {
|
||||
IQDisc* parent = get_parent();
|
||||
if (NULL == child) {
|
||||
if (parent) {
|
||||
parent->mark_dirty(this);
|
||||
}
|
||||
} else if (NULL == child->dirty_link_.next_ && NULL == child->over_quota_link_.next_) {
|
||||
add_to_dirty_list(child);
|
||||
if (parent) {
|
||||
parent->mark_dirty(this);
|
||||
}
|
||||
} else {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void refresh_dirty_list(int64_t cur_ns) {
|
||||
TCLink* p = NULL;
|
||||
while(&dirty_list_ != (p = dirty_list_.next_)) {
|
||||
link_del(&dirty_list_, p);
|
||||
p->next_ = NULL;
|
||||
inspect_child(dirty2qdisc(p), cur_ns);
|
||||
}
|
||||
}
|
||||
|
||||
void inspect_child(IQDisc* q, int64_t cur_ns) {
|
||||
if (q->ready_dlink_.next_) {
|
||||
dlink_del(&q->ready_dlink_);
|
||||
q->ready_dlink_.next_ = NULL;
|
||||
}
|
||||
if (q->refresh_candinate(cur_ns)) {
|
||||
sort_ready_child(q);
|
||||
}
|
||||
}
|
||||
|
||||
bool has_reserved_req() { return false; }
|
||||
void sort_ready_child(IQDisc* child) {
|
||||
TCDLink* prev = &ready_list_;
|
||||
TCDLink* cur = NULL;
|
||||
while(&ready_list_ != (cur = prev->next_) && child->get_predict_vast() > ready2qdisc(cur)->get_predict_vast()) {
|
||||
prev = cur;
|
||||
}
|
||||
dlink_insert(prev, &child->ready_dlink_);
|
||||
//char buf[128] = "\0";
|
||||
//dump_ready_list(buf, sizeof(buf));
|
||||
//info("sort ready child, %s: after sort: %s", child->name_, buf);
|
||||
}
|
||||
|
||||
const char* dump_ready_list(char* buf, int64_t limit) {
|
||||
int64_t pos = 0;
|
||||
TCDLink* prev = &ready_list_;
|
||||
TCDLink* cur = NULL;
|
||||
while(&ready_list_ != (cur = prev->next_)) {
|
||||
prev = cur;
|
||||
pos += snprintf(buf + pos, limit - pos, "%s,", ready2qdisc(cur)->desc_->name_);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void on_over_quota(int64_t next_active_ts);
|
||||
void on_over_reserve(int64_t next_active_ts);
|
||||
uint64_t calc_req_st(TCRequest* req) { return req->bytes_/desc_->weight_; }
|
||||
uint64_t get_predict_vast() {
|
||||
int64_t base = (candinate_is_reserved_? 0: INT64_MAX/2);
|
||||
return base + cur_vast_ + calc_req_st(candinate_req_);
|
||||
}
|
||||
IQDisc* min_vast_child() {
|
||||
TCDLink* p = ready_list_.next_;
|
||||
return (p == &ready_list_)? NULL: ready2qdisc(p);
|
||||
}
|
||||
IQDisc* pop_min_vast_child() {
|
||||
IQDisc* ret = NULL;
|
||||
TCDLink* p = ready_list_.next_;
|
||||
if (p != &ready_list_) {
|
||||
dlink_del(p);
|
||||
p->next_ = NULL;
|
||||
ret = ready2qdisc(p);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void add_to_dirty_list(IQDisc* child) {
|
||||
link_insert(&dirty_list_, &child->dirty_link_);
|
||||
}
|
||||
};
|
||||
|
||||
class BufferQueue: public IQDisc
|
||||
{
|
||||
public:
|
||||
BufferQueue(QDesc* desc, int chan_id): IQDisc(desc, chan_id) {}
|
||||
virtual ~BufferQueue() {}
|
||||
int64_t cnt() { return queue_.cnt(); }
|
||||
|
||||
virtual TCRequest* do_refresh_candinate(int64_t cur_ns) {
|
||||
return top();
|
||||
}
|
||||
void push(TCRequest* req) {
|
||||
queue_.push(&req->link_);
|
||||
mark_dirty(NULL);
|
||||
}
|
||||
TCRequest* top() {
|
||||
TCLink* p = queue_.top();
|
||||
return p? link2req(p): NULL;
|
||||
}
|
||||
TCRequest* do_pop() {
|
||||
TCLink* p = queue_.pop();
|
||||
return p? link2req(p): NULL;
|
||||
}
|
||||
TCRequest* quick_top() {
|
||||
return top();
|
||||
}
|
||||
private:
|
||||
SimpleTCLinkQueue queue_;
|
||||
};
|
||||
|
||||
class WeightedQueue: public IQDisc
|
||||
{
|
||||
public:
|
||||
WeightedQueue(QDesc* desc, int chan_id): IQDisc(desc, chan_id) {}
|
||||
virtual ~WeightedQueue() {}
|
||||
};
|
||||
|
||||
class OverQuotaList
|
||||
{
|
||||
public:
|
||||
TCLink over_quota_list_;
|
||||
public:
|
||||
OverQuotaList(): over_quota_list_(&over_quota_list_) {}
|
||||
~OverQuotaList() {}
|
||||
void sort_over_quota_qdisc(IQDisc* child) {
|
||||
assert(NULL == child->dirty_link_.next_);
|
||||
assert(NULL == child->over_quota_link_.next_);
|
||||
order_link_insert(&over_quota_list_, &child->over_quota_link_, IQDisc::next_quota_active_ts_less_than);
|
||||
}
|
||||
int64_t get_first_active_ns() {
|
||||
TCLink* first = over_quota_list_.next_;
|
||||
return (first != &over_quota_list_)? IQDisc::OverQuota2Qdisc(first)->next_active_ts_: INT64_MAX;
|
||||
}
|
||||
void inspect_over_quota_qdisc(int64_t cur_ns) {
|
||||
TCLink* h = &over_quota_list_;
|
||||
TCLink* cur = NULL;
|
||||
while(h != (cur = h->next_)) {
|
||||
IQDisc* q = IQDisc::OverQuota2Qdisc(cur);
|
||||
if (q->next_active_ts_ > cur_ns) {
|
||||
break;
|
||||
} else {
|
||||
link_del(h, cur);
|
||||
cur->next_ = NULL;
|
||||
if ((q->next_active_ts_ = q->desc_->limiter_.recalc_next_active_ns(q->quick_top())) > cur_ns) {
|
||||
sort_over_quota_qdisc(q);
|
||||
} else {
|
||||
q->mark_dirty(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class OverReserveList
|
||||
{
|
||||
public:
|
||||
TCLink over_reserve_list_;
|
||||
public:
|
||||
OverReserveList(): over_reserve_list_(&over_reserve_list_) {}
|
||||
~OverReserveList() {}
|
||||
void sort_over_reserve_qdisc(IQDisc* child) {
|
||||
if (NULL == child->over_reserve_link_.next_) {
|
||||
order_link_insert(&over_reserve_list_, &child->over_reserve_link_, IQDisc::next_reserve_active_ts_less_than);
|
||||
}
|
||||
}
|
||||
int64_t get_first_active_ns() {
|
||||
TCLink* first = over_reserve_list_.next_;
|
||||
return (first != &over_reserve_list_)? IQDisc::OverReserve2Qdisc(first)->next_active_ts_: INT64_MAX;
|
||||
}
|
||||
void inspect_over_reserve_qdisc(int64_t cur_ns) {
|
||||
TCLink* h = &over_reserve_list_;
|
||||
TCLink* cur = NULL;
|
||||
while(h != (cur = h->next_)) {
|
||||
IQDisc* q = IQDisc::OverReserve2Qdisc(cur);
|
||||
if (q->next_active_ts_ > cur_ns) {
|
||||
break;
|
||||
} else {
|
||||
link_del(h, cur);
|
||||
cur->next_ = NULL;
|
||||
if ((q->next_active_ts_ = q->desc_->reserver_.recalc_next_active_ns(nullptr)) > cur_ns
|
||||
&& q->next_active_ts_ != INT64_MAX) {
|
||||
sort_over_reserve_qdisc(q);
|
||||
} else {
|
||||
q->mark_dirty(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class QDescRoot: public QDesc
|
||||
{
|
||||
public:
|
||||
enum { MAX_TC_CHAN = 32 };
|
||||
QDescRoot(int id, const char* name): QDesc(id, QDISC_ROOT, -1, id, name), handler_(NULL), n_chan_(0) {}
|
||||
~QDescRoot() {}
|
||||
int get_n_chan() { return n_chan_; }
|
||||
void set_handler(ITCHandler* handler){ handler_ = handler; }
|
||||
ITCHandler* get_handler() { return handler_; }
|
||||
int qsched_start(int n_chan);
|
||||
int qsched_stop();
|
||||
int qsched_wait();
|
||||
int qsched_submit(TCRequest* req, uint32_t chan_id);
|
||||
private:
|
||||
ITCHandler* handler_;
|
||||
int n_chan_;
|
||||
};
|
||||
|
||||
static IQDisc* create_path_and_fetch_leaf(int qid, int chan_id);
|
||||
static void qsched_stat_report(int chan_id, int64_t cur_us, bool leaf_only);
|
||||
class QDiscRoot: public IQDisc
|
||||
{
|
||||
private:
|
||||
enum { QUOTA_BATCH_MS = 1, RESERVE_BATCH_MS = 1 };
|
||||
enum { MAX_QTABLES = 32 };
|
||||
SimpleTCLinkQueue fallback_queue_;
|
||||
OverQuotaList over_quota_list_;
|
||||
OverReserveList over_reserve_list_;
|
||||
BatchPopQueue req_queue_;
|
||||
SingleWaiterCond cond_ CACHE_ALIGNED;
|
||||
bool is_stop_ CACHE_ALIGNED;
|
||||
pthread_t pd_;
|
||||
public:
|
||||
QDiscRoot(QDesc* desc, int chan_id): IQDisc(desc, chan_id), is_stop_(false) {
|
||||
root_ = this;
|
||||
}
|
||||
virtual ~QDiscRoot() {}
|
||||
void set_chan_id(int chan_id) { chan_id_ = chan_id; }
|
||||
void sort_over_quota_qdisc(IQDisc* child) {
|
||||
over_quota_list_.sort_over_quota_qdisc(child);
|
||||
}
|
||||
void sort_over_reserve_qdisc(IQDisc* child) {
|
||||
over_reserve_list_.sort_over_reserve_qdisc(child);
|
||||
}
|
||||
int submit_req(TCRequest* req) {
|
||||
req->start_ns_ = tc_get_ns();
|
||||
req_queue_.push(&req->link_);
|
||||
cond_.signal();
|
||||
return 0;
|
||||
}
|
||||
TCRequest* refresh_and_pop(int64_t cur_ns, int64_t& next_active_ns) {
|
||||
TCRequest* req = NULL;
|
||||
QRGuardUnsafe("refresh_and_pop", chan_id_);
|
||||
if (handle_req_queue() > 0) {
|
||||
next_active_ns = 0;
|
||||
}
|
||||
over_quota_list_.inspect_over_quota_qdisc(cur_ns - QUOTA_BATCH_MS * 1000 * 1000);
|
||||
over_reserve_list_.inspect_over_reserve_qdisc(cur_ns - RESERVE_BATCH_MS * 1000 * 1000);
|
||||
if (!is_root_over_quota() && refresh_candinate(cur_ns)) {
|
||||
req = pop();
|
||||
}
|
||||
if (next_active_ns > 0) {
|
||||
int64_t next_ns = 0;
|
||||
if ((next_ns = over_quota_list_.get_first_active_ns()) < next_active_ns) {
|
||||
next_active_ns = next_ns;
|
||||
}
|
||||
}
|
||||
return req;
|
||||
}
|
||||
public:
|
||||
TCRequest* pop_fallback_queue() {
|
||||
TCRequest* req = NULL;
|
||||
TCLink* p = fallback_queue_.pop();
|
||||
if (NULL != p) {
|
||||
req = link2req(p);
|
||||
inc_stat(req);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
int do_thread_work() {
|
||||
tc_format_thread_name("qsched%d", chan_id_);
|
||||
while(!ATOMIC_LOAD(&is_stop_)) {
|
||||
int64_t cur_ns = tc_get_ns();
|
||||
int64_t next_active_ns = cur_ns + 100 * 1000 * 1000;
|
||||
TCRequest* req = pop_fallback_queue()?: refresh_and_pop(cur_ns, next_active_ns);
|
||||
QDescRoot* desc = (typeof(desc))desc_;
|
||||
if (req) {
|
||||
desc->get_handler()->handle(req);
|
||||
} else {
|
||||
int64_t wait_us = (next_active_ns - cur_ns)/1000;
|
||||
if (wait_us > 0) {
|
||||
cond_.wait(wait_us);
|
||||
}
|
||||
}
|
||||
if (0 == chan_id_) {
|
||||
bool leaf_only = false;
|
||||
qsched_stat_report(desc->get_n_chan(), cur_ns/1000, leaf_only);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int thread_work(QDiscRoot* root) {
|
||||
return root->do_thread_work();
|
||||
}
|
||||
int start() {
|
||||
return pthread_create(&pd_, NULL, (void* (*)(void*))thread_work, this);
|
||||
}
|
||||
void set_stop() { is_stop_ = true; }
|
||||
int wait() { return pthread_join(pd_, NULL); }
|
||||
private:
|
||||
bool is_root_over_quota() { return over_quota_link_.next_; }
|
||||
int64_t handle_req_queue() {
|
||||
int64_t handle_cnt = 0;
|
||||
TCLink* h = NULL;
|
||||
h = req_queue_.pop();
|
||||
while(h) {
|
||||
handle_cnt++;
|
||||
TCLink* n = h->next_;
|
||||
TCRequest* req = link2req(h);
|
||||
BufferQueue* qdisc = (typeof(qdisc))create_path_and_fetch_leaf(req->qid_, chan_id_);
|
||||
if (qdisc) {
|
||||
qdisc->push(req);
|
||||
} else {
|
||||
fallback_queue_.push(&req->link_);
|
||||
}
|
||||
h = n;
|
||||
}
|
||||
return handle_cnt;
|
||||
}
|
||||
};
|
||||
|
||||
void IQDisc::on_over_quota(int64_t next_active_ts)
|
||||
{
|
||||
next_active_ts_ = next_active_ts;
|
||||
((QDiscRoot*)get_root())->sort_over_quota_qdisc(this);
|
||||
}
|
||||
|
||||
void IQDisc::on_over_reserve(int64_t next_active_ts)
|
||||
{
|
||||
next_active_ts_ = next_active_ts;
|
||||
((QDiscRoot*)get_root())->sort_over_reserve_qdisc(this);
|
||||
}
|
||||
|
||||
static QDiscRoot* create_and_fetch_root(int qid, int chan_id);
|
||||
static QDiscRoot* fetch_root(int qid, int chan_id);
|
||||
int QDescRoot::qsched_start(int n_chan)
|
||||
{
|
||||
int err = 0;
|
||||
for(int chan_id = 0; 0 == err && chan_id < n_chan; chan_id++) {
|
||||
QDiscRoot* q = create_and_fetch_root(id_, chan_id);
|
||||
if (NULL == q) {
|
||||
err = -ENOMEM;
|
||||
} else {
|
||||
err = q->start();
|
||||
}
|
||||
}
|
||||
n_chan_ = n_chan;
|
||||
return err;
|
||||
}
|
||||
|
||||
int QDescRoot::qsched_stop()
|
||||
{
|
||||
int err = 0;
|
||||
for(int chan_id = 0; 0 == err && chan_id < n_chan_; chan_id++) {
|
||||
QDiscRoot* q = fetch_root(id_, chan_id);
|
||||
if (NULL == q) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->set_stop();
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int QDescRoot::qsched_wait()
|
||||
{
|
||||
int err = 0;
|
||||
for(int chan_id = 0; 0 == err && chan_id < n_chan_; chan_id++) {
|
||||
QDiscRoot* q = fetch_root(id_, chan_id);
|
||||
if (NULL == q) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->wait();
|
||||
}
|
||||
}
|
||||
n_chan_ = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
int QDescRoot::qsched_submit(TCRequest* req, uint32_t chan_id)
|
||||
{
|
||||
int err = 0;
|
||||
QDiscRoot * q = NULL;
|
||||
int n_chan = n_chan_;
|
||||
if (n_chan <= 0) {
|
||||
err = -EINVAL;
|
||||
} else if (NULL == (q = fetch_root(id_, chan_id % n_chan))) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
err = q->submit_req(req);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
QStat& QDesc::get_stat(QStat& stat) {
|
||||
QDescRoot* root = (typeof(root))imap_fetch(root_);
|
||||
int n_chan = root->get_n_chan();
|
||||
for(int i = 0; i < n_chan; i++) {
|
||||
IQDisc* q = fetch_qdisc(id_, i);
|
||||
if (NULL != q) {
|
||||
stat.inc(q->get_stat());
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
#include "ob_tc_interface.cpp"
|
||||
#include "ob_tc_stat.cpp"
|
64
deps/oblib/src/lib/tc/ob_tc.h
vendored
Normal file
64
deps/oblib/src/lib/tc/ob_tc.h
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstring>
|
||||
const int MAX_SHARED_DEVICE_LIMIT_COUNT = 2;
|
||||
struct TCLink
|
||||
{
|
||||
TCLink(TCLink* n): next_(n) {}
|
||||
TCLink* next_;
|
||||
};
|
||||
|
||||
struct TCRequest
|
||||
{
|
||||
TCRequest(): link_(NULL), qid_(-1), bytes_(0), start_ns_(0) {
|
||||
memset(ss_limiter_ids_, -1, sizeof(ss_limiter_ids_));
|
||||
}
|
||||
TCRequest(int qid, int64_t bytes): link_(NULL), qid_(qid), bytes_(bytes), start_ns_(0) {}
|
||||
~TCRequest() {}
|
||||
TCLink link_;
|
||||
int qid_;
|
||||
int64_t bytes_;
|
||||
int64_t start_ns_;
|
||||
int ss_limiter_ids_[MAX_SHARED_DEVICE_LIMIT_COUNT];
|
||||
};
|
||||
|
||||
class ITCHandler
|
||||
{
|
||||
public:
|
||||
ITCHandler() {}
|
||||
virtual ~ITCHandler() {}
|
||||
virtual int handle(TCRequest* req) = 0;
|
||||
};
|
||||
|
||||
enum QD_TYPE { QDISC_ROOT, QDISC_BUFFER_QUEUE, QDISC_WEIGHTED_QUEUE, QDISC_QUEUE_END, TCLIMIT_BYTES, TCLIMIT_COUNT };
|
||||
int tclimit_create(int type, const char* name);
|
||||
void tclimit_destroy(int limiter_id);
|
||||
int tclimit_set_limit(int limiter_id, int64_t limit);
|
||||
int tclimit_get_limit(int limiter_id, int64_t &limit);
|
||||
int qdisc_create(int type, int parent, const char* name);
|
||||
void qdisc_destroy(int qid);
|
||||
int qsched_set_handler(int root, ITCHandler* handler);
|
||||
int qsched_start(int root, int n_thread);
|
||||
int qsched_stop(int root);
|
||||
int qsched_wait(int root);
|
||||
int qsched_submit(int root, TCRequest* req, uint32_t chan_id);
|
||||
int qdisc_set_weight(int qid, int64_t weight); // default weight, limit, reserve
|
||||
int qdisc_set_limit(int qid, int64_t limit);
|
||||
int qdisc_set_reserve(int qid, int64_t limit);
|
||||
int qdisc_add_limit(int qid, int limiter_id);
|
||||
int qdisc_del_limit(int qid, int limiter_id);
|
||||
int qdisc_add_reserve(int qid, int limiter_id);
|
||||
int qdisc_del_reserve(int qid, int limiter_id);
|
348
deps/oblib/src/lib/tc/ob_tc_interface.cpp
vendored
Normal file
348
deps/oblib/src/lib/tc/ob_tc_interface.cpp
vendored
Normal file
@ -0,0 +1,348 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
const int QID_CAPACITY = 1<<13;
|
||||
const int MAX_QDISC_COUNT = QID_CAPACITY * (MAX_N_CHAN + 1);
|
||||
void* qdtable[MAX_QDISC_COUNT];
|
||||
|
||||
static void* imap_fetch(int id)
|
||||
{
|
||||
return id >= 0? qdtable[id % MAX_QDISC_COUNT]: NULL;
|
||||
}
|
||||
|
||||
static int imap_lock()
|
||||
{
|
||||
for(int i = 0; i < QID_CAPACITY; i++) {
|
||||
if (!qdtable[i]) {
|
||||
qdtable[i] = (void*)~0ULL;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int imap_set(int id, void* p)
|
||||
{
|
||||
qdtable[id] = p;
|
||||
return id;
|
||||
}
|
||||
|
||||
static IQDisc* qdisc_new_from_tpl(QDesc* tpl, int chan_id)
|
||||
{
|
||||
switch(tpl->get_type()) {
|
||||
case QDISC_ROOT:
|
||||
return new QDiscRoot(tpl, chan_id);
|
||||
case QDISC_BUFFER_QUEUE:
|
||||
return new BufferQueue(tpl, chan_id);
|
||||
break;
|
||||
case QDISC_WEIGHTED_QUEUE:
|
||||
return new WeightedQueue(tpl, chan_id);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static IQDisc* fetch_qdisc(int qid, int chan_id)
|
||||
{
|
||||
int64_t target_id = (chan_id + 1) * QID_CAPACITY + qid;
|
||||
return (IQDisc*)qdtable[target_id];
|
||||
}
|
||||
|
||||
static QDiscRoot* fetch_root(int qid, int chan_id)
|
||||
{
|
||||
return (QDiscRoot*)fetch_qdisc(qid, chan_id);
|
||||
}
|
||||
|
||||
static QDiscRoot* create_and_fetch_root(int qid, int chan_id)
|
||||
{
|
||||
int64_t target_id = (chan_id + 1) * QID_CAPACITY + qid;
|
||||
QDesc* tpl = (typeof(tpl))qdtable[qid];
|
||||
IQDisc** slot = (typeof(slot))(qdtable + target_id);
|
||||
if (NULL == *slot) {
|
||||
*slot = qdisc_new_from_tpl(tpl, chan_id);
|
||||
}
|
||||
return (QDiscRoot*)*slot;
|
||||
}
|
||||
|
||||
static IQDisc* create_path_and_fetch_leaf(int qid, int chan_id)
|
||||
{
|
||||
if (qid < 0 || NULL == qdtable[qid]) return NULL;
|
||||
int64_t target_id = (chan_id + 1) * QID_CAPACITY + qid;
|
||||
IQDisc** slot = (typeof(slot))(qdtable + target_id);
|
||||
if (*slot) return *slot;
|
||||
QDesc* tpl = (typeof(tpl))qdtable[qid];
|
||||
int parent_id = tpl->get_parent();
|
||||
assert(parent_id >= 0);
|
||||
IQDisc* parent = create_path_and_fetch_leaf(parent_id, chan_id);
|
||||
if (NULL == parent) return NULL;
|
||||
return (*slot = qdisc_new_from_tpl(tpl, chan_id));
|
||||
}
|
||||
|
||||
static QDesc* qdesc_new(int id, int type, int parent_id, int root, const char* name)
|
||||
{
|
||||
switch(type) {
|
||||
case QDISC_ROOT:
|
||||
return new QDescRoot(id, name);
|
||||
default:
|
||||
return new QDesc(id, type, parent_id, root, name);
|
||||
}
|
||||
}
|
||||
|
||||
int qdisc_create(int type, int parent_id, const char* name)
|
||||
{
|
||||
QWGuard("qdisc_create");
|
||||
int id = imap_lock();
|
||||
int root = -1;
|
||||
if (id >= 0) {
|
||||
if (type != QDISC_ROOT) {
|
||||
QDesc* parent = (typeof(parent))imap_fetch(parent_id);
|
||||
root = parent->get_root();
|
||||
if (root < 0) {
|
||||
root = parent_id;
|
||||
}
|
||||
}
|
||||
QDesc* q = qdesc_new(id, type, parent_id, root, name);
|
||||
imap_set(id, q);
|
||||
if (NULL == q) {
|
||||
id = -1;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void qdisc_destroy(int qid)
|
||||
{
|
||||
}
|
||||
|
||||
int qdisc_set_weight(int qid, int64_t weight)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("set_weight");
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
if (NULL == q) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->set_weight(weight);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_set_limit(int qid, int64_t limit)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("set_limit");
|
||||
limit = (limit <= 0) ? INT64_MAX : limit;
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
if (NULL == q) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->set_limit(limit);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_set_reserve(int qid, int64_t limit)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("set_reserve");
|
||||
limit = limit < 0 ? INT64_MAX : limit;
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
if (NULL == q) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->set_reserve(limit);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_add_limit(int qid, int limiter_id)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("add_limit");
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == q || NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->add_limit(L);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_del_limit(int qid, int limiter_id)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("del_limit");
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == q || NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->del_limit(L);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_add_reserve(int qid, int limiter_id)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("add_reserve");
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == q || NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->add_reserve(L);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qdisc_del_reserve(int qid, int limiter_id)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("del_reserve");
|
||||
QDesc* q = (typeof(q))imap_fetch(qid);
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == q || NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
q->del_reserve(L);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qsched_set_handler(int qid, ITCHandler* handler)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("set_handler");
|
||||
QDescRoot* root = (typeof(root))imap_fetch(qid);
|
||||
if (NULL == root) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
root->set_handler(handler);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qsched_start(int qid, int n_thread)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("start");
|
||||
if (n_thread >= MAX_N_CHAN) {
|
||||
n_thread = MAX_N_CHAN;
|
||||
}
|
||||
QDescRoot* root = (typeof(root))imap_fetch(qid);
|
||||
if (NULL == root) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
root->qsched_start(n_thread);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qsched_stop(int qid)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("stop");
|
||||
QDescRoot* root = (typeof(root))imap_fetch(qid);
|
||||
if (NULL == root) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
root->qsched_stop();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qsched_wait(int qid)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("wait");
|
||||
QDescRoot* root = (typeof(root))imap_fetch(qid);
|
||||
if (NULL == root) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
root->qsched_wait();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int qsched_submit(int qid, TCRequest* req, uint32_t chan_id)
|
||||
{
|
||||
int err = 0;
|
||||
QRGuard("submit");
|
||||
QDescRoot* root = (typeof(root))imap_fetch(qid);
|
||||
if (NULL == root) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
err = root->qsched_submit(req, chan_id);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
ITCLimiter* tclimit_new(int id, int type, const char* name)
|
||||
{
|
||||
switch(type) {
|
||||
case TCLIMIT_BYTES:
|
||||
return new BytesLimiter(id, name);
|
||||
case TCLIMIT_COUNT:
|
||||
return new CountLimiter(id, name);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int tclimit_create(int type, const char* name)
|
||||
{
|
||||
QWGuard("tclimit_create");
|
||||
int id = imap_lock();
|
||||
if (id >= 0) {
|
||||
ITCLimiter* limiter = tclimit_new(id, type, name);
|
||||
imap_set(id, limiter);
|
||||
if (NULL == limiter) {
|
||||
id = -1;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void tclimit_destroy(int id)
|
||||
{
|
||||
}
|
||||
|
||||
int tclimit_set_limit(int limiter_id, int64_t limit)
|
||||
{
|
||||
int err = 0;
|
||||
QWGuard("set_limit");
|
||||
limit = (limit <= 0) ? INT64_MAX : limit;
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
L->set_limit_per_sec(limit);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int tclimit_get_limit(int limiter_id, int64_t &limit)
|
||||
{
|
||||
int err = 0;
|
||||
QRGuard("get_limit");
|
||||
ITCLimiter* L = (typeof(L))imap_fetch(limiter_id);
|
||||
if (NULL == L) {
|
||||
err = -ENOENT;
|
||||
} else {
|
||||
limit = L->get_limit_per_sec();
|
||||
}
|
||||
return err;
|
||||
}
|
27
deps/oblib/src/lib/tc/ob_tc_limit.cpp
vendored
Normal file
27
deps/oblib/src/lib/tc/ob_tc_limit.cpp
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
class BytesLimiter: public ITCLimiter
|
||||
{
|
||||
public:
|
||||
BytesLimiter(int id, const char* name): ITCLimiter(id, TCLIMIT_BYTES, name) {}
|
||||
~BytesLimiter() {}
|
||||
int64_t get_cost(TCRequest* req) { return req->bytes_; }
|
||||
};
|
||||
|
||||
class CountLimiter: public ITCLimiter
|
||||
{
|
||||
public:
|
||||
CountLimiter(int id, const char* name): ITCLimiter(id, TCLIMIT_COUNT, name) {}
|
||||
~CountLimiter() {}
|
||||
int64_t get_cost(TCRequest* req) { return 1; }
|
||||
};
|
103
deps/oblib/src/lib/tc/ob_tc_stat.cpp
vendored
Normal file
103
deps/oblib/src/lib/tc/ob_tc_stat.cpp
vendored
Normal file
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
class QSchedStat
|
||||
{
|
||||
public:
|
||||
enum { N = 1024 };
|
||||
QSchedStat(): last_report_us_(0) {
|
||||
memset(last_stat_, 0, sizeof(last_stat_));
|
||||
}
|
||||
~QSchedStat() {}
|
||||
void try_report(int n_chan, int64_t cur_us, bool leaf_only) {
|
||||
char buf[4096];
|
||||
int idx[128];
|
||||
StrFormat f(buf, sizeof(buf));
|
||||
int active_cnt = 0;
|
||||
if (cur_us - last_report_us_ > 1000 * 1000) {
|
||||
f.append("|cfg:");
|
||||
collect_cfg(f);
|
||||
active_cnt = collect_active_grp_idx(idx, arrlen(idx), leaf_only);
|
||||
f.append("|stat:");
|
||||
collect_stat(f, idx, active_cnt);
|
||||
for(int i = 0; i < n_chan; i++) {
|
||||
f.append(" |q%d:", i);
|
||||
collect_qcount(f, i, idx, active_cnt);
|
||||
}
|
||||
TC_INFO("QSched: %s", buf);
|
||||
last_report_us_ = cur_us;
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool is_queue(int type) { return type >= QDISC_ROOT && type < QDISC_QUEUE_END; }
|
||||
void collect_cfg(StrFormat& f) {
|
||||
for(int i = 0; i < N; i++) {
|
||||
IQD* qd = (typeof(qd))imap_fetch(i);
|
||||
if (NULL == qd) continue;
|
||||
char b[256];
|
||||
if (is_queue(qd->get_type())) {
|
||||
QDesc* desc = (typeof(desc))qd;
|
||||
f.append(" %s:%ld", desc->get_name(), desc->get_weight());
|
||||
f.append(",%s", format_bytes(b, sizeof(b), desc->get_limit()));
|
||||
f.append(",%s", format_bytes(b, sizeof(b), desc->get_reserve()));
|
||||
desc->print_limiters_per_sec(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
int collect_active_grp_idx(int* idx, int limit, bool leaf_only) {
|
||||
int active_cnt = 0;
|
||||
for(int i = 0; active_cnt < limit && i < N; i++) {
|
||||
IQD* qd = (typeof(qd))imap_fetch(i);
|
||||
if (NULL == qd || !is_queue(qd->get_type())) continue;
|
||||
QDesc* desc = (typeof(desc))qd;
|
||||
if (NULL == desc || (leaf_only && QDISC_BUFFER_QUEUE != desc->get_type())) continue;
|
||||
QStat cur_stat;
|
||||
desc->get_stat(cur_stat);
|
||||
if (cur_stat.count_ - last_stat_[i].count_ > 0) {
|
||||
idx[active_cnt++] = i;
|
||||
}
|
||||
}
|
||||
return active_cnt;
|
||||
}
|
||||
void collect_stat(StrFormat& f, int* idx, int cnt) {
|
||||
char b[16];
|
||||
for(int j = 0; j < cnt; j++) {
|
||||
int i = idx[j];
|
||||
QDesc* desc = (typeof(desc))imap_fetch(i);
|
||||
QStat cur_stat;
|
||||
desc->get_stat(cur_stat);
|
||||
int64_t total_count = cur_stat.count_ - last_stat_[i].count_;
|
||||
f.append(" %s:%s/%ld:%ld", desc->get_name(), format_bytes(b, sizeof(b), cur_stat.bytes_ - last_stat_[i].bytes_), total_count, total_count > 0? (cur_stat.delay_ - last_stat_[i].delay_)/total_count: 0);
|
||||
last_stat_[i] = cur_stat;
|
||||
}
|
||||
}
|
||||
void collect_qcount(StrFormat& f, int chan_id, int* idx, int cnt) {
|
||||
for(int j = 0; j < cnt; j++) {
|
||||
int i = idx[j];
|
||||
QDesc* desc = (typeof(desc))imap_fetch(i);
|
||||
if (QDISC_BUFFER_QUEUE != desc->get_type()) continue;
|
||||
BufferQueue* q = (typeof(q))fetch_qdisc(i, chan_id);
|
||||
if (NULL != q) {
|
||||
f.append(" %ld", q->cnt());
|
||||
} else {
|
||||
f.append(" X");
|
||||
}
|
||||
}
|
||||
}
|
||||
private:
|
||||
QStat last_stat_[N];
|
||||
int64_t last_report_us_;
|
||||
} qsched_stat_;
|
||||
|
||||
static void qsched_stat_report(int chan_id, int64_t cur_us, bool leaf_only)
|
||||
{
|
||||
qsched_stat_.try_report(chan_id, cur_us, leaf_only);
|
||||
}
|
22
deps/oblib/src/lib/tc/ob_tc_wrapper.cpp
vendored
Normal file
22
deps/oblib/src/lib/tc/ob_tc_wrapper.cpp
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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 OCEANBASE_TC_OB_TC_WRAPPER_H_
|
||||
#define OCEANBASE_TC_OB_TC_WRAPPER_H_
|
||||
#include "lib/oblog/ob_log.h"
|
||||
#include "lib/ob_define.h"
|
||||
#include "lib/thread_local/ob_tsi_utils.h"
|
||||
|
||||
#define TC_INFO(...) _OB_LOG(INFO, __VA_ARGS__)
|
||||
#define MAX_CPU_NUM oceanbase::common::OB_MAX_CPU_NUM
|
||||
#define tc_itid oceanbase::common::get_itid
|
||||
#include "ob_tc.cpp"
|
||||
#endif /* OCEANBASE_TC_OB_TC_WRAPPER_H_ */
|
29
deps/oblib/src/lib/tc/test/test-2limit.cpp
vendored
Normal file
29
deps/oblib/src/lib/tc/test/test-2limit.cpp
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 1000000);
|
||||
DEF_LIMIT(L2, 4000000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
LIMIT(tt1g1, L1);
|
||||
LIMIT(tt1g2, L2);
|
||||
LIMIT(tt2g1, L1);
|
||||
LIMIT(tt2g2, L2);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
142
deps/oblib/src/lib/tc/test/test-base.cpp
vendored
Normal file
142
deps/oblib/src/lib/tc/test/test-base.cpp
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#define info(format,...) fprintf(stderr, format "\n", ## __VA_ARGS__)
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include "ob_tc.h"
|
||||
#include "deps/deps.h"
|
||||
#include "deps/fifo_alloc.h"
|
||||
#include <new>
|
||||
|
||||
#define cfg(k, v) (getenv(k)?:v)
|
||||
#define cfgi(k, v) atoi(cfg(k,v))
|
||||
#define ROOT(id) int id = qdisc_create(QDISC_ROOT, -1, #id)
|
||||
#define FIFO(id, parent, weight) int id = qdisc_create(QDISC_BUFFER_QUEUE, parent, #id); qdisc_set_weight(id, weight);
|
||||
#define SHARED(id, parent, weight) int id = qdisc_create(QDISC_WEIGHTED_QUEUE, parent, #id); qdisc_set_weight(id, weight);
|
||||
#define DEF_LIMIT(id, x) int id = tclimit_create(TCLIMIT_BYTES, #id); tclimit_set_limit(id, x);
|
||||
#define DEF_COUNT_LIMIT(id, x) int id = tclimit_create(TCLIMIT_COUNT, #id); tclimit_set_limit(id, x);
|
||||
#define LIMIT(id, limiter_id) qdisc_add_limit(id, limiter_id)
|
||||
#define RESERVE(id, limiter_id) qdisc_add_reserve(id, limiter_id)
|
||||
#define SCHED() qsched_set_handler(root, &g_handler); qsched_start(root, n_sched_thread);
|
||||
#define FILL(id, ...) FillThread fill_ ## id; fill_##id.init(root, id); fill_ ## id.start();
|
||||
|
||||
class FillThread;
|
||||
class TestRequest: public TCRequest
|
||||
{
|
||||
public:
|
||||
TestRequest(int qid, int64_t bytes, FillThread* fill, int64_t seq): TCRequest(qid, bytes), fill_(fill), seq_(seq) {}
|
||||
~TestRequest() {}
|
||||
FillThread* fill_;
|
||||
int64_t seq_;
|
||||
};
|
||||
|
||||
class FillThread
|
||||
{
|
||||
public:
|
||||
friend class TestHandler;
|
||||
enum { N_ALLOC = MAX_N_CHAN };
|
||||
FillThread(): root_(-1), grp_(-1), gen_cnt_(0), sleep_interval_(0) {
|
||||
for(int i = 0; i < N_ALLOC; i++) {
|
||||
alloc_[i].set_limit(1<<21);
|
||||
}
|
||||
}
|
||||
~FillThread() {}
|
||||
void init(int root, int grp) {
|
||||
root_ = root;
|
||||
grp_ = grp;
|
||||
}
|
||||
static void* do_fill_work(FillThread* self) { self->do_fill_loop(); return NULL; }
|
||||
void do_fill_loop() {
|
||||
tc_format_thread_name("fill_%d", grp_);
|
||||
while(1) {
|
||||
TestRequest* r = gen_request(100, gen_cnt_);
|
||||
if (r) {
|
||||
qsched_submit(root_, r, gen_cnt_);
|
||||
gen_cnt_++;
|
||||
} else {
|
||||
usleep(100);
|
||||
}
|
||||
int64_t sleep_us = sleep_interval_;
|
||||
if (sleep_us > 0) {
|
||||
usleep(sleep_us);
|
||||
}
|
||||
}
|
||||
}
|
||||
int start() {
|
||||
return pthread_create(&pd_, NULL, (void* (*)(void*))do_fill_work, this);
|
||||
}
|
||||
private:
|
||||
TestRequest* gen_request(int bytes, int64_t idx) {
|
||||
TestRequest* r = (typeof(r))alloc_[idx % N_ALLOC].alloc(sizeof(TestRequest));
|
||||
if (r) {
|
||||
new(r)TestRequest(grp_, bytes, this, idx);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void free_request(TestRequest* r)
|
||||
{
|
||||
alloc_[r->seq_ % N_ALLOC].free(r);
|
||||
}
|
||||
private:
|
||||
pthread_t pd_;
|
||||
int root_;
|
||||
int grp_;
|
||||
int64_t gen_cnt_;
|
||||
FifoAlloc alloc_[N_ALLOC];
|
||||
int sleep_interval_;
|
||||
};
|
||||
|
||||
class TestHandler: public ITCHandler
|
||||
{
|
||||
public:
|
||||
TestHandler() {}
|
||||
virtual ~TestHandler() {}
|
||||
int handle(TCRequest* r1) {
|
||||
TestRequest* r = (typeof(r))r1;
|
||||
r->fill_->free_request(r);
|
||||
return 0;
|
||||
}
|
||||
} g_handler;
|
||||
|
||||
void multi_fifo(int* array, int n, int parent) {
|
||||
for(int i = 0; i < n; i++) {
|
||||
char name[8];
|
||||
snprintf(name, sizeof(name), "a%d", i);
|
||||
array[i] = qdisc_create(QDISC_BUFFER_QUEUE, parent, name);
|
||||
qdisc_set_weight(array[i], 1);
|
||||
}
|
||||
}
|
||||
void multi_fill(FillThread* threads, int* array, int n, int root) {
|
||||
for(int i = 0; i < n; i++) {
|
||||
threads[i].init(root, array[i]);
|
||||
threads[i].start();
|
||||
}
|
||||
}
|
||||
#define MFIFO(array, n, parent) int array[32]; multi_fifo(array, n, parent);
|
||||
#define MFILL(array, n) FillThread fill_## array[32]; multi_fill(fill_##array, array, n, root);
|
||||
|
||||
#define STR(x) XSTR(x)
|
||||
#define XSTR(x) #x
|
||||
int main()
|
||||
{
|
||||
int n_sched_thread = cfgi("scheds", "2");
|
||||
#include STR(SRC)
|
||||
pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "ob_tc.cpp"
|
14
deps/oblib/src/lib/tc/test/test-fallback.cpp
vendored
Normal file
14
deps/oblib/src/lib/tc/test/test-fallback.cpp
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
ROOT(root);
|
||||
SCHED();
|
||||
FILL(2, 100);
|
19
deps/oblib/src/lib/tc/test/test-limit-1leaf.cpp
vendored
Normal file
19
deps/oblib/src/lib/tc/test/test-limit-1leaf.cpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 1000000);
|
||||
ROOT(root);
|
||||
FIFO(g1, root, 1);
|
||||
FIFO(g2, root, 2);
|
||||
LIMIT(g1, L1);
|
||||
SCHED();
|
||||
FILL(g1);
|
||||
FILL(g2);
|
20
deps/oblib/src/lib/tc/test/test-limit-2leaf.cpp
vendored
Normal file
20
deps/oblib/src/lib/tc/test/test-limit-2leaf.cpp
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 100000);
|
||||
ROOT(root);
|
||||
FIFO(g1, root, 1);
|
||||
FIFO(g2, root, 2);
|
||||
LIMIT(g1, L1);
|
||||
LIMIT(g2, L1);
|
||||
SCHED();
|
||||
FILL(g1);
|
||||
FILL(g2);
|
28
deps/oblib/src/lib/tc/test/test-limit-4leaf.cpp
vendored
Normal file
28
deps/oblib/src/lib/tc/test/test-limit-4leaf.cpp
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 1000000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
LIMIT(tt1g1, L1);
|
||||
LIMIT(tt1g2, L1);
|
||||
LIMIT(tt2g1, L1);
|
||||
LIMIT(tt2g2, L1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
26
deps/oblib/src/lib/tc/test/test-limit-top.cpp
vendored
Normal file
26
deps/oblib/src/lib/tc/test/test-limit-top.cpp
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
DEF_COUNT_LIMIT(L1, 10000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
LIMIT(root, L1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
39
deps/oblib/src/lib/tc/test/test-ob.cpp
vendored
Normal file
39
deps/oblib/src/lib/tc/test/test-ob.cpp
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
#define MAX_GROUP_STAT 30
|
||||
DEF_COUNT_LIMIT(B1R, 10000);
|
||||
ROOT(root);
|
||||
SHARED(net_in, root, 1);
|
||||
SHARED(net_out, root, 1);
|
||||
SHARED(tt1r, net_in, 1);
|
||||
SHARED(tt2r, net_in, 2);
|
||||
SHARED(tt1w, net_out, 1);
|
||||
SHARED(tt2w, net_out, 2);
|
||||
FIFO(tt1r1, tt1r, 1);
|
||||
FIFO(tt1r2, tt1r, 2);
|
||||
FIFO(tt2r1, tt2r, 1);
|
||||
FIFO(tt2r2, tt2r, 2);
|
||||
FIFO(tt1w1, tt1w, 1);
|
||||
FIFO(tt1w2, tt1w, 2);
|
||||
FIFO(tt2w1, tt2w, 1);
|
||||
FIFO(tt2w2, tt2w, 2);
|
||||
LIMIT(tt1r1, B1R);
|
||||
LIMIT(tt2r1, B1R);
|
||||
SCHED();
|
||||
FILL(tt1r1);
|
||||
FILL(tt1r2);
|
||||
FILL(tt2r1);
|
||||
FILL(tt2r2);
|
||||
FILL(tt1w1);
|
||||
FILL(tt1w2);
|
||||
FILL(tt2w1);
|
||||
FILL(tt2w2);
|
16
deps/oblib/src/lib/tc/test/test-perf.cpp
vendored
Normal file
16
deps/oblib/src/lib/tc/test/test-perf.cpp
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
ROOT(root);
|
||||
int fifos = cfgi("fifos", "4");
|
||||
SCHED();
|
||||
MFIFO(f, fifos, root);
|
||||
MFILL(f, fifos);
|
26
deps/oblib/src/lib/tc/test/test-plimit.cpp
vendored
Normal file
26
deps/oblib/src/lib/tc/test/test-plimit.cpp
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 1000000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
LIMIT(tt1g1, L1);
|
||||
LIMIT(tt2g1, L1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
30
deps/oblib/src/lib/tc/test/test-plimit2.cpp
vendored
Normal file
30
deps/oblib/src/lib/tc/test/test-plimit2.cpp
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 1000000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
FIFO(tt2g3, tt2, 3);
|
||||
LIMIT(tt1, L1);
|
||||
//LIMIT(tt1g1, L1);
|
||||
//LIMIT(tt1g2, L1);
|
||||
LIMIT(tt2g1, L1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
||||
FILL(tt2g3);
|
19
deps/oblib/src/lib/tc/test/test-reserve-1leaf.cpp
vendored
Normal file
19
deps/oblib/src/lib/tc/test/test-reserve-1leaf.cpp
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_COUNT_LIMIT(L1, 80000);
|
||||
ROOT(root);
|
||||
FIFO(g1, root, 1);
|
||||
FIFO(g2, root, 2);
|
||||
RESERVE(g1, L1);
|
||||
SCHED();
|
||||
FILL(g1);
|
||||
FILL(g2);
|
22
deps/oblib/src/lib/tc/test/test-reserve-2leaf.cpp
vendored
Normal file
22
deps/oblib/src/lib/tc/test/test-reserve-2leaf.cpp
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_COUNT_LIMIT(L1, 8000);
|
||||
DEF_COUNT_LIMIT(L2, 10000);
|
||||
ROOT(root);
|
||||
FIFO(g1, root, 1);
|
||||
FIFO(g2, root, 2);
|
||||
LIMIT(root, L2);
|
||||
RESERVE(g1, L1);
|
||||
RESERVE(g2, L1);
|
||||
SCHED();
|
||||
FILL(g1);
|
||||
FILL(g2);
|
30
deps/oblib/src/lib/tc/test/test-reserve-4leaf.cpp
vendored
Normal file
30
deps/oblib/src/lib/tc/test/test-reserve-4leaf.cpp
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
DEF_LIMIT(L1, 100 * 8000);
|
||||
DEF_LIMIT(L2, 100 * 10000);
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 2);
|
||||
SHARED(tt2, root, 2);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 2);
|
||||
LIMIT(root, L2);
|
||||
RESERVE(tt1g1, L1);
|
||||
RESERVE(tt1g2, L1);
|
||||
RESERVE(tt2g1, L1);
|
||||
//RESERVE(tt2g2, L1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
23
deps/oblib/src/lib/tc/test/test-weight-L2.cpp
vendored
Normal file
23
deps/oblib/src/lib/tc/test/test-weight-L2.cpp
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
ROOT(root);
|
||||
SHARED(tt1, root, 1);
|
||||
FIFO(tt1g1, tt1, 1);
|
||||
FIFO(tt1g2, tt1, 1);
|
||||
SHARED(tt2, root, 1);
|
||||
FIFO(tt2g1, tt2, 1);
|
||||
FIFO(tt2g2, tt2, 1);
|
||||
SCHED();
|
||||
FILL(tt1g1);
|
||||
FILL(tt1g2);
|
||||
FILL(tt2g1);
|
||||
FILL(tt2g2);
|
20
deps/oblib/src/lib/tc/test/test-weight.cpp
vendored
Normal file
20
deps/oblib/src/lib/tc/test/test-weight.cpp
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
DEF_COUNT_LIMIT(L1, 5000);
|
||||
ROOT(root);
|
||||
FIFO(g1, root, 1);
|
||||
FIFO(g2, root, 2);
|
||||
LIMIT(root, L1);
|
||||
SCHED();
|
||||
FILL(g1, 100);
|
||||
FILL(g2, 100);
|
@ -963,7 +963,11 @@ int ObSrvNetworkFrame::shared_storage_net_throt_predict(
|
||||
int ObSrvNetworkFrame::shared_storage_net_throt_set(const ObSharedDeviceResourceArray &assigned_resource)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_FAIL(OB_IO_MANAGER.get_tc().set_limit(assigned_resource))) {
|
||||
if (GCONF._enable_tree_based_io_scheduler == false) {
|
||||
if (OB_FAIL(OB_IO_MANAGER.get_tc().set_limit(assigned_resource))) {
|
||||
LOG_WARN("set failed", K(assigned_resource));
|
||||
}
|
||||
} else if (OB_FAIL(OB_IO_MANAGER.get_tc().set_limit_v2(assigned_resource))) {
|
||||
LOG_WARN("set failed", K(assigned_resource));
|
||||
}
|
||||
return ret;
|
||||
|
@ -103,6 +103,33 @@ int ObVirtualSharedStorageQuota::add_one_storage_batch_row()
|
||||
}
|
||||
obrpc::ObSharedDeviceResourceArray &limits_;
|
||||
};
|
||||
struct GetLimitV2
|
||||
{
|
||||
GetLimitV2(obrpc::ObSharedDeviceResourceArray &limits) : limits_(limits)
|
||||
{}
|
||||
int operator()(
|
||||
oceanbase::common::hash::HashMapPair<ObTrafficControl::ObStorageKey, ObTrafficControl::ObSharedDeviceControlV2>
|
||||
&entry)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int idx_begin = limits_.array_.count();
|
||||
for (int i = 0; i < obrpc::ResourceType::ResourceTypeCnt; ++i) {
|
||||
limits_.array_.push_back(obrpc::ObSharedDeviceResource());
|
||||
}
|
||||
if (OB_UNLIKELY(idx_begin < 0)
|
||||
|| OB_UNLIKELY(idx_begin + obrpc::ResourceType::ResourceTypeCnt > limits_.array_.count())) {
|
||||
} else {
|
||||
for (int i = 0; i < obrpc::ResourceType::ResourceTypeCnt; ++i) {
|
||||
limits_.array_.at(idx_begin + i).key_ = entry.first;
|
||||
limits_.array_.at(idx_begin + i).type_ = static_cast<obrpc::ResourceType>(i);
|
||||
limits_.array_.at(idx_begin + i).value_ = entry.second.get_limit(static_cast<obrpc::ResourceType>(i));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
obrpc::ObSharedDeviceResourceArray &limits_;
|
||||
};
|
||||
|
||||
struct GetUsage
|
||||
{
|
||||
GetUsage(obrpc::ObSharedDeviceResource &resource) : resource_(resource)
|
||||
@ -150,9 +177,18 @@ int ObVirtualSharedStorageQuota::add_one_storage_batch_row()
|
||||
};
|
||||
limits.array_.reserve(OB_IO_MANAGER.get_tc().get_storage_count() * obrpc::ResourceType::ResourceTypeCnt);
|
||||
// get limits
|
||||
GetLimit limits_fn(limits);
|
||||
if (OB_FAIL(OB_IO_MANAGER.get_tc().foreach_limit(limits_fn))) {
|
||||
SERVER_LOG(WARN, "predict failed", K(ret));
|
||||
if (GCONF._enable_tree_based_io_scheduler == false) {
|
||||
GetLimit limits_fn(limits);
|
||||
if (OB_FAIL(OB_IO_MANAGER.get_tc().foreach_limit(limits_fn))) {
|
||||
SERVER_LOG(WARN, "predict failed", K(ret));
|
||||
}
|
||||
} else {
|
||||
GetLimitV2 limits_fn_v2(limits);
|
||||
if (OB_FAIL(OB_IO_MANAGER.get_tc().foreach_limit_v2(limits_fn_v2))) {
|
||||
SERVER_LOG(WARN, "predict failed", K(ret));
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(usages.array_.assign(limits.array_))) {
|
||||
SERVER_LOG(WARN, "assign failed", K(ret));
|
||||
} else {
|
||||
|
@ -566,6 +566,7 @@ ob_set_subtarget(ob_share external_table
|
||||
ob_set_subtarget(ob_share io
|
||||
io/ob_io_define.cpp
|
||||
io/io_schedule/ob_io_mclock.cpp
|
||||
io/io_schedule/ob_io_schedule_v2.cpp
|
||||
io/ob_io_struct.cpp
|
||||
io/ob_io_calibration.cpp
|
||||
io/ob_io_manager.cpp
|
||||
|
343
src/share/io/io_schedule/ob_io_schedule_v2.cpp
Normal file
343
src/share/io/io_schedule/ob_io_schedule_v2.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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.
|
||||
*/
|
||||
|
||||
#define USING_LOG_PREFIX COMMON
|
||||
#include "ob_io_schedule_v2.h"
|
||||
#include "share/io/ob_io_struct.h"
|
||||
#include "observer/ob_server.h"
|
||||
namespace oceanbase
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
|
||||
static const int64_t STANDARD_IOPS_SIZE = 16 * (1<<10);
|
||||
|
||||
static void io_req_finish(ObIORequest& req, const ObIORetCode& ret_code)
|
||||
{
|
||||
if (OB_NOT_NULL(req.io_result_)) {
|
||||
req.io_result_->finish(ret_code, &req);
|
||||
}
|
||||
}
|
||||
|
||||
int QSchedCallback::handle(TCRequest* tc_req)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObDeviceChannel *device_channel = nullptr;
|
||||
ObTimeGuard time_guard("submit_req", 100000); //100ms
|
||||
ObIORequest& req = *CONTAINER_OF(tc_req, ObIORequest, qsched_req_);
|
||||
ObIOResult* result = req.io_result_;
|
||||
if (OB_UNLIKELY(stop_submit_)) {
|
||||
ret = OB_STATE_NOT_MATCH;
|
||||
LOG_WARN("sender stop submit", K(ret), K(stop_submit_));
|
||||
} else if (OB_ISNULL(result)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("io result is null", K(ret), K(req));
|
||||
} else if (OB_FAIL(req.prepare())) {
|
||||
LOG_WARN("prepare io request failed", K(ret), K(req));
|
||||
} else if (FALSE_IT(time_guard.click("prepare_req"))) {
|
||||
} else if (OB_FAIL(OB_IO_MANAGER.get_device_channel(req, device_channel))) {
|
||||
LOG_WARN("get device channel failed", K(ret), K(req));
|
||||
} else if (FALSE_IT(result->time_log_.dequeue_ts_ = ObTimeUtility::fast_current_time())) {
|
||||
} else {
|
||||
// lock request condition to prevent canceling halfway
|
||||
ObThreadCondGuard guard(result->get_cond());
|
||||
if (OB_FAIL(guard.get_ret())) {
|
||||
LOG_ERROR("fail to guard master condition", K(ret));
|
||||
} else if (req.is_canceled()) {
|
||||
ret = OB_CANCELED;
|
||||
} else if (OB_FAIL(device_channel->submit(req))) {
|
||||
LOG_WARN("submit io to device failed");
|
||||
} else {
|
||||
time_guard.click("device_submit");
|
||||
}
|
||||
}
|
||||
|
||||
if (time_guard.get_diff() > 100000) {// 100ms
|
||||
//print req
|
||||
LOG_INFO("submit_request cost too much time", K(ret), K(time_guard), K(req));
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
io_req_finish(req, ObIORetCode(ret));
|
||||
}
|
||||
req.dec_ref("phyqueue_dec"); // ref for io queue
|
||||
return ret;
|
||||
}
|
||||
|
||||
ObIOManagerV2 g_io_mgr2;
|
||||
|
||||
ObIOManagerV2::ObIOManagerV2(): root_qid_(-1)
|
||||
{
|
||||
memset(sub_roots_, -1, sizeof(sub_roots_));
|
||||
}
|
||||
|
||||
int ObIOManagerV2::init()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if ((root_qid_ = qdisc_create(QDISC_ROOT, -1, "root")) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else if (0 != qsched_set_handler(root_qid_, &io_submitter_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
} else if ((sub_roots_[(int)ObIOMode::READ] = qdisc_create(QDISC_WEIGHTED_QUEUE, root_qid_, "net_in")) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else if ((sub_roots_[(int)ObIOMode::WRITE] = qdisc_create(QDISC_WEIGHTED_QUEUE, root_qid_, "net_out")) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else if ((sub_roots_[(int)ObIOMode::MAX_MODE] = qdisc_create(QDISC_WEIGHTED_QUEUE, root_qid_, "disk")) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else if (OB_FAIL(set_default_net_tc_limits())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_ERROR("add net tc limits failed", K(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObIOManagerV2::start()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (0 != qsched_start(root_qid_, 2)) {
|
||||
ret = OB_ERR_SYS;
|
||||
} else if (OB_FAIL(io_submitter_.start())) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObIOManagerV2::stop()
|
||||
{
|
||||
io_submitter_.set_stop();
|
||||
qsched_stop(root_qid_);
|
||||
}
|
||||
|
||||
void ObIOManagerV2::wait()
|
||||
{
|
||||
qsched_wait(root_qid_);
|
||||
}
|
||||
|
||||
void ObIOManagerV2::destroy()
|
||||
{}
|
||||
|
||||
int ObIOManagerV2::set_default_net_tc_limits()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int r_qid = sub_roots_[(int)ObIOMode::READ];
|
||||
int w_qid = sub_roots_[(int)ObIOMode::WRITE];
|
||||
if (r_qid < 0 || w_qid < 0) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid qid", K(ret), K(r_qid), K(w_qid));
|
||||
} else if (OB_FAIL(qdisc_set_limit(r_qid, observer::ObServer::DEFAULT_ETHERNET_SPEED))) {
|
||||
LOG_WARN("set limit failed", K(ret), K(r_qid));
|
||||
} else if (OB_FAIL(qdisc_set_limit(w_qid, observer::ObServer::DEFAULT_ETHERNET_SPEED))) {
|
||||
LOG_WARN("set limit failed", K(ret), K(w_qid));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ObTenantIOSchedulerV2::ObTenantIOSchedulerV2(): tenant_id_(0)
|
||||
{
|
||||
memset(top_qid_, -1, sizeof(top_qid_));
|
||||
memset(default_qid_, -1, sizeof(default_qid_));
|
||||
}
|
||||
|
||||
int ObTenantIOSchedulerV2::init(const uint64_t tenant_id, const ObTenantIOConfig &io_config)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
for(int i = 0; OB_SUCC(ret) && i < N_SUB_ROOT; i++) {
|
||||
char name1[16];
|
||||
char name2[16];
|
||||
snprintf(name1, sizeof(name1), "t%ldm%d", tenant_id, i);
|
||||
snprintf(name2, sizeof(name2), "t%ldm%dgd", tenant_id, i);
|
||||
if ((top_qid_[i] = qdisc_create(QDISC_WEIGHTED_QUEUE, OB_IO_MANAGER_V2.get_sub_root_qid(i), name1)) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else if ((default_qid_[i] = qdisc_create(QDISC_BUFFER_QUEUE, top_qid_[i], name2)) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
destroy();
|
||||
} else {
|
||||
tenant_id_ = tenant_id;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObTenantIOSchedulerV2::destroy()
|
||||
{
|
||||
for(int i = 0; i < qid_.count(); i++) {
|
||||
if (qid_.at(i) >= 0) {
|
||||
qdisc_destroy(qid_.at(i));
|
||||
qid_.at(i) = -1;
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < N_SUB_ROOT; i++) {
|
||||
if (default_qid_[i] >= 0) {
|
||||
qdisc_destroy(default_qid_[i]);
|
||||
default_qid_[i] = -1;
|
||||
}
|
||||
if (top_qid_[i] >= 0) {
|
||||
qdisc_destroy(top_qid_[i]);
|
||||
top_qid_[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int config_qdisc(int qid, int64_t weight, int64_t max_bw, int64_t min_bw)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (0 != qdisc_set_weight(qid, weight? weight: 100)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
} else if (0 != qdisc_set_limit(qid, max_bw)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
} else if (0 != qdisc_set_reserve(qid, min_bw)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
} else {
|
||||
LOG_INFO("config qdisc success", K(ret), K(qid), K(weight), K(max_bw), K(min_bw));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int64_t calc_bw(const int64_t bw, const int64_t percentage)
|
||||
{
|
||||
return static_cast<double>(bw) / 100 * percentage >= INT64_MAX ? INT64_MAX : static_cast<int64_t>(static_cast<double>(bw) / 100 * percentage);
|
||||
}
|
||||
|
||||
static int config_group_qdisc(int qid, const int64_t tenant_id, const ObTenantIOConfig::UnitConfig& ucfg, const ObTenantIOConfig::GroupConfig &gcfg)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t unit_min_bw = gcfg.mode_ == ObIOMode::MAX_MODE ? (ucfg.min_iops_ * STANDARD_IOPS_SIZE < 0 ? INT64_MAX : ucfg.min_iops_ * STANDARD_IOPS_SIZE) : 0;
|
||||
int64_t unit_max_bw = gcfg.mode_ == ObIOMode::MAX_MODE ? (ucfg.max_iops_ * STANDARD_IOPS_SIZE <= 0 ? INT64_MAX : ucfg.max_iops_ * STANDARD_IOPS_SIZE) : ucfg.max_net_bandwidth_;
|
||||
if (OB_FAIL(config_qdisc(qid, gcfg.weight_percent_, calc_bw(unit_max_bw, gcfg.max_percent_), calc_bw(unit_min_bw, gcfg.min_percent_)))) {
|
||||
LOG_ERROR("config group_queue fail", K(ret), K(tenant_id), K(qid), K(ucfg), K(gcfg));
|
||||
} else {
|
||||
LOG_INFO("config group queue success", K(ret), K(tenant_id), K(qid), K(ucfg), K(gcfg), K(unit_min_bw), K(unit_max_bw));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool is_valid_mode(int mode)
|
||||
{
|
||||
return mode >= 0 && mode < ObTenantIOSchedulerV2::N_SUB_ROOT;
|
||||
}
|
||||
|
||||
int ObTenantIOSchedulerV2::update_config(const ObTenantIOConfig &io_config)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
// group config: READ, WRITE, MAX_MODE
|
||||
// qdisc : READ, WRITE, MAX_MODE
|
||||
const int64_t all_group_num = io_config.group_configs_.count();
|
||||
const ObTenantIOConfig::UnitConfig &ucfg = io_config.unit_config_;
|
||||
int64_t ucfg_max_bw = ucfg.max_iops_ * STANDARD_IOPS_SIZE <= 0 ? INT64_MAX : ucfg.max_iops_ * STANDARD_IOPS_SIZE;
|
||||
int64_t ucfg_min_bw = ucfg.min_iops_ * STANDARD_IOPS_SIZE < 0 ? INT64_MAX : ucfg.min_iops_ * STANDARD_IOPS_SIZE;
|
||||
LOG_INFO("update config", K_(tenant_id), K(io_config), K(ucfg_min_bw), K(ucfg_min_bw));
|
||||
if (OB_FAIL(config_qdisc(top_qid_[(int)ObIOMode::MAX_MODE], ucfg.weight_, ucfg_max_bw, ucfg_min_bw))) {
|
||||
LOG_WARN("config local tenant_queue fail", K(ret), K(tenant_id_), K(ObIOMode::MAX_MODE));
|
||||
} else if (OB_FAIL(config_qdisc(top_qid_[(int)ObIOMode::READ], ucfg.net_bandwidth_weight_, ucfg.max_net_bandwidth_, 0))) {
|
||||
LOG_WARN("config remote read tenant_queue fail", K(ret), K(ObIOMode::READ));
|
||||
} else if (OB_FAIL(config_qdisc(top_qid_[(int)ObIOMode::WRITE], ucfg.net_bandwidth_weight_, ucfg.max_net_bandwidth_, 0))) {
|
||||
LOG_WARN("config remote write tenant_queue fail", K(ret), K(ObIOMode::WRITE));
|
||||
} else if (OB_FAIL(qid_.reserve(all_group_num))) {
|
||||
LOG_WARN("qid reserve fail", K(ret));
|
||||
} else {
|
||||
for(int i = qid_.count(); OB_SUCC(ret) && i < all_group_num; i++) {
|
||||
ret = qid_.push_back(-1);
|
||||
}
|
||||
for (int i = 0; OB_SUCC(ret) && i < all_group_num; ++i) {
|
||||
const ObTenantIOConfig::GroupConfig& grp_cfg = io_config.group_configs_.at(i);
|
||||
int qid = qid_.at(i);
|
||||
if (qid >= 0) {
|
||||
} else if (!is_valid_mode((int)grp_cfg.mode_)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
} else {
|
||||
char name[16];
|
||||
snprintf(name, sizeof(name), "t%ldm%dg%ld", tenant_id_, (int)grp_cfg.mode_, grp_cfg.group_id_);
|
||||
if ((qid = qdisc_create(QDISC_BUFFER_QUEUE, top_qid_[(int)grp_cfg.mode_], name)) < 0) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
} else {
|
||||
qid_.at(i) = qid;
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(config_group_qdisc(qid, tenant_id_, ucfg, grp_cfg))) {
|
||||
LOG_WARN("config other group fail", K(ret), K(qid), K(io_config));
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fill_qsched_req(ObIORequest& req, int qid)
|
||||
{
|
||||
req.qsched_req_.qid_ = qid;
|
||||
req.qsched_req_.bytes_ = req.get_align_size();
|
||||
}
|
||||
|
||||
int64_t ObTenantIOSchedulerV2::get_qindex(ObIORequest& req)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t index = -1;
|
||||
const ObIOGroupKey grp_key = req.get_group_key();
|
||||
if (is_sys_group(grp_key.group_id_)) { //other
|
||||
index = static_cast<int64_t>(req.get_mode());
|
||||
} else if (!is_valid_group(grp_key.group_id_)) {
|
||||
} else if (OB_FAIL(req.tenant_io_mgr_.get_ptr()->get_group_index(grp_key, (uint64_t&)index))) {
|
||||
if (ret == OB_HASH_NOT_EXIST || ret == OB_STATE_NOT_MATCH) {
|
||||
ret = OB_SUCCESS;
|
||||
} else {
|
||||
LOG_WARN("get group index failed", K(ret), K(grp_key), K(index));
|
||||
}
|
||||
index = -1;
|
||||
} else if (INT64_MAX == index) {
|
||||
index = -1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int ObTenantIOSchedulerV2::get_qid(int64_t index)
|
||||
{
|
||||
int qid = -1;
|
||||
if (index >= 0 && index < qid_.count()) {
|
||||
qid = qid_.at(index);
|
||||
}
|
||||
if (qid < 0 && index >= 0) {
|
||||
qid = default_qid_[index % N_SUB_ROOT];
|
||||
}
|
||||
return qid;
|
||||
}
|
||||
|
||||
static uint32_t g_io_chan_id = 0;
|
||||
static uint32_t assign_chan_id()
|
||||
{
|
||||
return ATOMIC_FAA(&g_io_chan_id, 1);
|
||||
}
|
||||
|
||||
int ObTenantIOSchedulerV2::schedule_request(ObIORequest &req)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
int root = OB_IO_MANAGER_V2.get_root_qid();
|
||||
int64_t index = get_qindex(req);
|
||||
int qid = get_qid(index);
|
||||
fill_qsched_req(req, qid);
|
||||
req.inc_ref("phyqueue_inc"); //ref for phy_queue
|
||||
if (OB_ISNULL(req.io_result_)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("io result is null", K(ret), K(req));
|
||||
} else if (OB_FAIL(OB_IO_MANAGER.get_tc().register_bucket(req, qid))) {
|
||||
LOG_WARN("register bucket fail", K(ret), K(req));
|
||||
} else if (FALSE_IT(req.io_result_->time_log_.enqueue_ts_ = ObTimeUtility::fast_current_time())) {
|
||||
} else if (0 != qsched_submit(root, &req.qsched_req_, assign_chan_id())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
req.dec_ref("phyqueue_dec"); //ref for phy_queue
|
||||
LOG_WARN("qsched_submit fail", K(ret), K(req));
|
||||
io_req_finish(req, ObIORetCode(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}; // end namespace io_schedule
|
||||
}; // end namespace oceanbase
|
85
src/share/io/io_schedule/ob_io_schedule_v2.h
Normal file
85
src/share/io/io_schedule/ob_io_schedule_v2.h
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2021 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 OCEANBASE_IO_SCHEDULE_OB_IO_SCHEDULE_V2_H_
|
||||
#define OCEANBASE_IO_SCHEDULE_OB_IO_SCHEDULE_V2_H_
|
||||
#include "lib/lock/ob_drw_lock.h"
|
||||
#include "share/io/ob_io_define.h"
|
||||
#include "lib/container/ob_se_array.h"
|
||||
|
||||
namespace oceanbase
|
||||
{
|
||||
namespace common
|
||||
{
|
||||
class QSchedCallback: public ITCHandler
|
||||
{
|
||||
public:
|
||||
QSchedCallback(): stop_submit_(false) {}
|
||||
virtual ~QSchedCallback() {}
|
||||
int start() { stop_submit_ = false; return OB_SUCCESS; }
|
||||
void set_stop() { stop_submit_ = true; }
|
||||
virtual int handle(TCRequest* req);
|
||||
private:
|
||||
bool stop_submit_;
|
||||
};
|
||||
|
||||
class ObIOManagerV2
|
||||
{
|
||||
public:
|
||||
enum { N_SUB_ROOT = 3 };
|
||||
ObIOManagerV2();
|
||||
~ObIOManagerV2() {}
|
||||
int get_root_qid() { return root_qid_; }
|
||||
int get_sub_root_qid(int idx) {
|
||||
return (idx >= 0 && idx < N_SUB_ROOT)? sub_roots_[idx]: -1;
|
||||
}
|
||||
int init();
|
||||
int start();
|
||||
void stop();
|
||||
void wait();
|
||||
void destroy();
|
||||
private:
|
||||
QSchedCallback io_submitter_;
|
||||
int root_qid_;
|
||||
int sub_roots_[N_SUB_ROOT];
|
||||
int set_default_net_tc_limits();
|
||||
};
|
||||
|
||||
extern ObIOManagerV2 g_io_mgr2;
|
||||
#define OB_IO_MANAGER_V2 g_io_mgr2
|
||||
|
||||
class ObTenantIOSchedulerV2
|
||||
{
|
||||
public:
|
||||
enum { N_SUB_ROOT = ObIOManagerV2::N_SUB_ROOT };
|
||||
enum { GROUP_START_NUM = 3 * 3 };
|
||||
ObTenantIOSchedulerV2();
|
||||
~ObTenantIOSchedulerV2() { destroy(); }
|
||||
public:
|
||||
int init(const uint64_t tenant_id, const ObTenantIOConfig &io_config);
|
||||
void destroy();
|
||||
int update_config(const ObTenantIOConfig &io_config);
|
||||
int schedule_request(ObIORequest &req);
|
||||
private:
|
||||
static int64_t get_qindex(ObIORequest& req);
|
||||
int get_qid(int64_t index);
|
||||
private:
|
||||
DRWLock rwlock_;
|
||||
uint64_t tenant_id_;
|
||||
int top_qid_[N_SUB_ROOT];
|
||||
int default_qid_[N_SUB_ROOT];
|
||||
ObSEArray <int, GROUP_START_NUM> qid_;
|
||||
};
|
||||
|
||||
}; // end namespace common
|
||||
}; // end namespace oceanbase
|
||||
#endif /* OCEANBASE_IO_SCHEDULE_OB_IO_SCHEDULE_V2_H_ */
|
@ -1846,7 +1846,7 @@ int ObIOHandle::wait(const int64_t wait_timeout_ms)
|
||||
if (real_wait_timeout > 0) {
|
||||
int64_t wait_ms = real_wait_timeout;
|
||||
if (OB_FAIL(result_->wait(wait_ms))) {
|
||||
if (OB_TIMEOUT == ret) { // rarely happen
|
||||
if (OB_TIMEOUT == ret) {
|
||||
LOG_WARN("fail to wait result condition due to spurious wakeup", K(ret), K(wait_ms), K(*result_));
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,17 @@
|
||||
#ifndef OCEANBASE_LIB_STORAGE_IO_DEFINE
|
||||
#define OCEANBASE_LIB_STORAGE_IO_DEFINE
|
||||
|
||||
#include "lib/worker.h"
|
||||
#include "lib/profile/ob_trace_id.h"
|
||||
#include "lib/lock/ob_thread_cond.h"
|
||||
#include "lib/container/ob_rbtree.h"
|
||||
#include "lib/list/ob_list.h"
|
||||
#include "lib/container/ob_heap.h"
|
||||
#include "common/storage/ob_io_device.h"
|
||||
#include "lib/container/ob_array_iterator.h"
|
||||
#include "lib/container/ob_array_wrap.h"
|
||||
#include "lib/container/ob_heap.h"
|
||||
#include "lib/container/ob_rbtree.h"
|
||||
#include "lib/list/ob_list.h"
|
||||
#include "lib/lock/ob_thread_cond.h"
|
||||
#include "lib/profile/ob_trace_id.h"
|
||||
#include "lib/restore/ob_storage.h"
|
||||
#include "common/storage/ob_io_device.h"
|
||||
#include "lib/tc/ob_tc.h"
|
||||
#include "lib/worker.h"
|
||||
#include "share/resource_manager/ob_resource_plan_info.h"
|
||||
#ifdef OB_BUILD_SHARED_STORAGE
|
||||
#include "storage/shared_storage/micro_cache/ob_ss_micro_cache_common_meta.h"
|
||||
@ -33,7 +34,7 @@ namespace oceanbase
|
||||
{
|
||||
namespace share
|
||||
{
|
||||
class ObUnitConfig;
|
||||
class ObUnitConfig;
|
||||
}
|
||||
namespace backup
|
||||
{
|
||||
@ -45,38 +46,25 @@ namespace common
|
||||
|
||||
class ObObjectDevice;
|
||||
|
||||
//the timestamp adjustment will not adjust until the queue is idle for more than this time
|
||||
static constexpr int64_t CLOCK_IDLE_THRESHOLD_US = 100 * 1000L; // 100ms
|
||||
static constexpr int64_t DEFAULT_IO_WAIT_TIME_MS = 5000L; // 5s
|
||||
static constexpr int64_t MAX_IO_WAIT_TIME_MS = 300L * 1000L; // 5min
|
||||
// the timestamp adjustment will not adjust until the queue is idle for more than this time
|
||||
static constexpr int64_t CLOCK_IDLE_THRESHOLD_US = 100 * 1000L; // 100ms
|
||||
static constexpr int64_t DEFAULT_IO_WAIT_TIME_MS = 5000L; // 5s
|
||||
static constexpr int64_t MAX_IO_WAIT_TIME_MS = 300L * 1000L; // 5min
|
||||
static constexpr int64_t GROUP_START_NUM = 3L;
|
||||
static constexpr int64_t DEFAULT_IO_WAIT_TIME_US = 5000L * 1000L; // 5s
|
||||
static constexpr int64_t DEFAULT_IO_WAIT_TIME_US = 5000L * 1000L; // 5s
|
||||
static constexpr int64_t MAX_DETECT_READ_WARN_TIMES = 10L;
|
||||
static constexpr int64_t MAX_DETECT_READ_ERROR_TIMES = 100L;
|
||||
static constexpr int64_t DEFAULT_OBJECT_STORAGE_IO_TIMEOUT_MS = 20 * 1000L;
|
||||
|
||||
enum class ObIOMode : uint8_t
|
||||
{
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
MAX_MODE
|
||||
};
|
||||
enum class ObIOMode : uint8_t { READ = 0, WRITE = 1, MAX_MODE };
|
||||
|
||||
enum class ObIOGroupMode : uint8_t
|
||||
{
|
||||
LOCALREAD = 0,
|
||||
LOCALWRITE = 1,
|
||||
REMOTEREAD = 2,
|
||||
REMOTEWRITE = 3,
|
||||
MODECNT
|
||||
};
|
||||
enum class ObIOGroupMode : uint8_t { LOCALREAD = 0, LOCALWRITE = 1, REMOTEREAD = 2, REMOTEWRITE = 3, MODECNT };
|
||||
|
||||
enum class ObIOPriority : uint8_t
|
||||
{
|
||||
EMERGENT = 0, // 预留
|
||||
HIGH = 1, // 转储写、中间层索引读取
|
||||
MIDDLE = 2, // 合并写、临时文件写
|
||||
LOW = 3 // 后台任务读写,例如CRC校验
|
||||
enum class ObIOPriority : uint8_t {
|
||||
EMERGENT = 0, // 预留
|
||||
HIGH = 1, // 转储写、中间层索引读取
|
||||
MIDDLE = 2, // 合并写、临时文件写
|
||||
LOW = 3 // 后台任务读写,例如CRC校验
|
||||
};
|
||||
|
||||
const char *get_io_mode_string(const ObIOMode mode);
|
||||
@ -168,11 +156,9 @@ public:
|
||||
void set_need_close_dev_and_fd();
|
||||
void set_no_need_close_dev_and_fd();
|
||||
bool is_need_close_dev_and_fd() const;
|
||||
|
||||
TO_STRING_KV("mode", common::get_io_mode_string(static_cast<ObIOMode>(mode_)),
|
||||
K(group_id_), K(func_type_), K(wait_event_id_), K(is_sync_), K(is_unlimited_), K(is_detect_),
|
||||
K(is_write_through_), K(is_sealed_), K(is_time_detect_),
|
||||
K(need_close_dev_and_fd_), K(reserved_));
|
||||
TO_STRING_KV("mode", common::get_io_mode_string(static_cast<ObIOMode>(mode_)), K(group_id_), K(func_type_),
|
||||
K(wait_event_id_), K(is_sync_), K(is_unlimited_), K(is_detect_), K(is_write_through_), K(is_sealed_),
|
||||
K(is_time_detect_), K(need_close_dev_and_fd_), K(reserved_));
|
||||
|
||||
private:
|
||||
friend struct ObIOResult;
|
||||
@ -237,10 +223,20 @@ public:
|
||||
int alloc(T *&ptr);
|
||||
int recycle(T *ptr);
|
||||
bool contain(T *ptr);
|
||||
int64_t get_block_size() const { return obj_size_; }
|
||||
int64_t get_capacity() const { return capacity_; }
|
||||
int64_t get_free_cnt() const { return free_count_; }
|
||||
int64_t get_block_size() const
|
||||
{
|
||||
return obj_size_;
|
||||
}
|
||||
int64_t get_capacity() const
|
||||
{
|
||||
return capacity_;
|
||||
}
|
||||
int64_t get_free_cnt() const
|
||||
{
|
||||
return free_count_;
|
||||
}
|
||||
TO_STRING_KV(K(is_inited_), K(obj_size_), K(capacity_), K(free_count_), KP(allocator_), KP(start_ptr_));
|
||||
|
||||
private:
|
||||
bool is_inited_;
|
||||
int64_t obj_size_;
|
||||
@ -252,8 +248,7 @@ private:
|
||||
};
|
||||
|
||||
// different io callback types enqueue different io callback thread queue
|
||||
enum class ObIOCallbackType : uint8_t
|
||||
{
|
||||
enum class ObIOCallbackType : uint8_t {
|
||||
ATOMIC_WRITE_CALLBACK = 0,
|
||||
ASYNC_SINGLE_MICRO_BLOCK_CALLBACK = 1,
|
||||
MULTI_DATA_BLOCK_CALLBACK = 2,
|
||||
@ -286,11 +281,15 @@ public:
|
||||
virtual int64_t size() const = 0;
|
||||
virtual int alloc_data_buf(const char *io_data_buffer, const int64_t data_size) = 0;
|
||||
virtual int inner_process(const char *data_buffer, const int64_t size) = 0;
|
||||
ObIOCallbackType get_type() const { return type_; }
|
||||
ObIOCallbackType get_type() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
DECLARE_PURE_VIRTUAL_TO_STRING;
|
||||
|
||||
protected:
|
||||
static int alloc_and_copy_data(const char *io_data_buffer, const int64_t data_size, common::ObIAllocator *allocator, char *&data_buffer);
|
||||
static int alloc_and_copy_data(
|
||||
const char *io_data_buffer, const int64_t data_size, common::ObIAllocator *allocator, char *&data_buffer);
|
||||
|
||||
protected:
|
||||
ObIOCallbackType type_;
|
||||
@ -300,7 +299,7 @@ private:
|
||||
lib::Worker::CompatMode compat_mode_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
void free_io_callback(ObIOCallback *&io_callback)
|
||||
{
|
||||
if (OB_NOT_NULL(io_callback) && OB_NOT_NULL(io_callback->get_allocator())) {
|
||||
@ -322,8 +321,8 @@ public:
|
||||
virtual void reset();
|
||||
bool is_valid() const;
|
||||
ObSNIOInfo &operator=(const ObSNIOInfo &other);
|
||||
TO_STRING_KV(K(tenant_id_), K(fd_), K(offset_), K(size_), K(timeout_us_), K(flag_),
|
||||
KP(callback_), KP(buf_), KP(user_data_buf_), K_(part_id));
|
||||
TO_STRING_KV(K(tenant_id_), K(fd_), K(offset_), K(size_), K(timeout_us_), K(flag_), KP(callback_), KP(buf_),
|
||||
KP(user_data_buf_), K_(part_id));
|
||||
|
||||
public:
|
||||
uint64_t tenant_id_;
|
||||
@ -334,8 +333,8 @@ public:
|
||||
ObIOFlag flag_;
|
||||
ObIOCallback *callback_;
|
||||
const char *buf_;
|
||||
char *user_data_buf_; //actual data buf without cb, allocated by the calling layer
|
||||
int64_t part_id_; // multipart upload's part id
|
||||
char *user_data_buf_; // actual data buf without cb, allocated by the calling layer
|
||||
int64_t part_id_; // multipart upload's part id
|
||||
};
|
||||
|
||||
#ifdef OB_BUILD_SHARED_STORAGE
|
||||
@ -347,8 +346,9 @@ public:
|
||||
virtual ~ObSSIOInfo();
|
||||
virtual void reset() override;
|
||||
ObSSIOInfo &operator=(const ObSSIOInfo &other);
|
||||
|
||||
public:
|
||||
storage::ObSSPhysicalBlockHandle phy_block_handle_; // hold ref_cnt
|
||||
storage::ObSSPhysicalBlockHandle phy_block_handle_; // hold ref_cnt
|
||||
storage::ObSSFdCacheHandle fd_cache_handle_;
|
||||
int64_t tmp_file_valid_length_;
|
||||
|
||||
@ -366,24 +366,37 @@ template <typename T>
|
||||
class ObRefHolder final
|
||||
{
|
||||
public:
|
||||
explicit ObRefHolder(): ptr_(nullptr) {}
|
||||
explicit ObRefHolder(T *ptr): ptr_(nullptr) { hold(ptr); }
|
||||
~ObRefHolder() { reset(); }
|
||||
T *get_ptr() { return ptr_; }
|
||||
void hold(T *ptr) {
|
||||
explicit ObRefHolder() : ptr_(nullptr)
|
||||
{}
|
||||
explicit ObRefHolder(T *ptr) : ptr_(nullptr)
|
||||
{
|
||||
hold(ptr);
|
||||
}
|
||||
~ObRefHolder()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
T *get_ptr()
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
void hold(T *ptr)
|
||||
{
|
||||
if (nullptr != ptr && ptr != ptr_) {
|
||||
ptr->inc_ref();
|
||||
reset(); // reset previous ptr, must after ptr->inc_ref()
|
||||
reset(); // reset previous ptr, must after ptr->inc_ref()
|
||||
ptr_ = ptr;
|
||||
}
|
||||
}
|
||||
void reset() {
|
||||
void reset()
|
||||
{
|
||||
if (nullptr != ptr_) {
|
||||
ptr_->dec_ref();
|
||||
ptr_ = nullptr;
|
||||
}
|
||||
}
|
||||
TO_STRING_KV(KP_(ptr));
|
||||
|
||||
private:
|
||||
T *ptr_;
|
||||
};
|
||||
@ -395,15 +408,14 @@ public:
|
||||
~ObIOTimeLog();
|
||||
void reset();
|
||||
// Note: -1 represents invalid value
|
||||
TO_STRING_KV(K_(begin_ts),
|
||||
"enqueue_used", (enqueue_ts_ > 0 ? enqueue_ts_ - begin_ts_ : -1),
|
||||
"dequeue_used", (dequeue_ts_ > 0 ? dequeue_ts_ - enqueue_ts_ : -1),
|
||||
"submit_used", (submit_ts_ > 0 ? submit_ts_ - dequeue_ts_ : -1),
|
||||
"return_used", (return_ts_ > 0 ? return_ts_ - submit_ts_ : -1),
|
||||
"callback_enqueue_used", (callback_enqueue_ts_ > 0 ? callback_enqueue_ts_ - return_ts_ : -1),
|
||||
"callback_dequeue_used", (callback_dequeue_ts_ > 0 ? callback_dequeue_ts_ - callback_enqueue_ts_ : -1),
|
||||
"callback_finish_used", (callback_finish_ts_ > 0 ? callback_finish_ts_ - callback_dequeue_ts_ : -1),
|
||||
"end_used", (end_ts_ > 0 ? end_ts_ - callback_finish_ts_ : -1));
|
||||
TO_STRING_KV(K_(begin_ts), "enqueue_used", (enqueue_ts_ > 0 ? enqueue_ts_ - begin_ts_ : -1), "dequeue_used",
|
||||
(dequeue_ts_ > 0 ? dequeue_ts_ - enqueue_ts_ : -1), "submit_used",
|
||||
(submit_ts_ > 0 ? submit_ts_ - dequeue_ts_ : -1), "return_used", (return_ts_ > 0 ? return_ts_ - submit_ts_ : -1),
|
||||
"callback_enqueue_used", (callback_enqueue_ts_ > 0 ? callback_enqueue_ts_ - return_ts_ : -1),
|
||||
"callback_dequeue_used", (callback_dequeue_ts_ > 0 ? callback_dequeue_ts_ - callback_enqueue_ts_ : -1),
|
||||
"callback_finish_used", (callback_finish_ts_ > 0 ? callback_finish_ts_ - callback_dequeue_ts_ : -1), "end_used",
|
||||
(end_ts_ > 0 ? end_ts_ - callback_finish_ts_ : -1));
|
||||
|
||||
public:
|
||||
int64_t begin_ts_;
|
||||
int64_t enqueue_ts_;
|
||||
@ -426,6 +438,7 @@ public:
|
||||
~ObIORetCode();
|
||||
void reset();
|
||||
TO_STRING_KV(K(io_ret_), K(fs_errno_));
|
||||
|
||||
public:
|
||||
int io_ret_;
|
||||
int fs_errno_;
|
||||
@ -439,22 +452,80 @@ class ObIORequest;
|
||||
|
||||
struct ObIOGroupKey
|
||||
{
|
||||
ObIOGroupKey() : group_id_(0), mode_(ObIOMode::MAX_MODE) {}
|
||||
ObIOGroupKey(uint64_t group_id, ObIOMode mode) : group_id_(group_id), mode_(mode) {}
|
||||
int hash(uint64_t &res) const { res = ((uint64_t)mode_) << 56 | group_id_; return OB_SUCCESS; }
|
||||
bool operator==(const ObIOGroupKey &that) const { return group_id_ == that.group_id_ && mode_ == that.mode_; }
|
||||
ObIOGroupKey() : group_id_(0), mode_(ObIOMode::MAX_MODE)
|
||||
{}
|
||||
ObIOGroupKey(uint64_t group_id, ObIOMode mode) : group_id_(group_id), mode_(mode)
|
||||
{}
|
||||
int hash(uint64_t &res) const
|
||||
{
|
||||
res = ((uint64_t)mode_) << 56 | group_id_;
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
uint64_t hash() const
|
||||
{
|
||||
return ((uint64_t)mode_) << 56 | group_id_;
|
||||
}
|
||||
bool operator==(const ObIOGroupKey &that) const
|
||||
{
|
||||
return group_id_ == that.group_id_ && mode_ == that.mode_;
|
||||
}
|
||||
ObIOGroupKey& operator=(const ObIOGroupKey &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
group_id_ = other.group_id_;
|
||||
mode_ = other.mode_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
uint64_t group_id_;
|
||||
ObIOMode mode_;
|
||||
TO_STRING_KV(K(group_id_), K(mode_));
|
||||
};
|
||||
|
||||
struct ObIOSSGrpKey
|
||||
{
|
||||
ObIOSSGrpKey() : tenant_id_(0), group_key_()
|
||||
{}
|
||||
ObIOSSGrpKey(const int64_t tenant_id, const ObIOGroupKey group_key) : tenant_id_(tenant_id), group_key_(group_key)
|
||||
{}
|
||||
uint64_t hash() const
|
||||
{
|
||||
uint64_t hash_val = static_cast<uint64_t>(tenant_id_);
|
||||
uint64_t hash_val_2 = static_cast<uint64_t>(group_key_.hash());
|
||||
hash_val = common::murmurhash(&hash_val_2, sizeof(hash_val_2), hash_val);
|
||||
return hash_val;
|
||||
}
|
||||
int hash(uint64_t &hash_val) const
|
||||
{
|
||||
hash_val = hash();
|
||||
return common::OB_SUCCESS;
|
||||
}
|
||||
bool operator==(const ObIOSSGrpKey &that) const
|
||||
{
|
||||
return tenant_id_ == that.tenant_id_ && group_key_ == that.group_key_;
|
||||
}
|
||||
ObIOSSGrpKey& operator=(const ObIOSSGrpKey &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
tenant_id_ = other.tenant_id_;
|
||||
group_key_ = other.group_key_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ObIOMode get_mode() const { return group_key_.mode_; };
|
||||
int64_t tenant_id_;
|
||||
ObIOGroupKey group_key_;
|
||||
TO_STRING_KV(K(tenant_id_), K(group_key_));
|
||||
};
|
||||
|
||||
|
||||
class ObIOResult final
|
||||
{
|
||||
public:
|
||||
ObIOResult();
|
||||
~ObIOResult();
|
||||
bool is_valid() const;
|
||||
int basic_init(); //for pool
|
||||
int basic_init(); // for pool
|
||||
int init(const ObIOInfo &info);
|
||||
void reset();
|
||||
void destroy();
|
||||
@ -525,7 +596,7 @@ public:
|
||||
virtual ~ObIORequest();
|
||||
bool is_valid() const;
|
||||
int init(const ObIOInfo &info, ObIOResult *result);
|
||||
int basic_init(); //for pool
|
||||
int basic_init(); // for pool
|
||||
virtual void destroy();
|
||||
virtual void reset();
|
||||
void free();
|
||||
@ -536,7 +607,7 @@ public:
|
||||
ObIOGroupKey get_group_key() const;
|
||||
uint64_t get_sys_module_id() const;
|
||||
bool is_sys_module() const;
|
||||
char *calc_io_buf(); //calc the aligned io_buf of raw_buf_, which interact with the operating system
|
||||
char *calc_io_buf(); // calc the aligned io_buf of raw_buf_, which interact with the operating system
|
||||
const ObIOFlag &get_flag() const;
|
||||
ObIOMode get_mode() const;
|
||||
ObIOGroupMode get_group_mode() const;
|
||||
@ -560,6 +631,7 @@ public:
|
||||
K(trace_id_), K(retry_count_), K(tenant_io_mgr_), K_(storage_accesser),
|
||||
KPC(io_result_), K_(part_id));
|
||||
private:
|
||||
friend class ObTenantIOSchedulerV2;
|
||||
friend class ObDeviceChannel;
|
||||
friend class ObIOManager;
|
||||
friend class ObIOResult;
|
||||
@ -575,7 +647,7 @@ private:
|
||||
friend class ObTenantIOClock;
|
||||
friend class ObTrafficControl;
|
||||
friend class backup::ObBackupDeviceHelper;
|
||||
const char *get_io_data_buf(); //get data buf for MEMCPY before io_buf recycle
|
||||
const char *get_io_data_buf(); // get data buf for MEMCPY before io_buf recycle
|
||||
int alloc_aligned_io_buf(char *&io_buf);
|
||||
virtual int set_block_handle(const ObIOInfo &info);
|
||||
virtual int set_fd_cache_handle(const ObIOInfo &io_info);
|
||||
@ -583,6 +655,7 @@ private:
|
||||
int calc_io_offset_and_size_();
|
||||
public:
|
||||
ObIOResult *io_result_;
|
||||
TCRequest qsched_req_;
|
||||
protected:
|
||||
bool is_inited_;
|
||||
int8_t retry_count_;
|
||||
@ -606,23 +679,29 @@ class ObPhyQueue final
|
||||
public:
|
||||
ObPhyQueue();
|
||||
~ObPhyQueue();
|
||||
bool is_stop_accept() { return stop_accept_; }
|
||||
bool is_stop_accept()
|
||||
{
|
||||
return stop_accept_;
|
||||
}
|
||||
int init(const int64_t index);
|
||||
void destroy();
|
||||
void reset_time_info();
|
||||
void reset_queue_info();
|
||||
void set_stop_accept() { stop_accept_ = true; }
|
||||
void set_stop_accept()
|
||||
{
|
||||
stop_accept_ = true;
|
||||
}
|
||||
bool reach_adjust_interval();
|
||||
|
||||
public:
|
||||
TO_STRING_KV(K_(reservation_ts), K_(limitation_ts),
|
||||
K_(stop_accept), K_(last_empty_ts));
|
||||
TO_STRING_KV(K_(reservation_ts), K_(limitation_ts), K_(stop_accept), K_(last_empty_ts));
|
||||
bool is_inited_;
|
||||
bool stop_accept_;
|
||||
int64_t reservation_ts_;
|
||||
int64_t limitation_ts_;
|
||||
int64_t proportion_ts_;
|
||||
int64_t last_empty_ts_;
|
||||
int64_t queue_index_; //index in array, INT64_MAX means other
|
||||
int64_t queue_index_; // index in array, INT64_MAX means other
|
||||
int64_t reservation_pos_;
|
||||
int64_t limitation_pos_;
|
||||
int64_t proportion_pos_;
|
||||
@ -639,9 +718,12 @@ public:
|
||||
int set_result(ObIOResult &result);
|
||||
bool is_empty() const;
|
||||
bool is_valid() const;
|
||||
OB_INLINE bool is_finished() const { return nullptr != result_ && result_->is_finished_; }
|
||||
OB_INLINE bool is_finished() const
|
||||
{
|
||||
return nullptr != result_ && result_->is_finished_;
|
||||
}
|
||||
|
||||
int wait(const int64_t wait_timeout_ms=UINT64_MAX);
|
||||
int wait(const int64_t wait_timeout_ms = UINT64_MAX);
|
||||
const char *get_buffer();
|
||||
int64_t get_data_size() const;
|
||||
int64_t get_rt() const;
|
||||
@ -655,6 +737,7 @@ public:
|
||||
void clear_io_callback();
|
||||
ObIOCallback *get_io_callback();
|
||||
TO_STRING_KV("io_result", to_cstring(result_));
|
||||
|
||||
private:
|
||||
void estimate();
|
||||
|
||||
@ -662,7 +745,6 @@ private:
|
||||
ObIOResult *result_;
|
||||
};
|
||||
|
||||
|
||||
struct ObTenantIOConfig final
|
||||
{
|
||||
public:
|
||||
@ -684,15 +766,11 @@ public:
|
||||
GroupConfig();
|
||||
~GroupConfig();
|
||||
bool is_valid() const;
|
||||
TO_STRING_KV(K_(mode),
|
||||
K_(deleted),
|
||||
K_(cleared),
|
||||
K_(min_percent),
|
||||
K_(max_percent),
|
||||
K_(weight_percent));
|
||||
TO_STRING_KV(K_(mode), K_(deleted), K_(cleared), K_(min_percent), K_(max_percent), K_(weight_percent));
|
||||
|
||||
public:
|
||||
bool deleted_; //group被删除的标记
|
||||
bool cleared_; //group被清零的标记,以后有新的directive就会重置
|
||||
bool deleted_; // group被删除的标记
|
||||
bool cleared_; // group被清零的标记,以后有新的directive就会重置
|
||||
char group_name_[common::OB_MAX_RESOURCE_PLAN_NAME_LENGTH];
|
||||
int64_t min_percent_;
|
||||
int64_t max_percent_;
|
||||
@ -710,43 +788,41 @@ public:
|
||||
bool is_valid() const;
|
||||
int deep_copy(const ObTenantIOConfig &other_config);
|
||||
int parse_group_config(const char *config_str);
|
||||
int add_single_group_config(const uint64_t tenant_id,
|
||||
const ObIOGroupKey &key,
|
||||
const char *group_name,
|
||||
int64_t min_percent,
|
||||
int64_t max_percent,
|
||||
int64_t weight_percent);
|
||||
int add_single_group_config(const uint64_t tenant_id, const ObIOGroupKey &key, const char *group_name,
|
||||
int64_t min_percent, int64_t max_percent, int64_t weight_percent);
|
||||
int get_group_config(const uint64_t index, int64_t &min, int64_t &max, int64_t &weight) const;
|
||||
int64_t get_callback_thread_count() const;
|
||||
int64_t to_string(char* buf, const int64_t buf_len) const;
|
||||
int64_t to_string(char *buf, const int64_t buf_len) const;
|
||||
|
||||
public:
|
||||
int64_t memory_limit_;
|
||||
int64_t callback_thread_count_;
|
||||
UnitConfig unit_config_;
|
||||
ObSEArray <GroupConfig, GROUP_START_NUM * 3> group_configs_;
|
||||
ObSEArray<GroupConfig, GROUP_START_NUM * 3> group_configs_;
|
||||
bool group_config_change_;
|
||||
bool enable_io_tracer_;
|
||||
int64_t object_storage_io_timeout_ms_;
|
||||
};
|
||||
|
||||
|
||||
struct ObAtomIOClock final
|
||||
{
|
||||
ObAtomIOClock() : iops_(0), last_ns_(0) {}
|
||||
ObAtomIOClock() : iops_(0), last_ns_(0)
|
||||
{}
|
||||
void atom_update(const int64_t current_ts, const double iops_scale, int64_t &deadline_ts);
|
||||
void compare_and_update(const int64_t current_ts, const double iops_scale, int64_t &deadline_ts);
|
||||
void reset();
|
||||
TO_STRING_KV(K_(iops), K_(last_ns));
|
||||
int64_t iops_;
|
||||
int64_t last_ns_; // the unit is nano sescond for max iops of 1 billion
|
||||
int64_t last_ns_; // the unit is nano sescond for max iops of 1 billion
|
||||
};
|
||||
|
||||
class ObIOQueue
|
||||
{
|
||||
public:
|
||||
ObIOQueue() {}
|
||||
virtual ~ObIOQueue() {}
|
||||
ObIOQueue()
|
||||
{}
|
||||
virtual ~ObIOQueue()
|
||||
{}
|
||||
virtual int init() = 0;
|
||||
virtual void destroy() = 0;
|
||||
DECLARE_PURE_VIRTUAL_TO_STRING;
|
||||
@ -759,41 +835,53 @@ public:
|
||||
virtual ~ObMClockQueue();
|
||||
virtual int init() override;
|
||||
virtual void destroy() override;
|
||||
int get_time_info(int64_t &reservation_ts,
|
||||
int64_t &limitation_ts,
|
||||
int64_t &proportion_ts);
|
||||
int get_time_info(int64_t &reservation_ts, int64_t &limitation_ts, int64_t &proportion_ts);
|
||||
int push_phyqueue(ObPhyQueue *phy_queue);
|
||||
int pop_phyqueue(ObIORequest *&req, int64_t &deadline_ts);
|
||||
TO_STRING_KV(K(is_inited_), K(r_heap_.count()), K(l_heap_.count()), K(ready_heap_.count()));
|
||||
|
||||
int remove_from_heap(ObPhyQueue *phy_queue);
|
||||
|
||||
private:
|
||||
int pop_with_ready_queue(const int64_t current_ts, ObIORequest *&req, int64_t &deadline_ts);
|
||||
|
||||
template<typename T, int64_t T::*member_ts, IOReqList T::*list>
|
||||
struct HeapCompare {
|
||||
int get_error_code() { return OB_SUCCESS; }
|
||||
bool operator() (const T *left, const T *right) const {
|
||||
return left->*member_ts != right->*member_ts ? left->*member_ts > right->*member_ts :
|
||||
(left->*list).get_size() != (right->*list).get_size() ? (left->*list).get_size() < (right->*list).get_size() : (int64_t)left > (int64_t)right;
|
||||
template <typename T, int64_t T::*member_ts, IOReqList T::*list>
|
||||
struct HeapCompare
|
||||
{
|
||||
int get_error_code()
|
||||
{
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
bool operator()(const T *left, const T *right) const
|
||||
{
|
||||
return left->*member_ts != right->*member_ts ? left->*member_ts > right->*member_ts
|
||||
: (left->*list).get_size() != (right->*list).get_size()
|
||||
? (left->*list).get_size() < (right->*list).get_size()
|
||||
: (int64_t)left > (int64_t)right;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static const int64_t POP_MORE_PHY_QUEUE_USEC = 1000; //1ms
|
||||
static const int64_t POP_MORE_PHY_QUEUE_USEC = 1000; // 1ms
|
||||
private:
|
||||
bool is_inited_;
|
||||
HeapCompare<ObPhyQueue, &ObPhyQueue::reservation_ts_, &ObPhyQueue::req_list_> r_cmp_;
|
||||
HeapCompare<ObPhyQueue, &ObPhyQueue::limitation_ts_, &ObPhyQueue::req_list_> l_cmp_;
|
||||
HeapCompare<ObPhyQueue, &ObPhyQueue::proportion_ts_, &ObPhyQueue::req_list_> p_cmp_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::reservation_ts_, &ObPhyQueue::req_list_>, &ObPhyQueue::reservation_pos_> r_heap_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::limitation_ts_, &ObPhyQueue::req_list_>, &ObPhyQueue::limitation_pos_> l_heap_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::proportion_ts_, &ObPhyQueue::req_list_>, &ObPhyQueue::proportion_pos_> ready_heap_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::reservation_ts_, &ObPhyQueue::req_list_>,
|
||||
&ObPhyQueue::reservation_pos_>
|
||||
r_heap_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::limitation_ts_, &ObPhyQueue::req_list_>,
|
||||
&ObPhyQueue::limitation_pos_>
|
||||
l_heap_;
|
||||
ObRemovableHeap<ObPhyQueue *, HeapCompare<ObPhyQueue, &ObPhyQueue::proportion_ts_, &ObPhyQueue::req_list_>,
|
||||
&ObPhyQueue::proportion_pos_>
|
||||
ready_heap_;
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
ObIOObjectPool<T, U>::ObIOObjectPool()
|
||||
: is_inited_(false), obj_size_(0), capacity_(0), free_count_(0), allocator_(nullptr), start_ptr_(nullptr)
|
||||
: is_inited_(false), obj_size_(0), capacity_(0), free_count_(0), allocator_(nullptr), start_ptr_(nullptr)
|
||||
{
|
||||
static_assert(std::is_base_of<T, U>::value, "U must be T or subclass of T");
|
||||
}
|
||||
@ -827,7 +915,7 @@ int ObIOObjectPool<T, U>::init(const int64_t count, ObIAllocator &allocator)
|
||||
// do nothing
|
||||
} else if (OB_FAIL(pool_.init(capacity_, allocator_))) {
|
||||
COMMON_LOG(WARN, "fail to init memory pool", K(ret));
|
||||
} else if (OB_ISNULL(start_ptr_ = reinterpret_cast<char *>(allocator_->alloc(capacity_ * size)))){
|
||||
} else if (OB_ISNULL(start_ptr_ = reinterpret_cast<char *>(allocator_->alloc(capacity_ * size)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
COMMON_LOG(WARN, "fail to allocate IOobj memory", K(ret), K(capacity_), K(size));
|
||||
} else {
|
||||
@ -896,7 +984,7 @@ int ObIOObjectPool<T, U>::recycle(T *ptr)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
static_assert(std::is_base_of<T, U>::value, "U must be T or subclass of T");
|
||||
const int64_t idx = ((char*) ptr - start_ptr_) / obj_size_;
|
||||
const int64_t idx = ((char *)ptr - start_ptr_) / obj_size_;
|
||||
if (OB_UNLIKELY(!is_inited_)) {
|
||||
ret = OB_NOT_INIT;
|
||||
COMMON_LOG(WARN, "not init", K(ret));
|
||||
@ -917,14 +1005,12 @@ template <typename T, typename U>
|
||||
bool ObIOObjectPool<T, U>::contain(T *ptr)
|
||||
{
|
||||
static_assert(std::is_base_of<T, U>::value, "U must be T or subclass of T");
|
||||
bool bret = (uint64_t) ptr > 0
|
||||
&& ((char *)ptr >= start_ptr_)
|
||||
&& ((char *)ptr < start_ptr_ + (capacity_ * obj_size_))
|
||||
&& (((char *)ptr - start_ptr_) % obj_size_ == 0);
|
||||
bool bret = (uint64_t)ptr > 0 && ((char *)ptr >= start_ptr_) &&
|
||||
((char *)ptr < start_ptr_ + (capacity_ * obj_size_)) && (((char *)ptr - start_ptr_) % obj_size_ == 0);
|
||||
return bret;
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace oceanbase
|
||||
} // namespace common
|
||||
} // namespace oceanbase
|
||||
|
||||
#endif//OCEANBASE_LIB_STORAGE_IO_DEFINE
|
||||
#endif // OCEANBASE_LIB_STORAGE_IO_DEFINE
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "share/errsim_module/ob_errsim_module_interface_imp.h"
|
||||
#include "share/resource_manager/ob_cgroup_ctrl.h"
|
||||
#include "observer/ob_server.h"
|
||||
#include "src/share/io/io_schedule/ob_io_schedule_v2.h"
|
||||
#include "share/ob_io_device_helper.h"
|
||||
#ifdef OB_BUILD_SHARED_STORAGE
|
||||
#include "share/io/ob_ss_io_request.h"
|
||||
@ -123,12 +124,121 @@ void ObTrafficControl::ObSharedDeviceControl::set_limit(const obrpc::ObSharedDev
|
||||
}
|
||||
}
|
||||
|
||||
ObTrafficControl::ObSharedDeviceControlV2::ObSharedDeviceControlV2()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
ObTrafficControl::ObSharedDeviceControlV2::~ObSharedDeviceControlV2()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::init()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
memset(limit_ids_, -1, sizeof(limit_ids_));
|
||||
limits_[obrpc::ResourceType::ops] = INT64_MAX / 2;
|
||||
limits_[obrpc::ResourceType::ips] = INT64_MAX / 2;
|
||||
limits_[obrpc::ResourceType::iops] = INT64_MAX;
|
||||
limits_[obrpc::ResourceType::obw] = INT64_MAX / (16 * (1<<11));
|
||||
limits_[obrpc::ResourceType::ibw] = INT64_MAX / (16 * (1<<11));
|
||||
limits_[obrpc::ResourceType::iobw] = INT64_MAX / (16 * (1<<10));
|
||||
limits_[obrpc::ResourceType::tag] = INT64_MAX;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::destroy()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_FAIL(group_list_.clear())) {
|
||||
LOG_WARN("clear map failed", K(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::add_shared_device_limits()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
limit_ids_[static_cast<int>(ResourceType::ips)] = tclimit_create(TCLIMIT_COUNT, get_resource_type_str(ResourceType::ips));
|
||||
limit_ids_[static_cast<int>(ResourceType::ibw)] = tclimit_create(TCLIMIT_BYTES, get_resource_type_str(ResourceType::ibw));
|
||||
limit_ids_[static_cast<int>(ResourceType::ops)] = tclimit_create(TCLIMIT_COUNT, get_resource_type_str(ResourceType::ops));
|
||||
limit_ids_[static_cast<int>(ResourceType::obw)] = tclimit_create(TCLIMIT_BYTES, get_resource_type_str(ResourceType::obw));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::fill_qsched_req_ss_limits(ObIORequest& req)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (ObIOMode::READ == req.get_mode()) {
|
||||
req.qsched_req_.ss_limiter_ids_[0] = limit_ids_[static_cast<int>(ResourceType::ips)];
|
||||
req.qsched_req_.ss_limiter_ids_[1] = limit_ids_[static_cast<int>(ResourceType::ibw)];
|
||||
} else if (ObIOMode::WRITE == req.get_mode()) {
|
||||
req.qsched_req_.ss_limiter_ids_[0] = limit_ids_[static_cast<int>(ResourceType::ops)];
|
||||
req.qsched_req_.ss_limiter_ids_[1] = limit_ids_[static_cast<int>(ResourceType::obw)];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::add_group(const ObIOSSGrpKey &grp_key, const int qid) {
|
||||
return group_list_.add_group(grp_key, qid, limit_ids_, ResourceType::ResourceTypeCnt);
|
||||
}
|
||||
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::add_group(const ObIOSSGrpKey &grp_key, const int qid, int* limit_ids, int l_size)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
// add group limits of shared device
|
||||
if (l_size > ResourceType::ResourceTypeCnt) {
|
||||
LOG_ERROR("l_size is bigger than ResourceTypeCnt", K(l_size), K(ResourceType::ResourceTypeCnt), K(grp_key), K(ret));
|
||||
} else if (OB_UNLIKELY(OB_HASH_NOT_EXIST != is_group_key_exist(grp_key))) {
|
||||
LOG_WARN("repeat add the group limit ", K(ret), K(grp_key));
|
||||
} else if (OB_FAIL(grp_list_.push_back(grp_key))) {
|
||||
LOG_WARN("grp list push back failed", K(ret), K(grp_key));
|
||||
} else if (ObIOMode::READ == grp_key.get_mode()) {
|
||||
if (OB_FAIL(qdisc_add_limit(qid, limit_ids[static_cast<int>(ResourceType::ips)]))) {
|
||||
LOG_ERROR("qdiscadd_limit fail" , K(ret), K(qid), K(ResourceType::ips));
|
||||
} else if (OB_FAIL(qdisc_add_limit(qid, limit_ids[static_cast<int>(ResourceType::ibw)]))) {
|
||||
LOG_ERROR("qdiscadd_limit fail" , K(ret), K(qid), K(ResourceType::ibw));
|
||||
}
|
||||
} else if (ObIOMode::WRITE == grp_key.get_mode()) {
|
||||
if (OB_FAIL(qdisc_add_limit(qid, limit_ids[static_cast<int>(ResourceType::ops)]))) {
|
||||
LOG_ERROR("qdiscadd_limit fail" , K(ret), K(qid), K(ResourceType::ops), K(grp_key));
|
||||
} else if (OB_FAIL(qdisc_add_limit(qid, limit_ids[static_cast<int>(ResourceType::obw)]))) {
|
||||
LOG_ERROR("qdiscadd_limit fail" , K(ret), K(qid), K(ResourceType::obw), K(grp_key));
|
||||
}
|
||||
}
|
||||
LOG_INFO("add group limit of shared device success", K(grp_key), K(qid), K(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::is_group_key_exist(const ObIOSSGrpKey &grp_key)
|
||||
{
|
||||
return group_list_.is_group_key_exist(grp_key);
|
||||
}
|
||||
|
||||
int64_t ObTrafficControl::ObSharedDeviceControlV2::get_limit(const obrpc::ResourceType type) const
|
||||
{
|
||||
return limits_[static_cast<int>(type)];
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::update_limit(const obrpc::ObSharedDeviceResource &limit)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
limits_[static_cast<int>(limit.type_)] = limit.value_;
|
||||
if (OB_FAIL(tclimit_set_limit(limit_ids_[static_cast<int>(limit.type_)], limits_[static_cast<int>(limit.type_)]))) {
|
||||
LOG_WARN("update limit failed", K(ret), K(limit), K(limit_ids_[static_cast<int>(limit.type_)]));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
ObTrafficControl::ObTrafficControl()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
set_device_bandwidth(observer::ObServer::DEFAULT_ETHERNET_SPEED);
|
||||
if (OB_FAIL(shared_device_map_.create(7, "IO_TC_MAP"))) {
|
||||
LOG_WARN("create io share device map failed", K(ret));
|
||||
} else if (OB_FAIL(shared_device_map_v2_.create(7, "IO_TC_MAP_V2"))) {
|
||||
LOG_WARN("create io share device map v2 failed", K(ret));
|
||||
}
|
||||
if (OB_FAIL(io_record_map_.create(1, "IO_TC_MAP"))) {
|
||||
LOG_WARN("create io share device map failed", K(ret));
|
||||
@ -215,8 +325,28 @@ int ObTrafficControl::calc_usage(ObIORequest &req)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObTrafficControl::print_server_status()
|
||||
{
|
||||
inner_calc_();
|
||||
int64_t net_bw_in = net_ibw_.calc();
|
||||
int64_t net_bw_out = net_obw_.calc();
|
||||
int64_t shared_storage_bw_in = shared_storage_ibw_.calc();
|
||||
int64_t shared_storage_bw_out = shared_storage_obw_.calc();
|
||||
int64_t failed_shared_storage_bw_in = failed_shared_storage_ibw_.calc();
|
||||
int64_t failed_shared_storage_bw_out = failed_shared_storage_obw_.calc();
|
||||
if (net_bw_in || net_bw_out || shared_storage_bw_in || shared_storage_bw_out) {
|
||||
_LOG_INFO("[IO STATUS SERVER] net_in=%ldkB/s, net_out=%ldkB/s, bucket_in=%ldkB/s, bucket_out=%ldkB/s, failed_bucket_in=%ldkB/s, failed_bucket_out=%ldkB/s, limit=%ldkB/s",
|
||||
net_bw_in / 1024,
|
||||
net_bw_out / 1024,
|
||||
shared_storage_bw_in / 1024,
|
||||
shared_storage_bw_out / 1024,
|
||||
failed_shared_storage_bw_in / 1024,
|
||||
failed_shared_storage_bw_out / 1024,
|
||||
device_bandwidth_ / 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void ObTrafficControl::print_status()
|
||||
void ObTrafficControl::print_bucket_status_V1()
|
||||
{
|
||||
struct PrinterFn
|
||||
{
|
||||
@ -270,27 +400,65 @@ void ObTrafficControl::print_status()
|
||||
}
|
||||
const hash::ObHashMap<ObIORecordKey, ObSharedDeviceIORecord> &map_;
|
||||
};
|
||||
inner_calc_();
|
||||
int64_t net_bw_in = net_ibw_.calc();
|
||||
int64_t net_bw_out = net_obw_.calc();
|
||||
int64_t shared_storage_bw_in = shared_storage_ibw_.calc();
|
||||
int64_t shared_storage_bw_out = shared_storage_obw_.calc();
|
||||
int64_t failed_shared_storage_bw_in = failed_shared_storage_ibw_.calc();
|
||||
int64_t failed_shared_storage_bw_out = failed_shared_storage_obw_.calc();
|
||||
if (net_bw_in || net_bw_out || shared_storage_bw_in || shared_storage_bw_out) {
|
||||
_LOG_INFO("[IO STATUS SERVER] net_in=%ldkB/s, net_out=%ldkB/s, bucket_in=%ldkB/s, bucket_out=%ldkB/s, failed_bucket_in=%ldkB/s, failed_bucket_out=%ldkB/s, limit=%ldkB/s",
|
||||
net_bw_in / 1024,
|
||||
net_bw_out / 1024,
|
||||
shared_storage_bw_in / 1024,
|
||||
shared_storage_bw_out / 1024,
|
||||
failed_shared_storage_bw_in / 1024,
|
||||
failed_shared_storage_bw_out / 1024,
|
||||
device_bandwidth_ / 1024);
|
||||
}
|
||||
PrinterFn fn(io_record_map_);
|
||||
shared_device_map_.foreach_refactored(fn);
|
||||
}
|
||||
|
||||
void ObTrafficControl::print_bucket_status_V2()
|
||||
{
|
||||
struct PrinterFn
|
||||
{
|
||||
struct CalFn
|
||||
{
|
||||
CalFn(const ObStorageKey &key, int64_t &bw_in, int64_t &bw_out, int64_t &req_in, int64_t &req_out, int64_t &tag)
|
||||
: key_(key), bw_in_(bw_in), bw_out_(bw_out), req_in_(req_in), req_out_(req_out), tag_(tag) {}
|
||||
int operator () (oceanbase::common::hash::HashMapPair<ObIORecordKey, ObSharedDeviceIORecord> &entry) {
|
||||
if (key_ == entry.first.id_) {
|
||||
bw_in_ += entry.second.ibw_.calc();
|
||||
bw_out_ += entry.second.obw_.calc();
|
||||
req_in_ += entry.second.ips_.calc();
|
||||
req_out_ += entry.second.ops_.calc();
|
||||
tag_ += entry.second.tagps_.calc();
|
||||
}
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
const ObStorageKey &key_;
|
||||
int64_t &bw_in_;
|
||||
int64_t &bw_out_;
|
||||
int64_t &req_in_;
|
||||
int64_t &req_out_;
|
||||
int64_t &tag_;
|
||||
};
|
||||
PrinterFn(const hash::ObHashMap<ObIORecordKey, ObSharedDeviceIORecord> &map) : map_(map) {}
|
||||
int operator () (oceanbase::common::hash::HashMapPair<ObStorageKey, ObSharedDeviceControlV2> &entry) {
|
||||
int64_t bw_in = 0;
|
||||
int64_t bw_out = 0;
|
||||
int64_t req_in = 0;
|
||||
int64_t req_out = 0;
|
||||
int64_t tag = 0;
|
||||
CalFn fn(entry.first, bw_in, bw_out, req_in, req_out, tag);
|
||||
map_.foreach_refactored(fn);
|
||||
if (bw_in || bw_out || req_in || req_out || tag) {
|
||||
_LOG_INFO("[IO STATUS BUCKET] storage={%u, %ld, %ld}, in=[%ld / %ld]kB/s, out=[%ld / %ld]kB/s, ips=[%ld / %ld], ops=[%ld / %ld]",
|
||||
entry.first.get_category(),
|
||||
entry.first.get_tenant_id(),
|
||||
entry.first.get_storage_id(),
|
||||
bw_in / 1024,
|
||||
entry.second.limits_[static_cast<int>(ResourceType::ibw)] / 1024,
|
||||
bw_out / 1024,
|
||||
entry.second.limits_[static_cast<int>(ResourceType::obw)] / 1024,
|
||||
req_in,
|
||||
entry.second.limits_[static_cast<int>(ResourceType::ips)],
|
||||
req_out,
|
||||
entry.second.limits_[static_cast<int>(ResourceType::ops)]);
|
||||
}
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
const hash::ObHashMap<ObIORecordKey, ObSharedDeviceIORecord> &map_;
|
||||
};
|
||||
PrinterFn fn(io_record_map_);
|
||||
shared_device_map_v2_.foreach_refactored(fn);
|
||||
}
|
||||
int ObTrafficControl::set_limit(const obrpc::ObSharedDeviceResourceArray &limit)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
@ -307,19 +475,123 @@ int ObTrafficControl::set_limit(const obrpc::ObSharedDeviceResourceArray &limit)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::set_limit_v2(const obrpc::ObSharedDeviceResourceArray &limit)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
inner_calc_();
|
||||
for (int i = 0; i < limit.array_.count(); ++i) {
|
||||
ObSharedDeviceControlV2 *tc = nullptr;
|
||||
if (ResourceType::tag == limit.array_.at(i).type_) {
|
||||
// Tag is currently unavailable
|
||||
} else if (OB_ISNULL(tc = shared_device_map_v2_.get(limit.array_.at(i).key_))) {
|
||||
// ignore ret
|
||||
LOG_WARN_RET(OB_HASH_NOT_EXIST, "get index from map failed", K(limit.array_.at(i).key_));
|
||||
} else if (OB_SUCCESS != (tc->update_limit(limit.array_.at(i)))) {
|
||||
LOG_WARN("update shared device limit failed", K(ret), K(i), K(limit.array_.at(i)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObTrafficControl::inner_calc_()
|
||||
{
|
||||
if (REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
|
||||
int ret = OB_SUCCESS;
|
||||
int64_t read_bytes = 0;
|
||||
int64_t write_bytes = 0;
|
||||
reset_pnio_statistics(&read_bytes, &write_bytes);
|
||||
net_ibw_.inc(read_bytes);
|
||||
net_obw_.inc(write_bytes);
|
||||
ATOMIC_STORE(&ibw_clock_.iops_, std::max(0L, device_bandwidth_ - read_bytes));
|
||||
ATOMIC_STORE(&obw_clock_.iops_, std::max(0L, device_bandwidth_ - write_bytes));
|
||||
if (GCONF._enable_tree_based_io_scheduler == false) {
|
||||
ATOMIC_STORE(&ibw_clock_.iops_, std::max(0L, device_bandwidth_ - read_bytes));
|
||||
ATOMIC_STORE(&obw_clock_.iops_, std::max(0L, device_bandwidth_ - write_bytes));
|
||||
} else if (0 != (ret = qdisc_set_limit(OB_IO_MANAGER_V2.get_sub_root_qid((int)ObIOMode::READ), std::max(0L, device_bandwidth_ - read_bytes)))) {
|
||||
LOG_WARN("set net_in limit failed", K(ret));
|
||||
} else if (0 != (ret = qdisc_set_limit(OB_IO_MANAGER_V2.get_sub_root_qid((int)ObIOMode::WRITE), std::max(0L, device_bandwidth_ - write_bytes)))) {
|
||||
LOG_WARN("set net_out limit failed", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ObTrafficControl::register_bucket(ObIORequest &req, const int qid) {
|
||||
int ret = OB_SUCCESS;
|
||||
if (req.fd_.device_handle_->is_object_device()) {
|
||||
uint64_t storage_id = ((ObObjectDevice*)(req.fd_.device_handle_))->get_storage_id_mod().storage_id_;
|
||||
uint8_t mod_id = (uint8_t)((ObObjectDevice*)(req.fd_.device_handle_))->get_storage_id_mod().storage_used_mod_;
|
||||
ObStorageInfoType storage_type = __storage_table_mapper[mod_id];
|
||||
ObTrafficControl::ObStorageKey key(storage_id, req.tenant_id_, storage_type);
|
||||
ObIOSSGrpKey grp_key(req.tenant_id_, req.get_group_key());
|
||||
ObSharedDeviceControlV2 *tc = nullptr;
|
||||
// global register bucket
|
||||
if (OB_NOT_NULL(tc = shared_device_map_v2_.get(key))) {
|
||||
} else if (OB_FAIL(shared_device_map_v2_.set_refactored(key, ObSharedDeviceControlV2())) && OB_HASH_EXIST != ret) {
|
||||
LOG_WARN("set map failed", K(ret));
|
||||
} else if (OB_ISNULL(tc = shared_device_map_v2_.get(key))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_ERROR("hash is not existed", K(ret), K(key));
|
||||
} else if (OB_FAIL(tc->add_shared_device_limits())) {
|
||||
LOG_WARN("add shared device limits failed", K(ret), K(req), K(grp_key), K(qid));
|
||||
}
|
||||
|
||||
// register bucket for group
|
||||
if (REACH_TIME_INTERVAL(100 * 1000)) {
|
||||
if (OB_HASH_NOT_EXIST != tc->is_group_key_exist(grp_key)) {
|
||||
} else if (OB_FAIL(tc->add_group(grp_key, qid))) {
|
||||
LOG_WARN("add shared device limits failed", K(ret), K(grp_key), K(qid));
|
||||
}
|
||||
}
|
||||
|
||||
(void)tc->fill_qsched_req_ss_limits(req);
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int64_t ObTrafficControl::ObSharedDeviceControlV2::to_string(char* buf, const int64_t buf_len) const
|
||||
{
|
||||
int64_t pos = 0;
|
||||
J_OBJ_START();
|
||||
for (int i = 0; i < static_cast<int>(obrpc::ResourceType::ResourceTypeCnt); i++) {
|
||||
if (-1 != limit_ids_[i]) {
|
||||
J_KV("%s: id: %ld, limit: %ld, ", get_resource_type_str(static_cast<ResourceType>(i)), K(limit_ids_[i]), K(limits_[i]));
|
||||
}
|
||||
}
|
||||
J_OBJ_END();
|
||||
return pos;
|
||||
}
|
||||
|
||||
ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::ObSDGroupList()
|
||||
{
|
||||
}
|
||||
ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::~ObSDGroupList()
|
||||
{
|
||||
}
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::clear()
|
||||
{
|
||||
grp_list_.reuse();
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::assign(const ObSDGroupList &other)
|
||||
{
|
||||
grp_list_.assign(other.grp_list_);
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
|
||||
int ObTrafficControl::ObSharedDeviceControlV2::ObSDGroupList::is_group_key_exist(const ObIOSSGrpKey &grp_key) {
|
||||
int ret = OB_SUCCESS;
|
||||
bool is_found = false;
|
||||
for (int i = 0; !is_found && i < grp_list_.count(); i++) {
|
||||
if (grp_list_.at(i) == grp_key) {
|
||||
is_found = true;
|
||||
}
|
||||
}
|
||||
if (is_found == false) {
|
||||
ret = OB_HASH_NOT_EXIST;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTrafficControl::gc_tenant_infos()
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
@ -346,6 +618,28 @@ int ObTrafficControl::gc_tenant_infos()
|
||||
const ObVector<uint64_t> &tenant_ids_;
|
||||
ObSEArray<ObTrafficControl::ObStorageKey, 7> &gc_tenant_infos_;
|
||||
};
|
||||
struct GCTenantSharedDeviceInfosV2
|
||||
{
|
||||
GCTenantSharedDeviceInfosV2(
|
||||
const ObVector<uint64_t> &tenant_ids, ObSEArray<ObTrafficControl::ObStorageKey, 7> &gc_tenant_infos)
|
||||
: tenant_ids_(tenant_ids), gc_tenant_infos_(gc_tenant_infos)
|
||||
{}
|
||||
int operator()(hash::HashMapPair<ObTrafficControl::ObStorageKey, ObTrafficControl::ObSharedDeviceControlV2> &pair)
|
||||
{
|
||||
bool is_find = false;
|
||||
for (int i = 0; !is_find && i < tenant_ids_.size(); ++i) {
|
||||
if (0 == pair.first.get_tenant_id() || tenant_ids_.at(i) == pair.first.get_tenant_id()) {
|
||||
is_find = true;
|
||||
}
|
||||
}
|
||||
if (false == is_find) {
|
||||
gc_tenant_infos_.push_back(pair.first);
|
||||
}
|
||||
return OB_SUCCESS;
|
||||
}
|
||||
const ObVector<uint64_t> &tenant_ids_;
|
||||
ObSEArray<ObTrafficControl::ObStorageKey, 7> &gc_tenant_infos_;
|
||||
};
|
||||
struct GCTenantRecordInfos
|
||||
{
|
||||
GCTenantRecordInfos(
|
||||
@ -371,14 +665,18 @@ int ObTrafficControl::gc_tenant_infos()
|
||||
ObVector<uint64_t> tenant_ids;
|
||||
ObSEArray<ObTrafficControl::ObIORecordKey, 7> gc_tenant_record_infos;
|
||||
ObSEArray<ObTrafficControl::ObStorageKey, 7> gc_tenant_shared_device_infos;
|
||||
ObSEArray<ObTrafficControl::ObStorageKey, 7> gc_tenant_shared_device_infos_v2;
|
||||
GCTenantRecordInfos fn(tenant_ids, gc_tenant_record_infos);
|
||||
GCTenantSharedDeviceInfos fn2(tenant_ids, gc_tenant_shared_device_infos);
|
||||
GCTenantSharedDeviceInfosV2 fn3(tenant_ids, gc_tenant_shared_device_infos_v2);
|
||||
if(OB_ISNULL(GCTX.omt_)) {
|
||||
} else if (FALSE_IT(GCTX.omt_->get_tenant_ids(tenant_ids))) {
|
||||
} else if (OB_FAIL(io_record_map_.foreach_refactored(fn))) {
|
||||
LOG_WARN("SSNT:failed to get gc tenant record infos", K(ret));
|
||||
} else if (OB_FAIL(shared_device_map_.foreach_refactored(fn2))) {
|
||||
LOG_WARN("SSNT:failed to get gc tenant shared device infos", K(ret));
|
||||
} else if (OB_FAIL(shared_device_map_v2_.foreach_refactored(fn3))) {
|
||||
LOG_WARN("SSNT:failed to get gc tenant shared device infos", K(ret));
|
||||
} else {
|
||||
for (int i = 0; i < gc_tenant_record_infos.count(); ++i) {
|
||||
if (OB_SUCCESS != io_record_map_.erase_refactored(gc_tenant_record_infos.at(i))) {
|
||||
@ -391,6 +689,12 @@ int ObTrafficControl::gc_tenant_infos()
|
||||
"SSNT:failed to erase gc tenant shared device infos", K(ret), K(gc_tenant_shared_device_infos.at(i)));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < gc_tenant_shared_device_infos_v2.count(); ++i) {
|
||||
if (OB_SUCCESS != shared_device_map_v2_.erase_refactored(gc_tenant_shared_device_infos_v2.at(i))) {
|
||||
LOG_WARN(
|
||||
"SSNT:failed to erase gc tenant shared device infos", K(ret), K(gc_tenant_shared_device_infos_v2.at(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@ -427,6 +731,8 @@ int ObIOManager::init(const int64_t memory_limit,
|
||||
if (OB_UNLIKELY(is_inited_)) {
|
||||
ret = OB_INIT_TWICE;
|
||||
LOG_WARN("init twice", K(ret), K(is_inited_));
|
||||
} else if (OB_FAIL(OB_IO_MANAGER_V2.init())) {
|
||||
LOG_WARN("qsched global init fail");
|
||||
} else if (OB_UNLIKELY(memory_limit <= 0|| schedule_queue_count <= 0)) {
|
||||
ret = OB_INVALID_ARGUMENT;
|
||||
LOG_WARN("invalid arguments", K(ret), K(memory_limit), K(schedule_queue_count));
|
||||
@ -493,6 +799,8 @@ void ObIOManager::destroy()
|
||||
stop();
|
||||
fault_detector_.destroy();
|
||||
io_scheduler_.destroy();
|
||||
OB_IO_MANAGER_V2.wait();
|
||||
OB_IO_MANAGER_V2.destroy();
|
||||
DestroyChannelMapFn destry_channel_map_fn(allocator_);
|
||||
channel_map_.foreach_refactored(destry_channel_map_fn);
|
||||
channel_map_.destroy();
|
||||
@ -513,6 +821,8 @@ int ObIOManager::start()
|
||||
LOG_WARN("init server tenant io mgr start failed", K(ret));
|
||||
} else if (OB_FAIL(io_scheduler_.start())) {
|
||||
LOG_WARN("start io scheduler failed", K(ret));
|
||||
} else if (OB_FAIL(OB_IO_MANAGER_V2.start())) {
|
||||
LOG_WARN("start io scheduler V2 failed", K(ret));
|
||||
} else if (OB_FAIL(fault_detector_.start())) {
|
||||
LOG_WARN("start io fault detector failed", K(ret));
|
||||
} else {
|
||||
@ -528,6 +838,7 @@ void ObIOManager::stop()
|
||||
server_io_manager_->stop();
|
||||
}
|
||||
io_scheduler_.stop();
|
||||
OB_IO_MANAGER_V2.stop();
|
||||
}
|
||||
|
||||
void ObIOManager::wait()
|
||||
@ -1028,10 +1339,15 @@ void ObIOManager::print_channel_status()
|
||||
|
||||
void ObIOManager::print_status()
|
||||
{
|
||||
tc_.print_status();
|
||||
print_sender_status();
|
||||
print_tenant_status();
|
||||
print_channel_status();
|
||||
tc_.print_server_status();
|
||||
if (GCONF._enable_tree_based_io_scheduler == false) {
|
||||
tc_.print_bucket_status_V1();
|
||||
} else {
|
||||
tc_.print_bucket_status_V2();
|
||||
}
|
||||
}
|
||||
|
||||
int64_t ObIOManager::get_object_storage_io_timeout_ms(const uint64_t tenant_id) const
|
||||
@ -1160,6 +1476,8 @@ int ObTenantIOManager::init(const uint64_t tenant_id,
|
||||
LOG_WARN("init group map failed", K(ret));
|
||||
} else if (OB_FAIL(io_config_.deep_copy(io_config))) {
|
||||
LOG_WARN("copy io config failed", K(ret), K(io_config_));
|
||||
} else if (OB_FAIL(qsched_.init(tenant_id, io_config))) {
|
||||
LOG_WARN("init qsched failed", K(ret), K(io_config));
|
||||
} else {
|
||||
tenant_id_ = tenant_id;
|
||||
io_scheduler_ = io_scheduler;
|
||||
@ -1185,6 +1503,7 @@ void ObTenantIOManager::destroy()
|
||||
ob_usleep((useconds_t)10L * 1000L); //10ms
|
||||
}
|
||||
dec_ref();
|
||||
qsched_.destroy();
|
||||
}
|
||||
|
||||
int ret = OB_SUCCESS;
|
||||
@ -1442,6 +1761,11 @@ int ObTenantIOManager::inner_aio(const ObIOInfo &info, ObIOHandle &handle)
|
||||
LOG_DBA_ERROR(OB_DISK_HUNG, "msg", "disk has fatal error");
|
||||
} else if (OB_FAIL(alloc_req_and_result(info, handle, req, req_holder))) {
|
||||
LOG_WARN("pre set io args failed", K(ret), K(info));
|
||||
} else if (GCONF._enable_tree_based_io_scheduler) {
|
||||
if (OB_FAIL(ret)) {
|
||||
} else if (OB_FAIL(qsched_.schedule_request(*req))) {
|
||||
LOG_WARN("schedule request failed", K(ret), KPC(req));
|
||||
}
|
||||
} else if (OB_FAIL(io_scheduler_->schedule_request(*req))) {
|
||||
LOG_WARN("schedule request failed", K(ret), KPC(req));
|
||||
}
|
||||
@ -1557,6 +1881,8 @@ int ObTenantIOManager::update_basic_io_config(const ObTenantIOConfig &io_config)
|
||||
io_config_.unit_config_ = io_config.unit_config_;
|
||||
if (OB_FAIL(io_clock_.update_io_clocks(io_config_))) {
|
||||
LOG_WARN("update io clock unit config failed", K(ret), K(tenant_id_), K(io_config_), K(io_config), K(io_clock_));
|
||||
} else if (OB_FAIL(qsched_.update_config(io_config_))) {
|
||||
LOG_WARN("refresh tenant io config failed", K(ret), K(io_config_));
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
@ -2022,6 +2348,8 @@ int ObTenantIOManager::refresh_group_io_config()
|
||||
LOG_WARN("refresh phyqueue num failed", K(ret), K(io_config_.group_configs_.count()));
|
||||
} else if (OB_FAIL(io_clock_.update_io_clocks(io_config_))) {
|
||||
LOG_WARN("refresh io clock failed", K(ret), K(io_config_));
|
||||
} else if (OB_FAIL(qsched_.update_config(io_config_))) {
|
||||
LOG_WARN("refresh io config failed", K(ret), K(io_config_));
|
||||
} else {
|
||||
LOG_INFO("refresh group io config success", K(tenant_id_), K(io_config_));
|
||||
io_config_.group_config_change_ = false;
|
||||
|
@ -14,25 +14,48 @@
|
||||
#define OCEANBASE_LIB_STORAGE_OB_IO_MANAGER_H
|
||||
|
||||
#include "common/storage/ob_io_device.h"
|
||||
#include "share/io/io_schedule/ob_io_schedule_v2.h"
|
||||
#include "share/io/ob_io_struct.h"
|
||||
|
||||
namespace oceanbase
|
||||
{
|
||||
namespace obrpc
|
||||
{
|
||||
struct ObSharedDeviceResource;
|
||||
struct ObSharedDeviceResourceArray;
|
||||
enum ResourceType {
|
||||
ops = 0,
|
||||
ips = 1,
|
||||
iops = 2,
|
||||
obw = 3,
|
||||
ibw = 4,
|
||||
iobw = 5,
|
||||
tag = 6,
|
||||
ResourceTypeCnt
|
||||
};
|
||||
enum ResourceType { ops = 0, ips = 1, iops = 2, obw = 3, ibw = 4, iobw = 5, tag = 6, ResourceTypeCnt };
|
||||
inline const char *get_resource_type_str(const ResourceType type)
|
||||
{
|
||||
const char *str;
|
||||
switch (type) {
|
||||
case ops:
|
||||
str = "ops";
|
||||
break;
|
||||
case ips:
|
||||
str = "ips";
|
||||
break;
|
||||
case iops:
|
||||
str = "iops";
|
||||
break;
|
||||
case obw:
|
||||
str = "obw";
|
||||
break;
|
||||
case ibw:
|
||||
str = "ibw";
|
||||
break;
|
||||
case iobw:
|
||||
str = "iobw";
|
||||
break;
|
||||
case tag:
|
||||
str = "tag";
|
||||
break;
|
||||
default:
|
||||
str = "unknown";
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
} // namespace obrpc
|
||||
namespace common
|
||||
{
|
||||
class ObTenantIOManager;
|
||||
@ -42,8 +65,10 @@ class ObSSIORequest;
|
||||
|
||||
struct ResourceUsage
|
||||
{
|
||||
ResourceUsage() : type_(obrpc::ResourceType::ResourceTypeCnt), total_(0) {}
|
||||
~ResourceUsage() {}
|
||||
ResourceUsage() : type_(obrpc::ResourceType::ResourceTypeCnt), total_(0)
|
||||
{}
|
||||
~ResourceUsage()
|
||||
{}
|
||||
obrpc::ResourceType type_;
|
||||
int64_t total_;
|
||||
};
|
||||
@ -55,11 +80,12 @@ public:
|
||||
struct ObStorageKey
|
||||
{
|
||||
OB_UNIS_VERSION(1);
|
||||
|
||||
public:
|
||||
explicit ObStorageKey()
|
||||
: storage_id_(0), tenant_id_(0), category_(ObStorageInfoType::ALL_ZONE_STORAGE) {}
|
||||
explicit ObStorageKey() : storage_id_(0), tenant_id_(0), category_(ObStorageInfoType::ALL_ZONE_STORAGE)
|
||||
{}
|
||||
explicit ObStorageKey(uint64_t storage_id, uint64_t tenant_id, ObStorageInfoType category)
|
||||
: storage_id_(storage_id), tenant_id_(tenant_id), category_(category)
|
||||
: storage_id_(storage_id), tenant_id_(tenant_id), category_(category)
|
||||
{
|
||||
if (ObStorageInfoType::ALL_ZONE_STORAGE == category_) {
|
||||
tenant_id_ = OB_INVALID_TENANT_ID;
|
||||
@ -78,46 +104,61 @@ public:
|
||||
}
|
||||
bool operator==(const ObStorageKey &that) const
|
||||
{
|
||||
return storage_id_ == that.storage_id_
|
||||
&& tenant_id_ == that.tenant_id_
|
||||
&& category_ == that.category_;
|
||||
return storage_id_ == that.storage_id_ && tenant_id_ == that.tenant_id_ && category_ == that.category_;
|
||||
}
|
||||
bool operator!=(const ObStorageKey &that) const
|
||||
{
|
||||
return !(*this == that);
|
||||
}
|
||||
uint64_t get_storage_id() const { return storage_id_; }
|
||||
uint64_t get_tenant_id() const { return tenant_id_; }
|
||||
ObStorageInfoType get_category() const { return category_; }
|
||||
uint64_t get_storage_id() const
|
||||
{
|
||||
return storage_id_;
|
||||
}
|
||||
uint64_t get_tenant_id() const
|
||||
{
|
||||
return tenant_id_;
|
||||
}
|
||||
ObStorageInfoType get_category() const
|
||||
{
|
||||
return category_;
|
||||
}
|
||||
TO_STRING_KV(K(storage_id_), K_(tenant_id), K_(category));
|
||||
|
||||
private:
|
||||
uint64_t storage_id_;
|
||||
uint64_t tenant_id_; // tenant_id of storage
|
||||
uint64_t tenant_id_; // tenant_id of storage
|
||||
ObStorageInfoType category_;
|
||||
};
|
||||
|
||||
private:
|
||||
struct IORecord
|
||||
{
|
||||
IORecord()
|
||||
: last_ts_(ObTimeUtility::fast_current_time()),
|
||||
total_size_(0),
|
||||
last_record_(0),
|
||||
size_(0) {}
|
||||
IORecord() : last_ts_(ObTimeUtility::fast_current_time()), total_size_(0), last_record_(0), size_(0)
|
||||
{}
|
||||
int64_t calc();
|
||||
void inc(int64_t size) { IGNORE_RETURN ATOMIC_FAA(&size_, size); }
|
||||
int64_t clear() { return ATOMIC_SET(&total_size_, 0); }
|
||||
private:
|
||||
void inc(int64_t size)
|
||||
{
|
||||
IGNORE_RETURN ATOMIC_FAA(&size_, size);
|
||||
}
|
||||
int64_t clear()
|
||||
{
|
||||
return ATOMIC_SET(&total_size_, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
int64_t last_ts_;
|
||||
int64_t total_size_;
|
||||
int64_t last_record_;
|
||||
int64_t size_; // CACHE_ALIGNED?
|
||||
int64_t size_; // CACHE_ALIGNED?
|
||||
};
|
||||
|
||||
public:
|
||||
struct ObIORecordKey
|
||||
{
|
||||
explicit ObIORecordKey() : tenant_id_(0), id_() {}
|
||||
explicit ObIORecordKey(const ObStorageKey &id, uint64_t tenant_id)
|
||||
: tenant_id_(tenant_id), id_(id) {}
|
||||
explicit ObIORecordKey() : tenant_id_(0), id_()
|
||||
{}
|
||||
explicit ObIORecordKey(const ObStorageKey &id, uint64_t tenant_id) : tenant_id_(tenant_id), id_(id)
|
||||
{}
|
||||
int hash(uint64_t &res) const
|
||||
{
|
||||
id_.hash(res);
|
||||
@ -132,6 +173,7 @@ public:
|
||||
uint64_t tenant_id_; // tenant_id of req
|
||||
ObStorageKey id_;
|
||||
};
|
||||
|
||||
public:
|
||||
struct ObSharedDeviceIORecord
|
||||
{
|
||||
@ -143,24 +185,40 @@ public:
|
||||
IORecord ops_;
|
||||
IORecord tagps_;
|
||||
};
|
||||
|
||||
public:
|
||||
struct ObSharedDeviceControl
|
||||
{
|
||||
ObSharedDeviceControl();
|
||||
int calc_clock(const int64_t current_ts, ObIORequest &req, int64_t &deadline_ts);
|
||||
void set_limit(const obrpc::ObSharedDeviceResource &limit);
|
||||
ObAtomIOClock* get_clock(obrpc::ResourceType type)
|
||||
ObAtomIOClock *get_clock(obrpc::ResourceType type)
|
||||
{
|
||||
ObAtomIOClock *ret = nullptr;
|
||||
switch (type) {
|
||||
case obrpc::ResourceType::ops: ret = &ops_clock_; break;
|
||||
case obrpc::ResourceType::ips: ret = &ips_clock_; break;
|
||||
case obrpc::ResourceType::iops: ret = &iops_clock_; break;
|
||||
case obrpc::ResourceType::obw: ret = &obw_clock_; break;
|
||||
case obrpc::ResourceType::ibw: ret = &ibw_clock_; break;
|
||||
case obrpc::ResourceType::iobw: ret = &iobw_clock_; break;
|
||||
case obrpc::ResourceType::tag: ret = &tagps_clock_; break;
|
||||
default: break;
|
||||
case obrpc::ResourceType::ops:
|
||||
ret = &ops_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::ips:
|
||||
ret = &ips_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::iops:
|
||||
ret = &iops_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::obw:
|
||||
ret = &obw_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::ibw:
|
||||
ret = &ibw_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::iobw:
|
||||
ret = &iobw_clock_;
|
||||
break;
|
||||
case obrpc::ResourceType::tag:
|
||||
ret = &tagps_clock_;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -172,17 +230,56 @@ public:
|
||||
ObAtomIOClock ops_clock_;
|
||||
ObAtomIOClock iops_clock_;
|
||||
ObAtomIOClock tagps_clock_;
|
||||
TO_STRING_KV(K(ibw_clock_), K(obw_clock_), K(iobw_clock_), K(ips_clock_), K(ops_clock_), K(iops_clock_), K(tagps_clock_));
|
||||
TO_STRING_KV(
|
||||
K(ibw_clock_), K(obw_clock_), K(iobw_clock_), K(ips_clock_), K(ops_clock_), K(iops_clock_), K(tagps_clock_));
|
||||
};
|
||||
struct ObSharedDeviceControlV2
|
||||
{
|
||||
struct ObSDGroupList
|
||||
{
|
||||
ObSDGroupList();
|
||||
~ObSDGroupList();
|
||||
int clear();
|
||||
int assign(const ObSDGroupList &other);
|
||||
int add_group(const ObIOSSGrpKey &grp_key, int qid, int* limit_ids, int l_size);
|
||||
int is_group_key_exist(const ObIOSSGrpKey &grp_key);
|
||||
common::ObSEArray<ObIOSSGrpKey, 7> grp_list_;
|
||||
TO_STRING_KV(K(grp_list_));
|
||||
};
|
||||
ObSharedDeviceControlV2();
|
||||
~ObSharedDeviceControlV2();
|
||||
int init();
|
||||
int destroy();
|
||||
int add_shared_device_limits();
|
||||
int fill_qsched_req_ss_limits(ObIORequest& req);
|
||||
int add_group(const ObIOSSGrpKey &grp_key, const int qid);
|
||||
int is_group_key_exist(const ObIOSSGrpKey &grp_key);
|
||||
int64_t get_limit(const obrpc::ResourceType type) const;
|
||||
int update_limit(const obrpc::ObSharedDeviceResource &limit);
|
||||
int64_t to_string(char* buf, const int64_t buf_len) const;
|
||||
|
||||
// limit and limit_ids: ops = 0, ips = 1, iops = 2, obw = 3, ibw = 4, iobw = 5, tag = 6
|
||||
int64_t limits_[static_cast<int>(obrpc::ResourceType::ResourceTypeCnt)];
|
||||
int limit_ids_[static_cast<int>(obrpc::ResourceType::ResourceTypeCnt)];
|
||||
ObSDGroupList group_list_;
|
||||
};
|
||||
|
||||
public:
|
||||
ObTrafficControl();
|
||||
int calc_clock(const int64_t current_ts, ObIORequest &req, int64_t &deadline_ts);
|
||||
int calc_usage(ObIORequest &req);
|
||||
void print_status();
|
||||
void print_server_status();
|
||||
void print_bucket_status_V1();
|
||||
void print_bucket_status_V2();
|
||||
int set_limit(const obrpc::ObSharedDeviceResourceArray &limit);
|
||||
int set_limit_v2(const obrpc::ObSharedDeviceResourceArray &limit);
|
||||
int get_storage_count() const { return shared_device_map_.size(); };
|
||||
int register_bucket(ObIORequest &req, const int qid);
|
||||
int add_shared_device_limits(const ObStorageKey &key, const int qid);
|
||||
template<class _cb>
|
||||
int foreach_limit(_cb &cb) const { return shared_device_map_.foreach_refactored(cb); }
|
||||
template <class _cb>
|
||||
int foreach_limit_v2(_cb &cb) const { return shared_device_map_v2_.foreach_refactored(cb); }
|
||||
template<class _cb>
|
||||
int foreach_record(_cb &cb) const { return io_record_map_.foreach_refactored(cb); }
|
||||
int64_t get_net_ibw() { return net_ibw_.calc(); }
|
||||
@ -192,9 +289,11 @@ public:
|
||||
int gc_tenant_infos();
|
||||
private:
|
||||
void inner_calc_();
|
||||
|
||||
private:
|
||||
// for device limitation
|
||||
hash::ObHashMap<ObStorageKey, ObSharedDeviceControl> shared_device_map_;
|
||||
hash::ObHashMap<ObStorageKey, ObSharedDeviceControlV2> shared_device_map_v2_;
|
||||
// for diagnose
|
||||
hash::ObHashMap<ObIORecordKey, ObSharedDeviceIORecord> io_record_map_;
|
||||
// maybe different key between limitation and diagnose later
|
||||
@ -214,9 +313,8 @@ class ObIOManager final
|
||||
{
|
||||
public:
|
||||
static ObIOManager &get_instance();
|
||||
int init(const int64_t memory_limit = DEFAULT_MEMORY_LIMIT,
|
||||
const int32_t queue_depth = DEFAULT_QUEUE_DEPTH,
|
||||
const int32_t schedule_thread_count = 0);
|
||||
int init(const int64_t memory_limit = DEFAULT_MEMORY_LIMIT, const int32_t queue_depth = DEFAULT_QUEUE_DEPTH,
|
||||
const int32_t schedule_thread_count = 0);
|
||||
void destroy();
|
||||
int start();
|
||||
void stop();
|
||||
@ -247,24 +345,28 @@ public:
|
||||
int reset_device_health();
|
||||
|
||||
// device channel management
|
||||
int add_device_channel(ObIODevice *device_handle,
|
||||
const int64_t async_channel_count,
|
||||
const int64_t sync_channel_count,
|
||||
const int64_t max_io_depth);
|
||||
int add_device_channel(ObIODevice *device_handle, const int64_t async_channel_count, const int64_t sync_channel_count,
|
||||
const int64_t max_io_depth);
|
||||
int remove_device_channel(ObIODevice *device_handle);
|
||||
int get_device_channel(const ObIORequest &req, ObDeviceChannel *&device_channel);
|
||||
|
||||
// tenant management
|
||||
int refresh_tenant_io_config(const uint64_t tenant_id, const ObTenantIOConfig &tenant_io_config);
|
||||
int get_tenant_io_manager(const uint64_t tenant_id, ObRefHolder<ObTenantIOManager> &tenant_holder) const;
|
||||
OB_INLINE bool is_inited() { return is_inited_; }
|
||||
int modify_group_io_config(const uint64_t tenant_id,
|
||||
const uint64_t index,
|
||||
const int64_t min_percent,
|
||||
const int64_t max_percent,
|
||||
const int64_t weight_percent);
|
||||
ObIOScheduler *get_scheduler() { return &io_scheduler_; }
|
||||
ObTrafficControl &get_tc() { return tc_; }
|
||||
OB_INLINE bool is_inited()
|
||||
{
|
||||
return is_inited_;
|
||||
}
|
||||
int modify_group_io_config(const uint64_t tenant_id, const uint64_t index, const int64_t min_percent,
|
||||
const int64_t max_percent, const int64_t weight_percent);
|
||||
ObIOScheduler *get_scheduler()
|
||||
{
|
||||
return &io_scheduler_;
|
||||
}
|
||||
ObTrafficControl &get_tc()
|
||||
{
|
||||
return tc_;
|
||||
}
|
||||
void print_sender_status();
|
||||
void print_tenant_status();
|
||||
void print_channel_status();
|
||||
@ -273,13 +375,14 @@ public:
|
||||
|
||||
private:
|
||||
friend class ObTenantIOManager;
|
||||
static const int64_t DEFAULT_MEMORY_LIMIT = 10L * 1024L * 1024L * 1024L; // 10GB
|
||||
static const int64_t DEFAULT_MEMORY_LIMIT = 10L * 1024L * 1024L * 1024L; // 10GB
|
||||
static const int32_t DEFAULT_QUEUE_DEPTH = 10000;
|
||||
ObIOManager();
|
||||
~ObIOManager();
|
||||
int tenant_aio(const ObIOInfo &info, ObIOHandle &handle);
|
||||
int adjust_tenant_clock();
|
||||
DISABLE_COPY_ASSIGN(ObIOManager);
|
||||
|
||||
private:
|
||||
bool is_inited_;
|
||||
bool is_working_;
|
||||
@ -299,12 +402,11 @@ public:
|
||||
static int mtl_new(ObTenantIOManager *&io_service);
|
||||
static int mtl_init(ObTenantIOManager *&io_service);
|
||||
static void mtl_destroy(ObTenantIOManager *&io_service);
|
||||
|
||||
public:
|
||||
ObTenantIOManager();
|
||||
~ObTenantIOManager();
|
||||
int init(const uint64_t tenant_id,
|
||||
const ObTenantIOConfig &io_config,
|
||||
ObIOScheduler *io_scheduler);
|
||||
int init(const uint64_t tenant_id, const ObTenantIOConfig &io_config, ObIOScheduler *io_scheduler);
|
||||
void destroy();
|
||||
int start();
|
||||
void stop();
|
||||
@ -315,10 +417,22 @@ public:
|
||||
int detect_aio(const ObIOInfo &info, ObIOHandle &handle);
|
||||
int enqueue_callback(ObIORequest &req);
|
||||
int retry_io(ObIORequest &req);
|
||||
ObTenantIOClock *get_io_clock() { return &io_clock_; }
|
||||
ObIOUsage &get_io_usage() { return io_usage_; }
|
||||
ObIOCallbackManager &get_callback_mgr() { return callback_mgr_; };
|
||||
ObIOUsage &get_sys_io_usage() { return io_sys_usage_; }
|
||||
ObTenantIOClock *get_io_clock()
|
||||
{
|
||||
return &io_clock_;
|
||||
}
|
||||
ObIOUsage &get_io_usage()
|
||||
{
|
||||
return io_usage_;
|
||||
}
|
||||
ObIOCallbackManager &get_callback_mgr()
|
||||
{
|
||||
return callback_mgr_;
|
||||
};
|
||||
ObIOUsage &get_sys_io_usage()
|
||||
{
|
||||
return io_sys_usage_;
|
||||
}
|
||||
int update_basic_io_config(const ObTenantIOConfig &io_config);
|
||||
int try_alloc_req_until_timeout(const int64_t timeout_ts, ObIORequest *&req);
|
||||
int try_alloc_result_until_timeout(const int64_t timeout_ts, ObIOResult *&result);
|
||||
@ -385,23 +499,24 @@ private:
|
||||
ObIOAllocator io_allocator_;
|
||||
ObIOScheduler *io_scheduler_;
|
||||
ObIOCallbackManager callback_mgr_;
|
||||
ObIOUsage io_usage_; // user group usage
|
||||
ObIOUsage io_sys_usage_; // sys group usage
|
||||
ObIOMemStats io_mem_stats_; // Group Level: IO memory monitor
|
||||
ObIOFuncUsages io_func_infos_; // Tenant Level: IO function group usage monitor
|
||||
ObIOUsage io_usage_; // user group usage
|
||||
ObIOUsage io_sys_usage_; // sys group usage
|
||||
ObIOMemStats io_mem_stats_; // Group Level: IO memory monitor
|
||||
ObIOFuncUsages io_func_infos_; // Tenant Level: IO function group usage monitor
|
||||
ObIOTracer io_tracer_;
|
||||
DRWLock io_config_lock_; //for map and config
|
||||
hash::ObHashMap<ObIOGroupKey, uint64_t> group_id_index_map_; //key:group_id, value:index
|
||||
DRWLock io_config_lock_; // for map and config
|
||||
hash::ObHashMap<ObIOGroupKey, uint64_t> group_id_index_map_; // key:group_id, value:index
|
||||
#ifdef OB_BUILD_SHARED_STORAGE
|
||||
ObIOObjectPool<ObIORequest, ObSSIORequest> io_request_pool_;
|
||||
#else
|
||||
ObIOObjectPool<ObIORequest, ObIORequest> io_request_pool_;
|
||||
#endif
|
||||
ObIOObjectPool<ObIOResult, ObIOResult> io_result_pool_;
|
||||
ObTenantIOSchedulerV2 qsched_;
|
||||
};
|
||||
|
||||
#define OB_IO_MANAGER (oceanbase::common::ObIOManager::get_instance())
|
||||
}// end namespace common
|
||||
}// end namespace oceanbase
|
||||
} // end namespace common
|
||||
} // end namespace oceanbase
|
||||
|
||||
#endif//OCEANBASE_LIB_STORAGE_OB_IO_MANAGER_H
|
||||
#endif // OCEANBASE_LIB_STORAGE_OB_IO_MANAGER_H
|
||||
|
@ -2196,6 +2196,10 @@ DEF_BOOL(strict_check_os_params, OB_CLUSTER_PARAMETER, "False",
|
||||
"A switch that determines whether to enable strict OS parameter check mode, defaulting to true and can be set to false to bypass strict checks."
|
||||
"Value: True: allowed; False: allowed but not suggested",
|
||||
ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::STATIC_EFFECTIVE));
|
||||
DEF_BOOL(_enable_tree_based_io_scheduler, OB_CLUSTER_PARAMETER, "True",
|
||||
"A switch that allows enabling the tree-based IO scheduler."
|
||||
"Value: True: allowed; False: disabled",
|
||||
ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE));
|
||||
DEF_BOOL(enable_ob_error_msg_style, OB_CLUSTER_PARAMETER, "True",
|
||||
"A switch that determines whether to use the ORA-xx or OBE-xx error code format for ORA error codes, with a default value of True to use the OBE-xx format."
|
||||
"The default value is True. Value: False means we use the ORA-xx format, True means we use the OBE-xx format.",
|
||||
|
@ -381,6 +381,7 @@ _enable_tenant_sql_net_thread
|
||||
_enable_trace_session_leak
|
||||
_enable_trace_tablet_leak
|
||||
_enable_transaction_internal_routing
|
||||
_enable_tree_based_io_scheduler
|
||||
_enable_unit_gc_wait
|
||||
_enable_values_table_folding
|
||||
_enable_var_assign_use_das
|
||||
|
@ -42,7 +42,7 @@ add_subdirectory(ddl)
|
||||
add_subdirectory(share_storage)
|
||||
add_subdirectory(column_store_replica)
|
||||
|
||||
storage_unittest(test_io_manager)
|
||||
#storage_unittest(test_io_manager)
|
||||
storage_unittest(test_iocb_pool)
|
||||
storage_unittest(test_ob_col_map)
|
||||
storage_unittest(test_placement_hashmap)
|
||||
|
Loading…
x
Reference in New Issue
Block a user