[Feature] Auto extend disk space

This commit is contained in:
obdev
2022-05-25 20:49:58 +08:00
committed by wangzelin.wzl
parent f8f72a41bc
commit d22cee91c3
18 changed files with 511 additions and 160 deletions

View File

@ -805,6 +805,35 @@ int64_t ObLocalFileSystem::get_free_macro_block_count() const
return store_file_.get_free_macro_block_count();
}
int64_t ObLocalFileSystem::get_total_macro_block_max_count() const
{
int ret = OB_SUCCESS;
int64_t total_space = 0;
int64_t free_space = 0;
int64_t max_block_count = 0;
int64_t max_block_size;
int64_t datafile_size = GCONF.datafile_size;
int64_t datafile_maxsize = GCONF.datafile_maxsize;
if (OB_FAIL(FileDirectoryUtils::get_disk_space(sstable_dir_, total_space, free_space))) {
STORAGE_LOG(WARN, "Failed to get disk space ", K(ret));
} else if (datafile_size > 0 && data_file_size_ < datafile_maxsize ) {
// get total block count of ssblock file. Further more, if auto extend mode is on,
// and the disk is shared, the volume of disk will not fixed
int64_t actual_disk_max_size = data_file_size_ + free_space;
actual_disk_max_size = actual_disk_max_size < datafile_maxsize ?
actual_disk_max_size : datafile_maxsize;
max_block_size = lower_align(actual_disk_max_size, macro_block_size_);
} else {
max_block_size = lower_align(data_file_size_, macro_block_size_); // cur total block cnt
}
if (OB_SUCC(ret)) {
max_block_count = max_block_size / macro_block_size_;
}
return max_block_count;
}
int ObLocalFileSystem::get_marker_status(ObMacroBlockMarkerStatus& status)
{
return store_file_.get_store_status(status);
@ -883,7 +912,8 @@ int ObLocalFileSystem::inner_get_super_block_version(const int64_t offset, int64
return ret;
}
int ObLocalFileSystem::resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage)
int ObLocalFileSystem::resize_file(
const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage, const int64_t extend_size)
{
int ret = OB_SUCCESS;
int64_t new_cal_data_file_size = new_data_file_size;
@ -891,9 +921,13 @@ int ObLocalFileSystem::resize_file(const int64_t new_data_file_size, const int64
int64_t free_space = 0;
if (OB_FAIL(FileDirectoryUtils::get_disk_space(sstable_dir_, total_space, free_space))) {
STORAGE_LOG(WARN, "Failed to get disk space ", K(ret));
} else if (extend_size > 0) { // auto extend disk size, extend_size default 0
int64_t max_extend_size = free_space;
max_extend_size = extend_size < max_extend_size ? extend_size : max_extend_size;
new_cal_data_file_size = data_file_size_ + max_extend_size;
} else if (new_cal_data_file_size <= 0) {
new_cal_data_file_size = total_space * new_data_file_disk_percentage / 100;
}
}
#ifdef ERRSIM
if (OB_SUCC(ret)) {
ret = E(EventTable::EN_RESIZE_PHYSICAL_FILE_FAILED) OB_SUCCESS;
@ -906,8 +940,11 @@ int ObLocalFileSystem::resize_file(const int64_t new_data_file_size, const int64
const int64_t curr_aligned_file_size = lower_align(data_file_size_, macro_block_size_);
const int64_t new_aligned_file_size = lower_align(new_cal_data_file_size, macro_block_size_);
if (curr_aligned_file_size > new_aligned_file_size) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("can not resize file to smaller", K(ret), K(curr_aligned_file_size), K(new_aligned_file_size));
ret = OB_ERR_RESIZE_FILE_TO_SMALLER;
LOG_WARN("can not resize file to smaller",
K(ret),
K(curr_aligned_file_size),
K(new_aligned_file_size));
} else if (curr_aligned_file_size == new_aligned_file_size) {
LOG_INFO("new file size is equal to current file size, do not need to resize file",
K(curr_aligned_file_size),
@ -917,11 +954,16 @@ int ObLocalFileSystem::resize_file(const int64_t new_data_file_size, const int64
const int64_t offset = curr_aligned_file_size;
const int64_t delta_size = new_aligned_file_size - curr_aligned_file_size;
if (0 != (sys_ret = ::fallocate(fd_.fd_, 0, offset, delta_size))) {
LOG_WARN("fail to expand file size", K(ret), K(sys_ret), K(offset), K(delta_size), K(errno), KERRMSG);
LOG_WARN("fail to expand file size",
K(ret), K(sys_ret), K(offset), K(delta_size), K(free_space), K(errno), KERRMSG);
} else {
data_file_size_ = new_cal_data_file_size;
datafile_disk_percentage_ = new_data_file_disk_percentage;
LOG_INFO("succeed to resize file", K(data_file_size_), K(datafile_disk_percentage_));
data_file_size_ = new_cal_data_file_size;
datafile_disk_percentage_ = new_data_file_disk_percentage;
LOG_INFO("succeed to resize file",
K(extend_size),
K(delta_size),
K(data_file_size_),
K(datafile_disk_percentage_));
}
}
}

View File

@ -111,7 +111,8 @@ public:
virtual int get_marker_status(ObMacroBlockMarkerStatus& status) override;
virtual int read_old_super_block(ObSuperBlockV2& super_block) override;
virtual int get_super_block_version(int64_t& super_block_version) override;
virtual int resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage) override;
virtual int resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage, const int64_t extend_size = 0) override;
virtual int64_t get_total_macro_block_max_count() const override;
OB_INLINE int get_block_file_fd() const { return fd_.fd_; }

View File

@ -338,6 +338,23 @@ int ObMacroBlockHandleV1::set_macro_block_id(const MacroBlockId& macro_block_id)
return ret;
}
/**
* ---------------------------------------------------------ObStoreFileAutoExtendTask-----------------------------------------------------------
*/
ObStoreFileAutoExtendTask::ObStoreFileAutoExtendTask()
{}
ObStoreFileAutoExtendTask::~ObStoreFileAutoExtendTask()
{}
// TODO Before mini merge adjustment, create PG, which will be cored here
void ObStoreFileAutoExtendTask::runTimerTask()
{
OB_STORE_FILE.ssblock_check_and_extend();
}
/**
* ---------------------------------------------------------ObStoreFileGCTask-----------------------------------------------------------
*/
@ -398,6 +415,7 @@ ObStoreFile::ObStoreFile()
meta_array_lock_(),
cur_meta_array_pos_(0),
gc_task_(),
ssblock_auto_extend_task_(),
inspect_bad_block_task_(),
print_buffer_(NULL),
print_buffer_size_(ObLogger::MAX_LOG_SIZE - 100),
@ -408,9 +426,11 @@ ObStoreFile::ObStoreFile()
store_file_system_(NULL),
is_mark_sweep_enabled_(false),
is_doing_mark_sweep_(false),
is_doing_disk_extend_(false),
cond_(),
is_fs_support_punch_hole_(true),
block_file_fd_(OB_INVALID_FD)
block_file_fd_(OB_INVALID_FD),
alloc_lock_()
{
MEMSET(used_macro_cnt_, 0, sizeof(used_macro_cnt_));
}
@ -522,6 +542,10 @@ int ObStoreFile::open(const bool is_physical_flashback)
STORAGE_LOG(WARN, "Fail to schedule gc task, ", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(lib::TGDefIDs::StoreFileGC, inspect_bad_block_task_, INSPECT_DELAY_US, true))) {
STORAGE_LOG(WARN, "Fail to schedule bad_block_inspect task, ", K(ret));
} else if (OB_FAIL(TG_START(lib::TGDefIDs::StoreFileAutoExtend))){
STORAGE_LOG(WARN, "Fail to start StoreFileAutoExtend timer", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(lib::TGDefIDs::StoreFileAutoExtend, ssblock_auto_extend_task_, AUTOEXTEND_DELAY_US, true))) {
STORAGE_LOG(WARN, "Fail to schedule StoreFileAutoExtend task", K(ret));
} else {
is_opened_ = true;
if (is_replay_old) {
@ -555,6 +579,9 @@ void ObStoreFile::destroy()
inspect_bad_block_task_.destroy();
TG_STOP(lib::TGDefIDs::StoreFileGC);
TG_WAIT(lib::TGDefIDs::StoreFileGC);
TG_STOP(lib::TGDefIDs::StoreFileAutoExtend);
TG_WAIT(lib::TGDefIDs::StoreFileAutoExtend);
SLOGGER.destroy();
lib::ObMutexGuard bad_block_guard(bad_block_lock_);
@ -584,6 +611,7 @@ void ObStoreFile::destroy()
is_opened_ = false;
is_mark_sweep_enabled_ = false;
is_doing_mark_sweep_ = false;
is_doing_disk_extend_ = false;
cond_.destroy();
is_fs_support_punch_hole_ = true;
block_file_fd_ = OB_INVALID_FD;
@ -592,6 +620,7 @@ void ObStoreFile::destroy()
void ObStoreFile::stop()
{
TG_STOP(lib::TGDefIDs::StoreFileGC);
TG_STOP(lib::TGDefIDs::StoreFileAutoExtend);
is_opened_ = false;
STORAGE_LOG(INFO, "the store file gc task stopped");
}
@ -599,6 +628,7 @@ void ObStoreFile::stop()
void ObStoreFile::wait()
{
TG_WAIT(lib::TGDefIDs::StoreFileGC);
TG_WAIT(lib::TGDefIDs::StoreFileAutoExtend);
STORAGE_LOG(INFO, "the store file finish wait");
}
@ -800,15 +830,33 @@ int ObStoreFile::check_disk_full(const int64_t required_size) const
ret = OB_INVALID_ARGUMENT;
STORAGE_LOG(WARN, "invalid args", K(ret), K(required_size));
} else {
int64_t calc_total_block_cnt = store_file_system_->get_total_macro_block_count();;
int64_t calc_free_block_cnt = free_block_cnt_;
// if auto disk extend is active, calc total block and free block cnt
int64_t cur_total_data_file_size = store_file_system_->get_total_data_size();
if (cur_total_data_file_size > 0 &&
cur_total_data_file_size < GCONF.datafile_maxsize) { // if auto extend mode is on
int64_t cur_total_block_cnt = store_file_system_->get_total_macro_block_count();
calc_total_block_cnt =
store_file_system_->get_total_macro_block_max_count();
calc_free_block_cnt =
calc_total_block_cnt - cur_total_block_cnt + free_block_cnt_;
}
const int64_t required_count = required_size / store_file_system_->get_macro_block_size();
const int64_t free_count = free_block_cnt_ - required_count;
const int64_t used_percent = 100 - 100 * free_count / store_file_system_->get_total_macro_block_count();
const int64_t free_count = calc_free_block_cnt - required_count;
const int64_t used_percent = 100 - 100 * free_count / calc_total_block_cnt;
if (GCONF.data_disk_usage_limit_percentage != NO_LIMIT_PERCENT &&
used_percent >= GCONF.data_disk_usage_limit_percentage) {
ret = OB_CS_OUTOF_DISK_SPACE;
if (REACH_TIME_INTERVAL(24 * 3600LL * 1000 * 1000 /* 24h */)) {
STORAGE_LOG(
ERROR, "disk is almost full", K(ret), K(required_size), K(required_count), K(free_count), K(used_percent));
STORAGE_LOG(ERROR, "disk is almost full",
K(ret), K(required_size),
K(required_count),
K(free_count),
K(used_percent),
K(calc_free_block_cnt),
K(calc_total_block_cnt));
}
}
}
@ -950,6 +998,35 @@ int ObStoreFile::is_free_block(const int64_t block_index, bool& is_free)
return ret;
}
int ObStoreFile::auto_extend_file_size()
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(free_block_cnt_ > 0)) {
} else if (OB_FAIL(extend_file_size_task())) {
LOG_WARN("Fail to extend file size", K(ret));
} else if (OB_FAIL(TG_SCHEDULE(lib::TGDefIDs::StoreFileGC, gc_task_, 0, false))) {
LOG_WARN("Fail to schedule gc task to mark and sweep", K(ret));
} else {
int64_t begin_time = ObTimeUtility::current_time();
while (OB_SUCC(ret)) {
// check free blocks after gc_task get started.
// so if we cannot get free_block_cnt > 0 after extend_file_size_task,
// we should do retry until free_block_cnt refresh already or timeout after 5s
// to return failed.
if (free_block_cnt_ > 0) {
break;
}
if (ObTimeUtility::current_time() - begin_time > MARK_BLOCK_INFO_TIMEOUT) {
LOG_WARN("Timeout loop of waitting and getting free blocks",
K(free_block_cnt_));
ret = OB_MARK_BLOCK_INFO_TIMEOUT;
}
usleep(50 * 1000); // 50ms
}
}
return ret;
}
int ObStoreFile::alloc_block(ObMacroBlockHandle& macro_handle)
{
int ret = OB_SUCCESS;
@ -957,16 +1034,21 @@ int ObStoreFile::alloc_block(ObMacroBlockHandle& macro_handle)
macro_handle.reuse();
const int64_t MAX_ALLOC_BLOCK_TRY_COUNT = 10;
lib::ObMutexGuard guard(block_lock_);
if (OB_UNLIKELY(free_block_cnt_ <= 0)) {
ret = OB_CS_OUTOF_DISK_SPACE;
STORAGE_LOG(ERROR,
"Fail to alloc block, ",
lib::ObMutexGuard guard(alloc_lock_); // lock free_block_cnt--
if (OB_ISNULL(store_file_system_)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("Fail to alloc block, null pointer", K(ret));
} else if (OB_LIKELY(free_block_cnt_ > 0)) {
// do nothing
} else if (OB_FAIL(auto_extend_file_size())) {
int64_t total_block_cnt = store_file_system_->get_total_macro_block_count();
STORAGE_LOG(ERROR,"Fail to alloc block, ",
K(ret),
K(free_block_cnt_),
"total_count",
store_file_system_->get_total_macro_block_count());
} else {
K(total_block_cnt));
}
if (OB_SUCC(ret)) {
lib::ObMutexGuard guard(block_lock_); // lock block
bool is_alloc_succ = false;
for (int64_t i = 0; OB_SUCC(ret) && !is_alloc_succ && i < MAX_ALLOC_BLOCK_TRY_COUNT && free_block_cnt_ > 0; ++i) {
block_idx = free_block_array_[free_block_pop_pos_];
@ -983,21 +1065,10 @@ int ObStoreFile::alloc_block(ObMacroBlockHandle& macro_handle)
}
}
}
if (OB_SUCC(ret)) {
if (is_alloc_succ) {
} else if (OB_UNLIKELY(free_block_cnt_ <= 0)) {
ret = OB_CS_OUTOF_DISK_SPACE;
STORAGE_LOG(ERROR,
"Fail to alloc block, ",
K(ret),
K(free_block_cnt_),
"total_count",
store_file_system_->get_total_macro_block_count());
} else {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "Fail to alloc block", K(ret));
}
if (is_alloc_succ) {
} else {
ret = OB_ERR_UNEXPECTED;
STORAGE_LOG(WARN, "Fail to alloc block", K(ret));
}
}
return ret;
@ -1068,11 +1139,9 @@ int ObStoreFile::mark_macro_blocks()
} else {
// mark init
MEMSET(macro_block_bitmap_, 0, (store_file_system_->get_total_macro_block_count() / 64 + 1) * sizeof(uint64_t));
for (int64_t i = 0; i < ObStoreFileSystem::RESERVED_MACRO_BLOCK_INDEX && is_mark_sweep_enabled(); ++i) {
bitmap_set(i);
}
// mark data block
ObMacroBlockCommonHeader::MacroBlockType macro_type;
used_macro_cnt_[ObMacroBlockCommonHeader::SSTableData] = 0;
@ -1097,7 +1166,6 @@ int ObStoreFile::mark_macro_blocks()
STORAGE_LOG(ERROR, "Fail to iter data macro block ids, ", K(ret));
}
}
// mark meta block
if (OB_SUCC(ret)) {
lib::ObMutexGuard guard(meta_array_lock_);
@ -1109,6 +1177,126 @@ int ObStoreFile::mark_macro_blocks()
return ret;
}
// should lock before using to protect free_block_cnt_ opt
int ObStoreFile::extend_file_size_task()
{
lib::ObMutexGuard guard(block_lock_); // lock block info update opt
int ret = OB_SUCCESS;
if (OB_ISNULL(store_file_system_)) {
} else {
int64_t datafile_maxsize = GCONF.datafile_maxsize;
int64_t datafile_size = GCONF.datafile_size;
int64_t datafile_next = GCONF.datafile_next;
if (OB_UNLIKELY(datafile_maxsize <= 0) ||
OB_UNLIKELY(datafile_next <= 0) ||
OB_UNLIKELY(datafile_size <= 0)) {
LOG_DEBUG("Do not extend file size, datafile params not set", K(ret),
K(datafile_maxsize),
K(datafile_next),
K(datafile_size));
} else if (datafile_maxsize <= datafile_size) {
LOG_DEBUG("Do not extend file size, maxsize should bigger than datafile size",
K(ret),
K(datafile_maxsize),
K(datafile_size));
} else {
disable_mark_sweep(); // lock and wait mark_and_sweep block option done
if (OB_FAIL(wait_mark_sweep_finish())) {
LOG_WARN("fail to wait mark and sweep finish", K(ret));
} else {
bool is_extend_size = false;
int64_t total_block_cnt = store_file_system_->get_total_macro_block_count();
int64_t free_block_cnt_to_extend =
total_block_cnt - total_block_cnt * GCONF._datafile_usage_upper_bound_percentage / 100;
// here we can see auto extend disk premise:
// 1. free_block_cnt ratio is less than one percentage (default 10%)
// 2. free_block_cnt is less than one value (512 = 1G)
if (free_block_cnt_to_extend < free_block_cnt_ &&
(free_block_cnt_ > AUTO_EXTEND_LEAST_FREE_BLOCK_CNT)) {
LOG_DEBUG("Do not extend file, not reach extend trigger.",
K(free_block_cnt_to_extend),
K(free_block_cnt_),
K(total_block_cnt));
} else {
is_extend_size = true;
int64_t disk_in_use = total_block_cnt - free_block_cnt_;
LOG_INFO("Auto extend, start to extend disk.",
K(free_block_cnt_to_extend),
K(free_block_cnt_),
K(total_block_cnt),
K(disk_in_use));
}
if (is_extend_size) {
if (is_doing_disk_extend()) { // is_doing_disk_extend == true means there have not finish extend task yet,
// here DO NOT resize_file again!!!
LOG_INFO("Do extend file, there has doing extend job, only need to mark free block.",
K(free_block_cnt_),
"total blocks,",
store_file_system_->get_total_macro_block_count());
} else {
// calculate max extend size, max_extend_file maybe less than zero in the following situation:
// 1. alter datafile_size as A, alter datafile_maxsize as B, and A < B
// 2. auto extend to size to C ( A < C < B )
// 3. alter datafile_maxsize as D ( A < D < C )
int64_t cur_total_data_file_size = store_file_system_->get_total_data_size();
int64_t max_extend_file = datafile_maxsize - cur_total_data_file_size;
// calc actual_extend_size, following the rules:
// 1. if datafile_next less than 1G, actual_extend_size equal to min(1G, datafile_maxsize * 10%)
// 2. if datafile_next large than 1G, actual_extend_size equal to min(datafile_next, max_extend_file)
int64_t actual_extend_size;
if (datafile_next < DATAFILE_NEXT_MIN) {
int64_t min_extend_size = datafile_maxsize * 10 / 100;
actual_extend_size =
min_extend_size < DATAFILE_NEXT_MIN ? min_extend_size : DATAFILE_NEXT_MIN;
if (actual_extend_size > max_extend_file) { // take the smaller
actual_extend_size = max_extend_file;
}
} else {
actual_extend_size =
datafile_next < max_extend_file ? datafile_next : max_extend_file;
}
if (actual_extend_size <= 0) {
ret = OB_CS_OUTOF_DISK_SPACE;
LOG_DEBUG("No more disk space to extend, is full now", K(ret),
K(datafile_maxsize),
K(cur_total_data_file_size));
} else if (OB_FAIL(store_file_system_->resize_file(0, 0, actual_extend_size))) {
LOG_WARN("Extend file fail.",
K(actual_extend_size),
K(datafile_maxsize),
K(datafile_next));
} else if (OB_FAIL(refresh_block_meta())){
LOG_WARN("Extend file size fail, fresh block meta error", K(ret));
} else {
start_doing_disk_extend(); // set doing disk extend enable to skip auto extend check until mark_and_sweep done
LOG_INFO("Extend file success.",
K(actual_extend_size),
K(store_file_system_->get_total_data_size()));
}
}
}
}
enable_mark_sweep(); // restart gc task
}
}
return ret;
}
void ObStoreFile::ssblock_check_and_extend()
{
int ret = OB_SUCCESS;
if (OB_ISNULL(store_file_system_)) {
} else if (is_doing_disk_extend()){ // avoid doing double extend task
LOG_WARN("Extend file is doing now, skip this round.");
} else {
if (OB_FAIL(extend_file_size_task())) {
LOG_WARN("Fail to extend file size", K(ret));
} else {
LOG_DEBUG("Success to extend file size");
}
}
}
void ObStoreFile::mark_and_sweep()
{
int ret = OB_SUCCESS;
@ -1168,11 +1356,19 @@ void ObStoreFile::mark_and_sweep()
}
}
}
// time
end_time = ObTimeUtility::current_time();
sweep_cost_time_ = end_time - begin_time;
// print buf
hold_macro_cnt_ = hold_cnt;
print_buffer_[print_pos] = '\0';
// finish doing entire mark and sweep process
// is_mark_sweep_enabled==true means mark and sweep process is not being broken yet
if (is_mark_sweep_enabled()) {
finish_doing_disk_extend();
STORAGE_LOG(INFO, "finish doing mark_and_sweep without suspend ");
}
STORAGE_LOG(INFO, "mark_and_sweep free blocks.", K(print_buffer_), K(free_cnt), K(hold_cnt));
set_mark_sweep_done();
}
@ -1278,97 +1474,121 @@ void ObStoreFile::set_mark_sweep_done()
cond_.broadcast();
}
int ObStoreFile::resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage)
// should lock and then use
int ObStoreFile::refresh_block_meta()
{
int ret = OB_SUCCESS;
disable_mark_sweep();
if (OB_ISNULL(store_file_system_)) {
// do nothing
} else if (OB_FAIL(wait_mark_sweep_finish())) {
LOG_WARN("fail to wait mark and sweep finish", K(ret));
LOG_DEBUG("Do resize file fail, store_file_system_ is null pointer");
} else {
lib::ObMutexGuard guard(block_lock_);
if (OB_FAIL(store_file_system_->resize_file(new_data_file_size, new_data_file_disk_percentage))) {
LOG_WARN("fail to resize file", K(ret));
} else {
const int64_t new_total_file_size =
lower_align(store_file_system_->get_total_data_size(), store_file_system_->get_macro_block_size());
const int64_t new_macro_block_cnt = new_total_file_size / store_file_system_->get_macro_block_size();
const int64_t origin_macro_block_cnt = store_file_system_->get_total_macro_block_count();
if (new_macro_block_cnt > origin_macro_block_cnt) {
uint32_t* new_free_block_array = nullptr;
uint64_t* new_macro_block_bitmap = nullptr;
ObServerSuperBlock super_block = store_file_system_->get_server_super_block();
super_block.content_.total_file_size_ = new_total_file_size;
super_block.content_.total_macro_block_count_ = new_macro_block_cnt;
super_block.content_.modify_timestamp_ = ObTimeUtility::current_time();
ObStorageFile* file = OB_FILE_SYSTEM.get_server_root_handle().get_storage_file();
if (OB_ISNULL(file)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("error unexpected, file must not be null", K(ret));
} else if (OB_FAIL(alloc_memory(
new_macro_block_cnt, new_free_block_array, new_macro_block_bitmap, macro_block_info_))) {
LOG_WARN("fail to alloc memory", K(ret), K(new_macro_block_cnt));
} else if (OB_FAIL(file->write_super_block(super_block))) {
LOG_WARN("fail to write super block", K(ret));
const int64_t new_total_file_size =
lower_align(store_file_system_->get_total_data_size(), store_file_system_->get_macro_block_size());
const int64_t new_macro_block_cnt = new_total_file_size / store_file_system_->get_macro_block_size();
const int64_t origin_macro_block_cnt = store_file_system_->get_total_macro_block_count();
if (new_macro_block_cnt > origin_macro_block_cnt) {
uint32_t* new_free_block_array = nullptr;
uint64_t* new_macro_block_bitmap = nullptr;
ObServerSuperBlock super_block = store_file_system_->get_server_super_block();
super_block.content_.total_file_size_ = new_total_file_size;
super_block.content_.total_macro_block_count_ = new_macro_block_cnt;
super_block.content_.modify_timestamp_ = ObTimeUtility::current_time();
ObStorageFile* file = OB_FILE_SYSTEM.get_server_root_handle().get_storage_file();
if (OB_ISNULL(file)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("error unexpected, file must not be null", K(ret));
} else if (OB_FAIL(alloc_memory(
new_macro_block_cnt, new_free_block_array, new_macro_block_bitmap, macro_block_info_))) {
LOG_WARN("fail to alloc memory", K(ret), K(new_macro_block_cnt));
} else if (OB_FAIL(file->write_super_block(super_block))) {
LOG_WARN("fail to write super block", K(ret));
} else {
// copy free block info to new_free_block_array
if (free_block_pop_pos_ > free_block_push_pos_) {
MEMCPY(new_free_block_array,
free_block_array_ + free_block_pop_pos_,
(origin_macro_block_cnt - free_block_pop_pos_) * sizeof(uint32_t));
MEMCPY(new_free_block_array + origin_macro_block_cnt - free_block_pop_pos_,
free_block_array_,
free_block_push_pos_ * sizeof(uint32_t));
} else if (free_block_pop_pos_ < free_block_push_pos_) {
MEMCPY(new_free_block_array,
free_block_array_ + free_block_pop_pos_,
(free_block_push_pos_ - free_block_pop_pos_) * sizeof(uint32_t));
} else {
// copy free block info to new_free_block_array
if (free_block_pop_pos_ > free_block_push_pos_) {
MEMCPY(new_free_block_array,
free_block_array_ + free_block_pop_pos_,
(origin_macro_block_cnt - free_block_pop_pos_) * sizeof(uint32_t));
MEMCPY(new_free_block_array + origin_macro_block_cnt - free_block_pop_pos_,
free_block_array_,
free_block_push_pos_ * sizeof(uint32_t));
} else if (free_block_pop_pos_ < free_block_push_pos_) {
MEMCPY(new_free_block_array,
free_block_array_ + free_block_pop_pos_,
(free_block_push_pos_ - free_block_pop_pos_) * sizeof(uint32_t));
} else {
MEMCPY(new_free_block_array, free_block_array_, free_block_cnt_ * sizeof(uint32_t));
}
free_block_pop_pos_ = 0;
free_block_push_pos_ = free_block_cnt_;
MEMCPY(new_macro_block_bitmap,
macro_block_bitmap_,
get_macro_bitmap_array_cnt(origin_macro_block_cnt) * sizeof(uint64_t));
allocator_.free(free_block_array_);
allocator_.free(macro_block_bitmap_);
free_block_array_ = new_free_block_array;
macro_block_bitmap_ = new_macro_block_bitmap;
LOG_INFO("succeed to resize file", K(new_data_file_size));
}
if (OB_FAIL(ret)) {
allocator_.free(new_free_block_array);
allocator_.free(new_macro_block_bitmap);
MEMCPY(new_free_block_array, free_block_array_, free_block_cnt_ * sizeof(uint32_t));
}
free_block_pop_pos_ = 0;
free_block_push_pos_ = free_block_cnt_;
MEMCPY(new_macro_block_bitmap,
macro_block_bitmap_,
get_macro_bitmap_array_cnt(origin_macro_block_cnt) * sizeof(uint64_t));
allocator_.free(free_block_array_);
allocator_.free(macro_block_bitmap_);
free_block_array_ = new_free_block_array;
macro_block_bitmap_ = new_macro_block_bitmap;
}
if (OB_FAIL(ret)) {
allocator_.free(new_free_block_array);
allocator_.free(new_macro_block_bitmap);
}
}
}
enable_mark_sweep();
return ret;
}
int ObStoreFile::validate_datafile_size(const char* config_data_file_size)
int ObStoreFile::resize_file(
const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(store_file_system_)) {
LOG_DEBUG("Do resize file fail, store_file_system_ is null pointer");
} else {
lib::ObMutexGuard guard(block_lock_);
disable_mark_sweep();
if (OB_FAIL(wait_mark_sweep_finish())) {
LOG_WARN("fail to wait mark and sweep finish", K(ret));
} else {
if (OB_FAIL(store_file_system_->resize_file(new_data_file_size, new_data_file_disk_percentage))) {
LOG_WARN("fail to resize file", K(ret));
} else if (OB_FAIL(refresh_block_meta())) {
LOG_WARN("fail to refresh block meta", K(ret));
} else {
start_doing_disk_extend();
LOG_INFO("succeed to resize file");
}
}
enable_mark_sweep();
}
return ret;
}
int ObStoreFile::validate_datafile_param(const ObString& name, const char* config_data_file_param)
{
int ret = OB_SUCCESS;
bool valid = false;
if (OB_ISNULL(store_file_system_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("The OB store file instance is not exist", K(ret));
} else {
}
if (OB_SUCC(ret)) {
bool valid = false;
int64_t new_data_file_size = ObConfigCapacityParser::get(config_data_file_size, valid);
if(!valid){
ret = OB_ERR_PARSE_SQL;
LOG_USER_ERROR(OB_INVALID_CONFIG, "datafile_size can not be parsed");
} else {
const int64_t original_file_size = store_file_system_->get_total_data_size();
if (new_data_file_size < original_file_size) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("datafile_size is smaller than the original configuration", K(ret));
LOG_USER_ERROR(OB_INVALID_CONFIG, "datafile_size can not be smaller than the original configuration");
int64_t new_data_file_param;
if (0 == name.case_compare("datafile_size")) {
new_data_file_param = ObConfigCapacityParser::get(config_data_file_param, valid);
if(!valid){
ret = OB_ERR_PARSE_SQL;
LOG_USER_ERROR(OB_INVALID_CONFIG, "datafile size can not be parsed");
} else {
const int64_t original_file_size = store_file_system_->get_total_data_size();
if (new_data_file_param < original_file_size) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("datafile_size is smaller than the original configuration",
K(ret), K(new_data_file_param), K(original_file_size));
LOG_USER_ERROR(OB_INVALID_CONFIG,
"datafile_size can not be smaller than the original configuration");
}
}
}
}
}
return ret;
}

View File

@ -209,6 +209,13 @@ private:
common::ObIOHandle io_handle_;
};
class ObStoreFileAutoExtendTask : public common::ObTimerTask {
public:
ObStoreFileAutoExtendTask();
virtual ~ObStoreFileAutoExtendTask();
virtual void runTimerTask();
};
class ObStoreFileGCTask : public common::ObTimerTask {
public:
ObStoreFileGCTask();
@ -348,61 +355,62 @@ public:
int get_macro_block_info(const int64_t block_index, ObMacroBlockInfo& macro_block_info);
int report_bad_block(const MacroBlockId& macro_block_id, const int64_t error_type, const char* error_msg);
int get_bad_block_infos(common::ObArray<ObBadBlockInfo>& bad_block_infos);
OB_INLINE const char* get_store_file_path()
{
return sstable_dir_;
}
OB_INLINE int64_t get_free_macro_block_count() const
{
return free_block_cnt_;
}
OB_INLINE const char* get_store_file_path() { return sstable_dir_; }
OB_INLINE int64_t get_free_macro_block_count() const { return free_block_cnt_; }
int add_disk(
const common::ObString& diskgroup_name, const common::ObString& disk_path, const common::ObString& alias_name);
int drop_disk(const common::ObString& diskgroup_name, const common::ObString& alias_name);
int is_free_block(const int64_t block_index, bool& is_free);
int resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage);
int validate_datafile_size(const char* config_data_file_size);
int validate_datafile_param(const ObString& name, const char* config_data_file_param);
int refresh_block_meta();
private:
friend class ObStoreFileGCTask;
friend class ObFileSystemInspectBadBlockTask;
friend class ObAllMacroIdIterator;
friend class ObStoreFileAutoExtendTask;
ObStoreFile();
virtual ~ObStoreFile();
int alloc_block(ObMacroBlockHandle& macro_handle);
int alloc_block(ObMacroBlockHandle& macro_handle);
int mark_macro_blocks();
int extend_file_size_task();
int auto_extend_file_size();
void free_block(const uint32_t block_idx, bool& is_freed);
int mark_macro_blocks();
void mark_and_sweep();
void ssblock_check_and_extend();
OB_INLINE bool is_valid(const MacroBlockId macro_id);
OB_INLINE void bitmap_set(const int64_t block_idx);
OB_INLINE bool bitmap_test(const int64_t block_idx);
bool is_bad_block(const MacroBlockId& macro_block_id);
int read_checkpoint_and_replay_log(bool& is_replay_old);
void disable_mark_sweep()
{
ATOMIC_SET(&is_mark_sweep_enabled_, false);
}
void enable_mark_sweep()
{
ATOMIC_SET(&is_mark_sweep_enabled_, true);
}
bool is_mark_sweep_enabled()
{
return ATOMIC_LOAD(&is_mark_sweep_enabled_);
}
void disable_mark_sweep() { ATOMIC_SET(&is_mark_sweep_enabled_, false);}
void enable_mark_sweep() { ATOMIC_SET(&is_mark_sweep_enabled_, true);}
bool is_mark_sweep_enabled() { return ATOMIC_LOAD(&is_mark_sweep_enabled_);}
void finish_doing_disk_extend() { ATOMIC_SET(&is_doing_disk_extend_, false);}
void start_doing_disk_extend() { ATOMIC_SET(&is_doing_disk_extend_, true);}
bool is_doing_disk_extend() { return ATOMIC_LOAD(&is_doing_disk_extend_);}
int64_t get_macro_bitmap_array_cnt(const int64_t macro_block_cnt) { return macro_block_cnt / 64 + 1; }
int wait_mark_sweep_finish();
void set_mark_sweep_doing();
void set_mark_sweep_done();
int alloc_memory(const int64_t total_macro_block_cnt, uint32_t*& free_block_array, uint64_t*& macro_block_bitmap,
ObSegmentArray<ObMacroBlockInfo>& macro_block_info_array);
int64_t get_macro_bitmap_array_cnt(const int64_t macro_block_cnt)
{
return macro_block_cnt / 64 + 1;
}
private:
static const int64_t RECYCLE_DELAY_US = 5 * 1000 * 1000; // 5s
static const int64_t INSPECT_DELAY_US = 1 * 1000 * 1000; // 1s
static const int64_t RECYCLE_DELAY_US = 5 * 1000 * 1000; // 5s
static const int64_t INSPECT_DELAY_US = 1 * 1000 * 1000; // 1s
static const int64_t AUTOEXTEND_DELAY_US = 1 * 1000 * 1000; // 1s
static const int64_t DATAFILE_NEXT_MIN = 1 * 1024 * 1024 * 1024; // 1G
static const int64_t FREE_BLOCK_LEFT_PERCENTAGE = 5;
static const int64_t AUTO_EXTEND_LEAST_FREE_BLOCK_CNT = 512; // 1G
static const int64_t MARK_BLOCK_INFO_TIMEOUT = RECYCLE_DELAY_US;
bool is_inited_;
bool is_opened_;
char sstable_dir_[common::OB_MAX_FILE_NAME_LENGTH];
@ -419,6 +427,7 @@ private:
int64_t cur_meta_array_pos_;
common::ObArray<MacroBlockId> meta_block_ids_[2];
ObStoreFileGCTask gc_task_;
ObStoreFileAutoExtendTask ssblock_auto_extend_task_;
ObFileSystemInspectBadBlockTask inspect_bad_block_task_;
char* print_buffer_;
int64_t print_buffer_size_;
@ -431,9 +440,11 @@ private:
ObStoreFileSystem* store_file_system_;
bool is_mark_sweep_enabled_;
bool is_doing_mark_sweep_;
bool is_doing_disk_extend_;
ObThreadCond cond_; // for mark sweep
bool is_fs_support_punch_hole_;
int block_file_fd_;
lib::ObMutex alloc_lock_;
};
OB_INLINE bool ObStoreFile::is_valid(const MacroBlockId macro_id)

