Optimize del_dir function using batch_del_files interface

This commit is contained in:
obdev 2024-09-20 06:33:42 +00:00 committed by ob-robot
parent a7c5dffdb4
commit d31ecabcce
2 changed files with 92 additions and 17 deletions

View File

@ -1727,16 +1727,16 @@ int ObStorageS3Util::batch_del_files_(
for (int64_t i = 0; OB_SUCC(ret) && i < deleted_object_list.size(); i++) {
object_name = deleted_object_list[i].GetKey().c_str();
object_name_len = deleted_object_list[i].GetKey().size();
if (OB_ISNULL(object_name)) {
if (OB_ISNULL(object_name) || OB_UNLIKELY(object_name_len <= 0)) {
ret = OB_ERR_UNEXPECTED;
OB_LOG(WARN, "returned object name is null",
K(ret), K(s3_base.s3_account_), K(i), K(object_name));
K(ret), K(s3_base.s3_account_), K(i), K(object_name), K(object_name_len));
}
// S3 returns the successfully deleted object in the structure of the basic_string.
// We use the size of string to construct ObString.
else if (OB_FAIL(files_to_delete.erase_refactored(ObString(object_name_len, object_name)))) {
OB_LOG(WARN, "fail to erase succeed deleted object",
K(ret), K(s3_base.s3_account_), K(i), K(object_name));
OB_LOG(WARN, "fail to erase succeed deleted object", K(ret),
K(s3_base.s3_account_), K(i), K(object_name), K(object_name_len));
} else {
OB_LOG(DEBUG, "succeed deleting object", K(object_name));
}

View File

@ -763,24 +763,43 @@ int ObBackupIoAdapter::get_file_size(ObIODevice *device_handle, const ObIOFd &fd
class ObDelFilesOp : public ObBaseDirEntryOperator
{
public:
ObDelFilesOp() : is_inited_(false), dir_path_len_(0), storage_info_(nullptr)
ObDelFilesOp()
: is_inited_(false), dir_path_len_(0), storage_info_(nullptr),
allocator_("ObDelFilesOp"), files_to_delete_()
{
MEMSET(dir_path_, 0, sizeof(dir_path_));
}
virtual ~ObDelFilesOp() {}
virtual ~ObDelFilesOp()
{
if (OB_UNLIKELY(!files_to_delete_.empty())) {
OB_LOG_RET(WARN, OB_ERR_UNEXPECTED,
"There are remaining files to delete, "
"it seems the clean_batch_files function may have been overlooked",
K(dir_path_), K(files_to_delete_), K(files_to_delete_.count()));
}
allocator_.reset();
files_to_delete_.reset();
}
int init(const common::ObString &uri, const share::ObBackupStorageInfo *storage_info);
virtual int func(const dirent *entry) override;
int clean_batch_files();
protected:
static constexpr int64_t BATCH_DELETE_SIZE = 1000;
bool is_inited_;
char dir_path_[OB_MAX_URI_LENGTH];
int64_t dir_path_len_;
const share::ObBackupStorageInfo *storage_info_;
ObArenaAllocator allocator_;
ObArray<ObString> files_to_delete_;
};
int ObDelFilesOp::init(const common::ObString &uri, const share::ObBackupStorageInfo *storage_info)
{
int ret = OB_SUCCESS;
dir_path_len_ = 0;
if (OB_UNLIKELY(is_inited_)) {
ret = OB_INIT_TWICE;
OB_LOG(WARN, "ObDelFilesOp has been inited", KR(ret));
@ -788,16 +807,24 @@ int ObDelFilesOp::init(const common::ObString &uri, const share::ObBackupStorage
OB_UNLIKELY(uri.empty() || uri.length() >= sizeof(dir_path_) || !storage_info->is_valid())) {
ret = OB_INVALID_ARGUMENT;
OB_LOG(WARN, "invalid argument", KR(ret), K(uri), KPC(storage_info));
} else {
const char *suffix = is_end_with_slash(uri.ptr()) ? "" : "/";
if (OB_FAIL(databuff_printf(dir_path_, sizeof(dir_path_), dir_path_len_,
"%s%s", uri.ptr(), suffix))) {
OB_LOG(WARN, "fail to fill dir_path", KR(ret), K(uri), K(suffix));
} else if (OB_FAIL(databuff_printf(dir_path_, sizeof(dir_path_), dir_path_len_,
"%.*s", uri.length(), uri.ptr()))) {
OB_LOG(WARN, "fail to fill dir_path", KR(ret), K(uri));
} else if (dir_path_[dir_path_len_] != '/') {
if (OB_UNLIKELY(dir_path_len_ >= sizeof(dir_path_) - 1)) {
ret = OB_INVALID_ARGUMENT;
OB_LOG(WARN, "uri too long", KR(ret), K(uri), K(dir_path_len_), K(sizeof(dir_path_)));
} else {
storage_info_ = storage_info;
is_inited_ = true;
dir_path_[dir_path_len_] = '/';
dir_path_len_++;
dir_path_[dir_path_len_] = '\0';
}
}
if (OB_SUCC(ret)) {
storage_info_ = storage_info;
is_inited_ = true;
}
return ret;
}
@ -805,6 +832,7 @@ int ObDelFilesOp::func(const dirent *entry)
{
int ret = OB_SUCCESS;
int64_t pos = dir_path_len_;
char *cur_uri = nullptr;
if (IS_NOT_INIT) {
ret = OB_NOT_INIT;
OB_LOG(WARN, "ObDelFilesOp is not inited", KR(ret));
@ -816,10 +844,55 @@ int ObDelFilesOp::func(const dirent *entry)
OB_LOG(WARN, "dt type is not a regular file!",
KR(ret), K(entry->d_type), K(entry->d_name));
} else if (OB_FAIL(databuff_printf(dir_path_, sizeof(dir_path_), pos, "%s", entry->d_name))) {
OB_LOG(WARN, "failed to construct obj name", KR(ret), K(entry->d_name));
} else if (OB_FAIL(ObBackupIoAdapter::del_file(dir_path_, storage_info_))) {
OB_LOG(WARN, "failed to del file",
KR(ret), K(entry->d_name), K_(dir_path), KPC_(storage_info));
OB_LOG(WARN, "failed to construct obj name", KR(ret), K(entry->d_name), K(pos));
} else if (OB_FAIL(ob_dup_cstring(allocator_, dir_path_, cur_uri))) {
OB_LOG(WARN, "fail to copy cur uri", KR(ret), K(dir_path_), K(entry->d_name), K(pos));
} else if (OB_FAIL(files_to_delete_.push_back(cur_uri))) {
OB_LOG(WARN, "fail to store cur uri", KR(ret),
K(dir_path_), K(cur_uri), K(entry->d_name), K(pos));
} else if (files_to_delete_.count() >= BATCH_DELETE_SIZE) {
if (OB_FAIL(clean_batch_files())) {
OB_LOG(WARN, "failed to batch del files",
KR(ret), K(entry->d_name), K_(dir_path), KPC_(storage_info),
K(files_to_delete_.count()), K(files_to_delete_));
}
}
return ret;
}
int ObDelFilesOp::clean_batch_files()
{
int ret = OB_SUCCESS;
int tmp_ret = OB_SUCCESS;
int64_t retry_times = 3;
ObArray<int64_t> failed_files_idx;
if (files_to_delete_.count() > 0) {
// Call batch_del_files to delete files.
// Only when this interface returns OB_SUCCESS and failed_files_idx is empty
// does it indicate that all objects have been successfully deleted.
// If deletion fails, retry up to retry_times times.
do {
failed_files_idx.reset();
if (OB_TMP_FAIL(ObBackupIoAdapter::batch_del_files(
storage_info_, files_to_delete_, failed_files_idx))
|| !failed_files_idx.empty()) {
OB_LOG(WARN, "ObDelFilesOp fail to batch_del_files",
KR(tmp_ret), K(retry_times), KPC_(storage_info), K(files_to_delete_.count()),
K(files_to_delete_), K(failed_files_idx.count()));
}
retry_times--;
} while (OB_SUCC(ret) && retry_times > 0
&& (OB_SUCCESS != tmp_ret || !failed_files_idx.empty()));
if (OB_SUCCESS == tmp_ret && !failed_files_idx.empty()) {
ret = OB_UTL_FILE_DELETE_FAILED;
}
ret = COVER_SUCC(tmp_ret);
}
if (OB_SUCC(ret)) {
files_to_delete_.reset();
allocator_.reuse();
}
return ret;
}
@ -888,6 +961,8 @@ int ObBackupIoAdapter::del_dir(const common::ObString &uri,
OB_LOG(WARN, "fail to init ObDelFilesOp", KR(ret), K(uri), KPC(storage_info));
} else if (OB_FAIL(list_files(uri, storage_info, del_files_op))) {
OB_LOG(WARN, "fail to delete files", KR(ret), K(uri), KPC(storage_info));
} else if (OB_FAIL(del_files_op.clean_batch_files())) {
OB_LOG(WARN, "fail to delete remained files", KR(ret), K(uri), KPC(storage_info));
} else if (OB_FAIL(device_handle->rmdir(uri.ptr()))) {
OB_LOG(WARN, "fail to remove dir!", KR(ret), K(uri), KPC(storage_info));
}