fix the overflow check of AObject
This commit is contained in:
1
deps/oblib/src/lib/CMakeLists.txt
vendored
1
deps/oblib/src/lib/CMakeLists.txt
vendored
@ -319,7 +319,6 @@ ob_set_subtarget(ob_malloc_object_list common_alloc
|
|||||||
alloc/alloc_struct.cpp
|
alloc/alloc_struct.cpp
|
||||||
alloc/block_set.cpp
|
alloc/block_set.cpp
|
||||||
alloc/memory_dump.cpp
|
alloc/memory_dump.cpp
|
||||||
alloc/ob_free_log_printer.cpp
|
|
||||||
alloc/ob_malloc_allocator.cpp
|
alloc/ob_malloc_allocator.cpp
|
||||||
alloc/ob_malloc_callback.cpp
|
alloc/ob_malloc_callback.cpp
|
||||||
alloc/ob_malloc_sample_struct.cpp
|
alloc/ob_malloc_sample_struct.cpp
|
||||||
|
|||||||
12
deps/oblib/src/lib/alloc/alloc_struct.h
vendored
12
deps/oblib/src/lib/alloc/alloc_struct.h
vendored
@ -150,13 +150,14 @@ struct ObMemAttr
|
|||||||
prio_(prio),
|
prio_(prio),
|
||||||
use_500_(false),
|
use_500_(false),
|
||||||
expect_500_(true),
|
expect_500_(true),
|
||||||
ignore_version_(ObMemVersionNode::tl_ignore_node)
|
ignore_version_(ObMemVersionNode::tl_ignore_node),
|
||||||
|
alloc_extra_info_(false)
|
||||||
{}
|
{}
|
||||||
int64_t to_string(char* buf, const int64_t buf_len) const;
|
int64_t to_string(char* buf, const int64_t buf_len) const;
|
||||||
bool use_500() const { return use_500_; }
|
bool use_500() const { return use_500_; }
|
||||||
bool expect_500() const { return expect_500_; }
|
bool expect_500() const { return expect_500_; }
|
||||||
bool ignore_version() const { return ignore_version_; }
|
bool ignore_version() const { return ignore_version_; }
|
||||||
private:
|
public:
|
||||||
union {
|
union {
|
||||||
char padding__[4];
|
char padding__[4];
|
||||||
struct {
|
struct {
|
||||||
@ -164,6 +165,7 @@ private:
|
|||||||
uint8_t use_500_ : 1;
|
uint8_t use_500_ : 1;
|
||||||
uint8_t expect_500_ : 1;
|
uint8_t expect_500_ : 1;
|
||||||
uint8_t ignore_version_ : 1;
|
uint8_t ignore_version_ : 1;
|
||||||
|
uint8_t alloc_extra_info_ : 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -300,6 +302,7 @@ struct AObject {
|
|||||||
OB_INLINE ABlock *block() const;
|
OB_INLINE ABlock *block() const;
|
||||||
OB_INLINE uint64_t hold(uint32_t cells_per_block) const;
|
OB_INLINE uint64_t hold(uint32_t cells_per_block) const;
|
||||||
OB_INLINE ObLabel label() const;
|
OB_INLINE ObLabel label() const;
|
||||||
|
OB_INLINE char *bt();
|
||||||
|
|
||||||
// members
|
// members
|
||||||
union {
|
union {
|
||||||
@ -357,6 +360,7 @@ static const uint32_t INTACT_MIDDLE_AOBJECT_SIZE = 64L << 10;
|
|||||||
|
|
||||||
static const int32_t AOBJECT_BACKTRACE_COUNT = 16;
|
static const int32_t AOBJECT_BACKTRACE_COUNT = 16;
|
||||||
static const int32_t AOBJECT_BACKTRACE_SIZE = sizeof(void*) * AOBJECT_BACKTRACE_COUNT;
|
static const int32_t AOBJECT_BACKTRACE_SIZE = sizeof(void*) * AOBJECT_BACKTRACE_COUNT;
|
||||||
|
static const int32_t AOBJECT_EXTRA_INFO_SIZE = AOBJECT_BACKTRACE_SIZE;
|
||||||
|
|
||||||
static const int32_t MAX_BACKTRACE_LENGTH = 512;
|
static const int32_t MAX_BACKTRACE_LENGTH = 512;
|
||||||
|
|
||||||
@ -614,6 +618,10 @@ ObLabel AObject::label() const
|
|||||||
{
|
{
|
||||||
return ObLabel(label_);
|
return ObLabel(label_);
|
||||||
}
|
}
|
||||||
|
char *AObject::bt()
|
||||||
|
{
|
||||||
|
return &data_[alloc_bytes_ + AOBJECT_TAIL_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
class Label
|
class Label
|
||||||
{
|
{
|
||||||
|
|||||||
14
deps/oblib/src/lib/alloc/memory_dump.cpp
vendored
14
deps/oblib/src/lib/alloc/memory_dump.cpp
vendored
@ -431,12 +431,11 @@ int label_stat(AChunk *chunk, ABlock *block, AObject *object,
|
|||||||
LabelItem *litem = nullptr;
|
LabelItem *litem = nullptr;
|
||||||
auto key = std::make_pair(*(uint64_t*)object->label_, *((uint64_t*)object->label_ + 1));
|
auto key = std::make_pair(*(uint64_t*)object->label_, *((uint64_t*)object->label_ + 1));
|
||||||
LabelInfoItem *linfoitem = lmap.get(key);
|
LabelInfoItem *linfoitem = lmap.get(key);
|
||||||
int64_t bt_size = object->on_malloc_sample_ ? AOBJECT_BACKTRACE_SIZE : 0;
|
|
||||||
if (NULL != linfoitem) {
|
if (NULL != linfoitem) {
|
||||||
// exist
|
// exist
|
||||||
litem = linfoitem->litem_;
|
litem = linfoitem->litem_;
|
||||||
litem->hold_ += hold;
|
litem->hold_ += hold;
|
||||||
litem->used_ += (object->alloc_bytes_ - bt_size);
|
litem->used_ += object->alloc_bytes_;
|
||||||
litem->count_++;
|
litem->count_++;
|
||||||
if (chunk != linfoitem->chunk_) {
|
if (chunk != linfoitem->chunk_) {
|
||||||
litem->chunk_cnt_ += 1;
|
litem->chunk_cnt_ += 1;
|
||||||
@ -456,7 +455,7 @@ int label_stat(AChunk *chunk, ABlock *block, AObject *object,
|
|||||||
litem->str_[sizeof(litem->str_) - 1] = '\0';
|
litem->str_[sizeof(litem->str_) - 1] = '\0';
|
||||||
litem->str_len_ = strlen(litem->str_);
|
litem->str_len_ = strlen(litem->str_);
|
||||||
litem->hold_ = hold;
|
litem->hold_ = hold;
|
||||||
litem->used_ = (object->alloc_bytes_ - bt_size);
|
litem->used_ = object->alloc_bytes_;
|
||||||
litem->count_ = 1;
|
litem->count_ = 1;
|
||||||
litem->block_cnt_ = 1;
|
litem->block_cnt_ = 1;
|
||||||
litem->chunk_cnt_ = 1;
|
litem->chunk_cnt_ = 1;
|
||||||
@ -473,20 +472,19 @@ int malloc_sample_stat(uint64_t tenant_id, uint64_t ctx_id,
|
|||||||
{
|
{
|
||||||
int ret = OB_SUCCESS;
|
int ret = OB_SUCCESS;
|
||||||
if (object->in_use_ && object->on_malloc_sample_) {
|
if (object->in_use_ && object->on_malloc_sample_) {
|
||||||
int64_t offset = object->alloc_bytes_ - AOBJECT_BACKTRACE_SIZE;
|
|
||||||
ObMallocSampleKey key;
|
ObMallocSampleKey key;
|
||||||
key.tenant_id_ = tenant_id;
|
key.tenant_id_ = tenant_id;
|
||||||
key.ctx_id_ = ctx_id;
|
key.ctx_id_ = ctx_id;
|
||||||
MEMCPY((char*)key.bt_, &object->data_[offset], AOBJECT_BACKTRACE_SIZE);
|
MEMCPY((char*)key.bt_, object->bt(), AOBJECT_BACKTRACE_SIZE);
|
||||||
STRNCPY(key.label_, object->label_, sizeof(key.label_));
|
STRNCPY(key.label_, object->label_, sizeof(key.label_));
|
||||||
key.label_[sizeof(key.label_) - 1] = '\0';
|
key.label_[sizeof(key.label_) - 1] = '\0';
|
||||||
ObMallocSampleValue *item = malloc_sample_map.get(key);
|
ObMallocSampleValue *item = malloc_sample_map.get(key);
|
||||||
if (NULL != item) {
|
if (NULL != item) {
|
||||||
item->alloc_count_ += 1;
|
item->alloc_count_ += 1;
|
||||||
item->alloc_bytes_ += offset;
|
item->alloc_bytes_ += object->alloc_bytes_;
|
||||||
} else {
|
} else {
|
||||||
ObSignalHandlerGuard guard(ob_signal_handler);
|
ObSignalHandlerGuard guard(ob_signal_handler);
|
||||||
ret = malloc_sample_map.set_refactored(key, ObMallocSampleValue(1, offset));
|
ret = malloc_sample_map.set_refactored(key, ObMallocSampleValue(1, object->alloc_bytes_));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -572,7 +570,7 @@ void ObMemoryDump::handle(void *task)
|
|||||||
has_memory_leak = true;
|
has_memory_leak = true;
|
||||||
char bt[MAX_BACKTRACE_LENGTH] = {'\0'};
|
char bt[MAX_BACKTRACE_LENGTH] = {'\0'};
|
||||||
if (object->on_malloc_sample_) {
|
if (object->on_malloc_sample_) {
|
||||||
parray(bt, sizeof(bt), (int64_t*)&object->data_[object->alloc_bytes_ - AOBJECT_BACKTRACE_SIZE], AOBJECT_BACKTRACE_COUNT);
|
parray(bt, sizeof(bt), (int64_t*)object->bt(), AOBJECT_BACKTRACE_COUNT);
|
||||||
}
|
}
|
||||||
allow_next_syslog();
|
allow_next_syslog();
|
||||||
LOG_WARN("SQL_MEMORY_LEAK", KP(object), K(tenant_id), K(ctx_id), K(object->version_), K(object->label_), K(bt));
|
LOG_WARN("SQL_MEMORY_LEAK", KP(object), K(tenant_id), K(ctx_id), K(object->version_), K(object->label_), K(bt));
|
||||||
|
|||||||
118
deps/oblib/src/lib/alloc/ob_free_log_printer.cpp
vendored
118
deps/oblib/src/lib/alloc/ob_free_log_printer.cpp
vendored
@ -1,118 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 "lib/alloc/ob_free_log_printer.h"
|
|
||||||
#include "lib/alloc/alloc_struct.h"
|
|
||||||
#include "lib/alloc/ob_malloc_sample_struct.h"
|
|
||||||
#include "lib/time/ob_time_utility.h"
|
|
||||||
#include "lib/utility/utility.h"
|
|
||||||
using namespace oceanbase::lib;
|
|
||||||
using namespace oceanbase::common;
|
|
||||||
|
|
||||||
ObFreeLogPrinter::ObFreeLogPrinter() : level_(DEFAULT), lock_()
|
|
||||||
{}
|
|
||||||
|
|
||||||
ObFreeLogPrinter& ObFreeLogPrinter::get_instance()
|
|
||||||
{
|
|
||||||
static ObFreeLogPrinter free_log_print;
|
|
||||||
return free_log_print;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ObFreeLogPrinter::get_level()
|
|
||||||
{
|
|
||||||
int ret = DEFAULT;
|
|
||||||
int reason = g_alloc_failed_ctx().reason_;
|
|
||||||
switch (reason) {
|
|
||||||
case CTX_HOLD_REACH_LIMIT : {
|
|
||||||
ret = CTX;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TENANT_HOLD_REACH_LIMIT: {
|
|
||||||
ret = TENANT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SERVER_HOLD_REACH_LIMIT: {
|
|
||||||
ret = SERVER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PHYSICAL_MEMORY_EXHAUST: {
|
|
||||||
ret = SERVER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObFreeLogPrinter::enable_free_log(int64_t tenant_id, int64_t ctx_id, int level)
|
|
||||||
{
|
|
||||||
bool has_lock = false;
|
|
||||||
if (DEFAULT == level_ && OB_SUCCESS == lock_.trylock()) {
|
|
||||||
DEFER(lock_.unlock());
|
|
||||||
last_enable_time_ = ObTimeUtility::current_time();
|
|
||||||
tenant_id_ = tenant_id;
|
|
||||||
ctx_id_ = ctx_id;
|
|
||||||
level_ = level;
|
|
||||||
has_lock = true;
|
|
||||||
}
|
|
||||||
if (has_lock) {
|
|
||||||
_OB_LOG(INFO, "start to print free log");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObFreeLogPrinter::disable_free_log()
|
|
||||||
{
|
|
||||||
bool has_lock = false;
|
|
||||||
if (DEFAULT != level_ && OB_SUCCESS == lock_.trylock()) {
|
|
||||||
DEFER(lock_.unlock());
|
|
||||||
level_ = DEFAULT;
|
|
||||||
has_lock = true;
|
|
||||||
}
|
|
||||||
if (has_lock) {
|
|
||||||
_OB_LOG(INFO, "finish to print free log");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObFreeLogPrinter::print_free_log(int64_t tenant_id, int64_t ctx_id, AObject *obj)
|
|
||||||
{
|
|
||||||
if (DEFAULT != level_ && obj->on_malloc_sample_) {
|
|
||||||
if (ObTimeUtility::current_time() - last_enable_time_ > MAX_FREE_LOG_TIME) {
|
|
||||||
disable_free_log();
|
|
||||||
} else {
|
|
||||||
bool allowed = false;
|
|
||||||
switch (level_) {
|
|
||||||
case CTX: {
|
|
||||||
allowed = tenant_id == tenant_id_ && ctx_id == ctx_id_;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case TENANT: {
|
|
||||||
allowed = tenant_id == tenant_id_;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SERVER: {
|
|
||||||
allowed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allowed) {
|
|
||||||
char buf[MAX_BACKTRACE_LENGTH];
|
|
||||||
int64_t addrs[AOBJECT_BACKTRACE_COUNT];
|
|
||||||
int64_t offset = obj->alloc_bytes_ - AOBJECT_BACKTRACE_SIZE;
|
|
||||||
MEMCPY((char*)addrs, &obj->data_[offset], sizeof(addrs));
|
|
||||||
IGNORE_RETURN parray(buf, sizeof(buf), addrs, ARRAYSIZEOF(addrs));
|
|
||||||
allow_next_syslog();
|
|
||||||
_OB_LOG(INFO, "[MEM_FREE_LOG] tenant_id=%ld, ctx_name=%s, mod=%s, alloc_bytes=%u, malloc_bt=%s\n",
|
|
||||||
tenant_id, get_global_ctx_info().get_ctx_name(ctx_id),
|
|
||||||
obj->label_, obj->alloc_bytes_, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
48
deps/oblib/src/lib/alloc/ob_free_log_printer.h
vendored
48
deps/oblib/src/lib/alloc/ob_free_log_printer.h
vendored
@ -1,48 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 _OB_FREE_LOG_PRINTER_H_
|
|
||||||
#define _OB_FREE_LOG_PRINTER_H_
|
|
||||||
#include "lib/lock/ob_mutex.h"
|
|
||||||
namespace oceanbase
|
|
||||||
{
|
|
||||||
namespace lib
|
|
||||||
{
|
|
||||||
class AObject;
|
|
||||||
class ObFreeLogPrinter
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
const int64_t MAX_FREE_LOG_TIME = 30 * 1000 * 1000; //30s
|
|
||||||
enum Level
|
|
||||||
{
|
|
||||||
DEFAULT = 0,
|
|
||||||
CTX = 1,
|
|
||||||
TENANT = 2,
|
|
||||||
SERVER = 3,
|
|
||||||
};
|
|
||||||
ObFreeLogPrinter();
|
|
||||||
static ObFreeLogPrinter& get_instance();
|
|
||||||
static int get_level();
|
|
||||||
void enable_free_log(int64_t tenant_id , int64_t ctx_id, int level);
|
|
||||||
void disable_free_log();
|
|
||||||
void print_free_log(int64_t tenant_id, int64_t ctx_id, AObject *obj);
|
|
||||||
private:
|
|
||||||
int64_t last_enable_time_;
|
|
||||||
int64_t tenant_id_;
|
|
||||||
int64_t ctx_id_;
|
|
||||||
int level_;
|
|
||||||
ObMutex lock_;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -159,15 +159,6 @@ inline bool ObMallocSampleKey::operator==(const ObMallocSampleKey &other) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ob_malloc_sample_backtrace(obj, size) \
|
|
||||||
{ \
|
|
||||||
if (OB_UNLIKELY(obj->on_malloc_sample_)) { \
|
|
||||||
void *addrs[100] = {nullptr}; \
|
|
||||||
int bt_len = ob_backtrace(addrs, ARRAYSIZEOF(addrs)); \
|
|
||||||
STATIC_ASSERT(AOBJECT_BACKTRACE_SIZE < sizeof(addrs), "AOBJECT_BACKTRACE_SIZE must be less than addrs!");\
|
|
||||||
MEMCPY(&obj->data_[size], (char*)addrs, AOBJECT_BACKTRACE_SIZE); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
} // end of namespace lib
|
} // end of namespace lib
|
||||||
} // end of namespace oceanbase
|
} // end of namespace oceanbase
|
||||||
|
|
||||||
|
|||||||
@ -413,7 +413,6 @@ void* ObTenantCtxAllocator::common_realloc(const void *ptr, const int64_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
AObject *obj = NULL;
|
AObject *obj = NULL;
|
||||||
int64_t alloc_size = 0;
|
|
||||||
bool sample_allowed = false;
|
bool sample_allowed = false;
|
||||||
bool is_errsim = false;
|
bool is_errsim = false;
|
||||||
if (NULL != ptr) {
|
if (NULL != ptr) {
|
||||||
@ -436,13 +435,14 @@ void* ObTenantCtxAllocator::common_realloc(const void *ptr, const int64_t size,
|
|||||||
#endif
|
#endif
|
||||||
ObLightBacktraceGuard light_backtrace_guard(is_memleak_light_backtrace_enabled()
|
ObLightBacktraceGuard light_backtrace_guard(is_memleak_light_backtrace_enabled()
|
||||||
&& ObCtxIds::GLIBC != attr.ctx_id_);
|
&& ObCtxIds::GLIBC != attr.ctx_id_);
|
||||||
|
ObMemAttr inner_attr = attr;
|
||||||
if (OB_UNLIKELY(is_errsim)) {
|
if (OB_UNLIKELY(is_errsim)) {
|
||||||
} else {
|
} else {
|
||||||
BASIC_TIME_GUARD(time_guard, "ObMalloc");
|
BASIC_TIME_GUARD(time_guard, "ObMalloc");
|
||||||
DEFER(ObMallocTimeMonitor::get_instance().record_malloc_time(time_guard, size, attr));
|
DEFER(ObMallocTimeMonitor::get_instance().record_malloc_time(time_guard, size, inner_attr));
|
||||||
sample_allowed = ObMallocSampleLimiter::malloc_sample_allowed(size, attr);
|
sample_allowed = ObMallocSampleLimiter::malloc_sample_allowed(size, inner_attr);
|
||||||
alloc_size = sample_allowed ? (size + AOBJECT_BACKTRACE_SIZE) : size;
|
inner_attr.alloc_extra_info_ = sample_allowed;
|
||||||
obj = allocator.realloc_object(obj, alloc_size, attr);
|
obj = allocator.realloc_object(obj, size, inner_attr);
|
||||||
if(OB_ISNULL(obj)) {
|
if(OB_ISNULL(obj)) {
|
||||||
int64_t total_size = 0;
|
int64_t total_size = 0;
|
||||||
if (g_alloc_failed_ctx().need_wash_block()) {
|
if (g_alloc_failed_ctx().need_wash_block()) {
|
||||||
@ -453,31 +453,40 @@ void* ObTenantCtxAllocator::common_realloc(const void *ptr, const int64_t size,
|
|||||||
BASIC_TIME_GUARD_CLICK("WASH_CHUNK_END");
|
BASIC_TIME_GUARD_CLICK("WASH_CHUNK_END");
|
||||||
}
|
}
|
||||||
if (total_size > 0) {
|
if (total_size > 0) {
|
||||||
obj = allocator.realloc_object(obj, alloc_size, attr);
|
obj = allocator.realloc_object(obj, size, inner_attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
obj->on_malloc_sample_ = sample_allowed;
|
if (inner_attr.label_.str_ != nullptr) {
|
||||||
ob_malloc_sample_backtrace(obj, size);
|
STRNCPY(obj->label_, inner_attr.label_.str_, sizeof(obj->label_));
|
||||||
obj->ignore_version_ = attr.ignore_version() || ObMemVersionNode::tl_ignore_node;
|
obj->label_[sizeof(obj->label_) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
MEMSET(obj->label_, '\0', sizeof(obj->label_));
|
||||||
|
}
|
||||||
|
if (sample_allowed) {
|
||||||
|
void *addrs[100] = {nullptr};
|
||||||
|
ob_backtrace(addrs, ARRAYSIZEOF(addrs));
|
||||||
|
STATIC_ASSERT(AOBJECT_BACKTRACE_SIZE < sizeof(addrs), "AOBJECT_BACKTRACE_SIZE must be less than addrs!");
|
||||||
|
MEMCPY(obj->bt(), (char*)addrs, AOBJECT_BACKTRACE_SIZE);
|
||||||
|
obj->on_malloc_sample_ = true;
|
||||||
|
}
|
||||||
|
obj->ignore_version_ = inner_attr.ignore_version() || ObMemVersionNode::tl_ignore_node;
|
||||||
if (!obj->ignore_version_) {
|
if (!obj->ignore_version_) {
|
||||||
obj->version_ = ObMemVersionNode::tl_node->version_;
|
obj->version_ = ObMemVersionNode::tl_node->version_;
|
||||||
}
|
}
|
||||||
nptr = obj->data_;
|
nptr = obj->data_;
|
||||||
get_mem_leak_checker().on_alloc(*obj, attr);
|
get_mem_leak_checker().on_alloc(*obj, inner_attr);
|
||||||
SANITY_POISON(obj, AOBJECT_HEADER_SIZE);
|
SANITY_POISON(obj, obj->nobjs_ * AOBJECT_CELL_BYTES);
|
||||||
SANITY_UNPOISON(obj->data_, size);
|
SANITY_UNPOISON(obj->data_, size);
|
||||||
SANITY_POISON((void*)upper_align((int64_t)obj->data_ + size, 8),
|
|
||||||
alloc_size - size + sizeof(AOBJECT_TAIL_MAGIC_CODE));
|
|
||||||
} else if (TC_REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
|
} else if (TC_REACH_TIME_INTERVAL(1 * 1000 * 1000)) {
|
||||||
const char *msg = is_errsim ? "[ERRSIM] errsim inject memory error" : alloc_failed_msg();
|
const char *msg = is_errsim ? "[ERRSIM] errsim inject memory error" : alloc_failed_msg();
|
||||||
LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg));
|
LOG_DBA_WARN(OB_ALLOCATE_MEMORY_FAILED, "[OOPS]", "alloc failed reason", KCSTRING(msg));
|
||||||
_OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, "
|
_OB_LOG_RET(WARN, OB_ALLOCATE_MEMORY_FAILED, "oops, alloc failed, tenant_id=%ld, ctx_id=%ld, ctx_name=%s, ctx_hold=%ld, "
|
||||||
"ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld",
|
"ctx_limit=%ld, tenant_hold=%ld, tenant_limit=%ld",
|
||||||
attr.tenant_id_, attr.ctx_id_,
|
inner_attr.tenant_id_, inner_attr.ctx_id_,
|
||||||
get_global_ctx_info().get_ctx_name(attr.ctx_id_),
|
get_global_ctx_info().get_ctx_name(inner_attr.ctx_id_),
|
||||||
ta.get_hold(), ta.get_limit(), ta.get_tenant_hold(), ta.get_tenant_limit());
|
ta.get_hold(), ta.get_limit(), ta.get_tenant_hold(), ta.get_tenant_limit());
|
||||||
// 49 is the user defined signal to dump memory
|
// 49 is the user defined signal to dump memory
|
||||||
raise(49);
|
raise(49);
|
||||||
|
|||||||
17
deps/oblib/src/lib/alloc/object_mgr.cpp
vendored
17
deps/oblib/src/lib/alloc/object_mgr.cpp
vendored
@ -14,6 +14,7 @@
|
|||||||
#include "lib/allocator/ob_ctx_define.h"
|
#include "lib/allocator/ob_ctx_define.h"
|
||||||
#include "lib/alloc/ob_malloc_allocator.h"
|
#include "lib/alloc/ob_malloc_allocator.h"
|
||||||
#include "lib/alloc/memory_sanity.h"
|
#include "lib/alloc/memory_sanity.h"
|
||||||
|
#include "lib/alloc/ob_tenant_ctx_allocator.h"
|
||||||
|
|
||||||
using namespace oceanbase;
|
using namespace oceanbase;
|
||||||
using namespace lib;
|
using namespace lib;
|
||||||
@ -243,14 +244,12 @@ SubObjectMgr *ObjectMgr::create_sub_mgr()
|
|||||||
attr.tenant_id_ = OB_SERVER_TENANT_ID;
|
attr.tenant_id_ = OB_SERVER_TENANT_ID;
|
||||||
attr.label_ = common::ObModIds::OB_TENANT_CTX_ALLOCATOR;
|
attr.label_ = common::ObModIds::OB_TENANT_CTX_ALLOCATOR;
|
||||||
attr.ctx_id_ = ObCtxIds::DEFAULT_CTX_ID;
|
attr.ctx_id_ = ObCtxIds::DEFAULT_CTX_ID;
|
||||||
|
attr.ignore_version_ = true;
|
||||||
root_mgr.lock();
|
root_mgr.lock();
|
||||||
auto *obj = root_mgr.alloc_object(sizeof(SubObjectMgr), attr);
|
void *ptr = ObTenantCtxAllocator::common_realloc(NULL, sizeof(SubObjectMgr), attr, *(ta.ref_allocator()), root_mgr);
|
||||||
root_mgr.unlock();
|
root_mgr.unlock();
|
||||||
if (OB_NOT_NULL(obj)) {
|
if (OB_NOT_NULL(ptr)) {
|
||||||
obj->ignore_version_ = true;
|
sub_mgr = new (ptr) SubObjectMgr(ta_, enable_no_log_,
|
||||||
SANITY_UNPOISON(obj->data_, obj->alloc_bytes_);
|
|
||||||
sub_mgr = new (obj->data_) SubObjectMgr(ta_,
|
|
||||||
enable_no_log_,
|
|
||||||
ablock_size_, enable_dirty_list_, blk_mgr_);
|
ablock_size_, enable_dirty_list_, blk_mgr_);
|
||||||
}
|
}
|
||||||
return sub_mgr;
|
return sub_mgr;
|
||||||
@ -263,11 +262,7 @@ void ObjectMgr::destroy_sub_mgr(SubObjectMgr *sub_mgr)
|
|||||||
ObCtxIds::DEFAULT_CTX_ID);
|
ObCtxIds::DEFAULT_CTX_ID);
|
||||||
auto &root_mgr = static_cast<ObjectMgr&>(ta->get_block_mgr()).root_mgr_;
|
auto &root_mgr = static_cast<ObjectMgr&>(ta->get_block_mgr()).root_mgr_;
|
||||||
sub_mgr->~SubObjectMgr();
|
sub_mgr->~SubObjectMgr();
|
||||||
auto *obj = reinterpret_cast<AObject*>((char*)sub_mgr - AOBJECT_HEADER_SIZE);
|
ObTenantCtxAllocator::common_free(sub_mgr);
|
||||||
abort_unless(obj->MAGIC_CODE_ == AOBJECT_MAGIC_CODE
|
|
||||||
|| obj->MAGIC_CODE_ == BIG_AOBJECT_MAGIC_CODE);
|
|
||||||
SANITY_POISON(obj->data_, obj->alloc_bytes_);
|
|
||||||
root_mgr.free_object(obj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
4
deps/oblib/src/lib/alloc/object_mgr.h
vendored
4
deps/oblib/src/lib/alloc/object_mgr.h
vendored
@ -49,6 +49,10 @@ public:
|
|||||||
{
|
{
|
||||||
return os_.alloc_object(size, attr);
|
return os_.alloc_object(size, attr);
|
||||||
}
|
}
|
||||||
|
OB_INLINE AObject *realloc_object(AObject *obj, const uint64_t size, const ObMemAttr &attr)
|
||||||
|
{
|
||||||
|
return os_.realloc_object(obj, size, attr);
|
||||||
|
}
|
||||||
void free_object(AObject *object);
|
void free_object(AObject *object);
|
||||||
OB_INLINE ABlock *alloc_block(uint64_t size, const ObMemAttr &attr) override
|
OB_INLINE ABlock *alloc_block(uint64_t size, const ObMemAttr &attr) override
|
||||||
{
|
{
|
||||||
|
|||||||
26
deps/oblib/src/lib/alloc/object_set.cpp
vendored
26
deps/oblib/src/lib/alloc/object_set.cpp
vendored
@ -55,7 +55,8 @@ AObject *ObjectSet::alloc_object(
|
|||||||
const uint64_t size, const ObMemAttr &attr)
|
const uint64_t size, const ObMemAttr &attr)
|
||||||
{
|
{
|
||||||
const uint64_t adj_size = MAX(size, MIN_AOBJECT_SIZE);
|
const uint64_t adj_size = MAX(size, MIN_AOBJECT_SIZE);
|
||||||
const uint64_t all_size = align_up2(adj_size + AOBJECT_META_SIZE, 16);
|
const uint64_t meta_size = AOBJECT_META_SIZE + (attr.alloc_extra_info_ ? AOBJECT_EXTRA_INFO_SIZE : 0);
|
||||||
|
const uint64_t all_size = align_up2(adj_size + meta_size, 16);
|
||||||
|
|
||||||
const int64_t ctx_id = blk_mgr_->get_ctx_id();
|
const int64_t ctx_id = blk_mgr_->get_ctx_id();
|
||||||
abort_unless(ctx_id == attr.ctx_id_);
|
abort_unless(ctx_id == attr.ctx_id_);
|
||||||
@ -77,7 +78,7 @@ AObject *ObjectSet::alloc_object(
|
|||||||
normal_used_bytes_ += obj->nobjs_ * AOBJECT_CELL_BYTES;
|
normal_used_bytes_ += obj->nobjs_ * AOBJECT_CELL_BYTES;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
obj = alloc_big_object(adj_size, attr);
|
obj = alloc_big_object(all_size, attr);
|
||||||
abort_unless(NULL == obj || obj->in_use_);
|
abort_unless(NULL == obj || obj->in_use_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,12 +87,6 @@ AObject *ObjectSet::alloc_object(
|
|||||||
abort_unless(obj->is_valid());
|
abort_unless(obj->is_valid());
|
||||||
reinterpret_cast<uint64_t&>(obj->data_[size]) = AOBJECT_TAIL_MAGIC_CODE;
|
reinterpret_cast<uint64_t&>(obj->data_[size]) = AOBJECT_TAIL_MAGIC_CODE;
|
||||||
obj->alloc_bytes_ = static_cast<uint32_t>(size);
|
obj->alloc_bytes_ = static_cast<uint32_t>(size);
|
||||||
if (attr.label_.str_ != nullptr) {
|
|
||||||
STRNCPY(&obj->label_[0], attr.label_.str_, sizeof(obj->label_));
|
|
||||||
obj->label_[sizeof(obj->label_) - 1] = '\0';
|
|
||||||
} else {
|
|
||||||
MEMSET(obj->label_, '\0', sizeof(obj->label_));
|
|
||||||
}
|
|
||||||
allocs_++;
|
allocs_++;
|
||||||
alloc_bytes_ += size;
|
alloc_bytes_ += size;
|
||||||
used_bytes_ += obj->hold(cells_per_block_);
|
used_bytes_ += obj->hold(cells_per_block_);
|
||||||
@ -104,19 +99,12 @@ AObject *ObjectSet::realloc_object(
|
|||||||
AObject *obj, const uint64_t size, const ObMemAttr &attr)
|
AObject *obj, const uint64_t size, const ObMemAttr &attr)
|
||||||
{
|
{
|
||||||
AObject *new_obj = NULL;
|
AObject *new_obj = NULL;
|
||||||
uint64_t copy_size = 0;
|
|
||||||
|
|
||||||
if (NULL == obj) {
|
if (NULL == obj) {
|
||||||
new_obj = alloc_object(size, attr);
|
new_obj = alloc_object(size, attr);
|
||||||
} else {
|
} else {
|
||||||
abort_unless(obj->is_valid());
|
abort_unless(obj->is_valid());
|
||||||
if (obj->is_large_ != 0) {
|
uint64_t copy_size = MIN(obj->alloc_bytes_, size);
|
||||||
copy_size = MIN(obj->alloc_bytes_, size);
|
|
||||||
} else {
|
|
||||||
copy_size = MIN(
|
|
||||||
size, (obj->nobjs_ - META_CELLS) * AOBJECT_CELL_BYTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
new_obj = alloc_object(size, attr);
|
new_obj = alloc_object(size, attr);
|
||||||
if (NULL != new_obj && copy_size != 0) {
|
if (NULL != new_obj && copy_size != 0) {
|
||||||
memmove(new_obj->data_, obj->data_, copy_size);
|
memmove(new_obj->data_, obj->data_, copy_size);
|
||||||
@ -336,13 +324,12 @@ void ObjectSet::free_block(ABlock *block)
|
|||||||
AObject *ObjectSet::alloc_big_object(const uint64_t size, const ObMemAttr &attr)
|
AObject *ObjectSet::alloc_big_object(const uint64_t size, const ObMemAttr &attr)
|
||||||
{
|
{
|
||||||
AObject *obj = NULL;
|
AObject *obj = NULL;
|
||||||
ABlock *block = alloc_block(size + AOBJECT_META_SIZE, attr);
|
ABlock *block = alloc_block(size, attr);
|
||||||
|
|
||||||
if (NULL != block) {
|
if (NULL != block) {
|
||||||
obj = new (block->data()) AObject();
|
obj = new (block->data()) AObject();
|
||||||
obj->is_large_ = true;
|
obj->is_large_ = true;
|
||||||
obj->in_use_ = true;
|
obj->in_use_ = true;
|
||||||
obj->alloc_bytes_ = static_cast<uint32_t>(size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@ -491,8 +478,7 @@ bool ObjectSet::check_has_unfree(char *first_label, char *first_bt)
|
|||||||
}
|
}
|
||||||
if (obj->on_malloc_sample_ && '\0' == first_bt[0]) {
|
if (obj->on_malloc_sample_ && '\0' == first_bt[0]) {
|
||||||
void *addrs[AOBJECT_BACKTRACE_COUNT];
|
void *addrs[AOBJECT_BACKTRACE_COUNT];
|
||||||
int64_t offset = obj->alloc_bytes_ - AOBJECT_BACKTRACE_SIZE;
|
MEMCPY((char*)addrs, obj->bt(), AOBJECT_BACKTRACE_SIZE);
|
||||||
MEMCPY((char*)addrs, &obj->data_[offset], AOBJECT_BACKTRACE_SIZE);
|
|
||||||
IGNORE_RETURN parray(first_bt, MAX_BACKTRACE_LENGTH, (int64_t*)addrs, AOBJECT_BACKTRACE_COUNT);
|
IGNORE_RETURN parray(first_bt, MAX_BACKTRACE_LENGTH, (int64_t*)addrs, AOBJECT_BACKTRACE_COUNT);
|
||||||
}
|
}
|
||||||
if (!has_unfree) {
|
if (!has_unfree) {
|
||||||
|
|||||||
Reference in New Issue
Block a user