View File

@ -736,6 +736,11 @@ int64_t ObStoreFileSystem::get_total_macro_block_count() const
return super_block_.get_total_macro_block_count();
}
int64_t ObStoreFileSystem::get_total_macro_block_max_count() const
{
return -1;
}
int64_t ObStoreFileSystem::get_free_macro_block_count() const
{
return -1;
@ -777,10 +782,11 @@ int ObStoreFileSystem::get_bad_block_infos(common::ObArray<ObBadBlockInfo>& bad_
return OB_SUCCESS;
}
int ObStoreFileSystem::resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage)
int ObStoreFileSystem::resize_file(
const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage, const int64_t extend_size)
{
int ret = OB_NOT_SUPPORTED;
UNUSEDx(new_data_file_size, new_data_file_disk_percentage);
UNUSEDx(new_data_file_size, new_data_file_disk_percentage, extend_size);
LOG_WARN("resize file is not supported in current file system", K(ret));
return ret;
}

View File

@ -399,7 +399,9 @@ public:
{
return super_block_;
}
virtual int resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage);
virtual int resize_file(const int64_t new_data_file_size, const int64_t new_data_file_disk_percentage, const int64_t extend_size = 0);
virtual int64_t get_total_macro_block_max_count() const;
VIRTUAL_TO_STRING_KV("ObStoreFileSystem", "empty");