support merge free trunk spaces

pull/484/head
YuQing 2019-12-21 21:00:09 +08:00
parent 8d2a04e435
commit 513894c5a2
9 changed files with 299 additions and 34 deletions

View File

@ -1,5 +1,5 @@
Version 6.05 2019-12-20
Version 6.05 2019-12-21
* fdfs_trackerd and fdfs_storaged print the server version in usage.
you can execute fdfs_trackerd or fdfs_storaged without parameters
to show the server version
@ -10,6 +10,7 @@ Version 6.05 2019-12-20
* support backup binlog file when truncate trunk binlog,
the config item in tracker.conf: trunk_binlog_max_backups
* support alignment size for trunk space allocation
* support merge free trunk spaces
Version 6.04 2019-12-05
* storage_report_ip_changed ignore result EEXIST

View File

@ -161,6 +161,11 @@ slot_max_size = 1MB
# fragmentation, but the more space is wasted.
trunk_alloc_alignment_size = 512
# if merge contiguous free spaces of trunk file
# default value is false
# since V6.05
trunk_free_space_merge = true
# the trunk file size, should >= 4MB
# default value is 64MB
# since V3.00

View File

@ -142,6 +142,8 @@ int storage_get_params_from_tracker()
"trunk_init_check_occupying", &iniContext, false);
g_trunk_init_reload_from_binlog = iniGetBoolValue(NULL,
"trunk_init_reload_from_binlog", &iniContext, false);
g_trunk_free_space_merge = iniGetBoolValue(NULL,
"trunk_free_space_merge", &iniContext, false);
g_trunk_compress_binlog_min_interval = iniGetIntValue(NULL,
"trunk_compress_binlog_min_interval", &iniContext, 0);
g_trunk_compress_binlog_interval = iniGetIntValue(NULL,
@ -203,6 +205,7 @@ int storage_get_params_from_tracker()
"trunk_create_file_space_threshold=%d GB, "
"trunk_init_check_occupying=%d, "
"trunk_init_reload_from_binlog=%d, "
"trunk_free_space_merge=%d, "
"trunk_compress_binlog_min_interval=%d, "
"trunk_compress_binlog_interval=%d, "
"trunk_compress_binlog_time_base=%02d:%02d, "
@ -224,6 +227,7 @@ int storage_get_params_from_tracker()
(int)(g_trunk_create_file_space_threshold /
(FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour,

View File

@ -64,6 +64,7 @@ bool g_if_trunker_self = false;
bool g_trunk_create_file_advance = false;
bool g_trunk_init_check_occupying = false;
bool g_trunk_init_reload_from_binlog = false;
bool g_trunk_free_space_merge = false;
int g_trunk_binlog_compress_stage = STORAGE_TRUNK_COMPRESS_STAGE_NONE;
int64_t g_trunk_total_free_space = 0;
int64_t g_trunk_create_file_space_threshold = 0;
@ -349,54 +350,141 @@ static int64_t storage_trunk_get_binlog_size()
return stat_buf.st_size;
}
struct trunk_info_array {
FDFSTrunkFullInfo **trunks;
int count;
int alloc;
};
struct walk_callback_args {
int fd;
char buff[16 * 1024];
char temp_trunk_filename[MAX_PATH_SIZE];
char *pCurrent;
struct trunk_info_array trunk_array; //for space combine
};
static int tree_walk_callback(void *data, void *args)
static int trunk_alloc_trunk_array(
struct trunk_info_array *trunk_array)
{
int bytes;
FDFSTrunkFullInfo **trunks;
int alloc;
if (trunk_array->alloc == 0)
{
alloc = 64 * 1024;
}
else
{
alloc = trunk_array->alloc * 2;
}
bytes = sizeof(FDFSTrunkFullInfo *) * alloc;
trunks = (FDFSTrunkFullInfo **)malloc(bytes);
if (trunks == NULL)
{
logError("file: "__FILE__", line: %d, "
"malloc %d bytes fail", __LINE__, bytes);
return ENOMEM;
}
if (trunk_array->count > 0)
{
memcpy(trunks, trunk_array->trunks,
sizeof(FDFSTrunkFullInfo *) *
trunk_array->count);
}
if (trunk_array->trunks != NULL)
{
free(trunk_array->trunks);
}
trunk_array->trunks = trunks;
trunk_array->alloc = alloc;
return 0;
}
static int save_one_trunk(struct walk_callback_args *pCallbackArgs,
FDFSTrunkFullInfo *pTrunkInfo)
{
int len;
int result;
len = sprintf(pCallbackArgs->pCurrent,
"%d %c %d %d %d %d %d %d\n",
(int)g_current_time, TRUNK_OP_TYPE_ADD_SPACE,
pTrunkInfo->path.store_path_index,
pTrunkInfo->path.sub_path_high,
pTrunkInfo->path.sub_path_low,
pTrunkInfo->file.id,
pTrunkInfo->file.offset,
pTrunkInfo->file.size);
pCallbackArgs->pCurrent += len;
if (pCallbackArgs->pCurrent - pCallbackArgs->buff >
sizeof(pCallbackArgs->buff) - 128)
{
if (fc_safe_write(pCallbackArgs->fd, pCallbackArgs->buff,
pCallbackArgs->pCurrent - pCallbackArgs->buff)
!= pCallbackArgs->pCurrent - pCallbackArgs->buff)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s", __LINE__,
pCallbackArgs->temp_trunk_filename,
result, STRERROR(result));
return result;
}
pCallbackArgs->pCurrent = pCallbackArgs->buff;
}
return 0;
}
static int tree_walk_callback_to_file(void *data, void *args)
{
struct walk_callback_args *pCallbackArgs;
FDFSTrunkFullInfo *pTrunkInfo;
FDFSTrunkNode *pCurrent;
int len;
int result;
pCallbackArgs = (struct walk_callback_args *)args;
pCurrent = ((FDFSTrunkSlot *)data)->head;
while (pCurrent != NULL)
{
pTrunkInfo = &pCurrent->trunk;
len = sprintf(pCallbackArgs->pCurrent,
"%d %c %d %d %d %d %d %d\n",
(int)g_current_time, TRUNK_OP_TYPE_ADD_SPACE,
pTrunkInfo->path.store_path_index,
pTrunkInfo->path.sub_path_high,
pTrunkInfo->path.sub_path_low,
pTrunkInfo->file.id,
pTrunkInfo->file.offset,
pTrunkInfo->file.size);
pCallbackArgs->pCurrent += len;
if (pCallbackArgs->pCurrent - pCallbackArgs->buff >
sizeof(pCallbackArgs->buff) - 128)
{
if (fc_safe_write(pCallbackArgs->fd, pCallbackArgs->buff,
pCallbackArgs->pCurrent - pCallbackArgs->buff)
!= pCallbackArgs->pCurrent - pCallbackArgs->buff)
{
result = errno != 0 ? errno : EIO;
logError("file: "__FILE__", line: %d, "
"write to file %s fail, "
"errno: %d, error info: %s", __LINE__,
pCallbackArgs->temp_trunk_filename,
result, STRERROR(result));
return result;
}
if ((result=save_one_trunk(pCallbackArgs, &pCurrent->trunk)) != 0)
{
return result;
}
pCurrent = pCurrent->next;
}
pCallbackArgs->pCurrent = pCallbackArgs->buff;
}
return 0;
}
static int tree_walk_callback_to_list(void *data, void *args)
{
struct walk_callback_args *pCallbackArgs;
FDFSTrunkNode *pCurrent;
int result;
pCallbackArgs = (struct walk_callback_args *)args;
pCurrent = ((FDFSTrunkSlot *)data)->head;
while (pCurrent != NULL)
{
if (pCallbackArgs->trunk_array.count >= pCallbackArgs->trunk_array.alloc)
{
if ((result=trunk_alloc_trunk_array(
&pCallbackArgs->trunk_array)) != 0)
{
return result;
}
}
pCallbackArgs->trunk_array.trunks[pCallbackArgs->trunk_array.
count++] = &pCurrent->trunk;
pCurrent = pCurrent->next;
}
@ -404,6 +492,145 @@ static int tree_walk_callback(void *data, void *args)
return 0;
}
static int trunk_compare_id_offset(const void *p1, const void *p2)
{
FDFSTrunkFullInfo *pTrunkInfo1;
FDFSTrunkFullInfo *pTrunkInfo2;
int result;
pTrunkInfo1 = *((FDFSTrunkFullInfo **)p1);
pTrunkInfo2 = *((FDFSTrunkFullInfo **)p2);
result = memcmp(&(pTrunkInfo1->path), &(pTrunkInfo2->path),
sizeof(FDFSTrunkPathInfo));
if (result != 0)
{
return result;
}
result = pTrunkInfo1->file.id - pTrunkInfo2->file.id;
if (result != 0)
{
return result;
}
return pTrunkInfo1->file.offset - pTrunkInfo2->file.offset;
}
static int trunk_compare_path_and_id(const FDFSTrunkFullInfo *pTrunkInfo1,
const FDFSTrunkFullInfo *pTrunkInfo2)
{
int result;
result = memcmp(&(pTrunkInfo1->path), &(pTrunkInfo2->path),
sizeof(FDFSTrunkPathInfo));
if (result != 0)
{
return result;
}
return pTrunkInfo1->file.id - pTrunkInfo2->file.id;
}
static int trunk_save_merged_spaces(struct walk_callback_args *pCallbackArgs)
{
FDFSTrunkFullInfo **ppTrunkInfo;
FDFSTrunkFullInfo **ppEnd;
FDFSTrunkFullInfo **previous;
FDFSTrunkFullInfo **ppMergeFirst;
FDFSTrunkFullInfo trunk_info;
FDFSTrunkFullInfo *pTrunkInfo;
int merge_count;
int merged_trunk_count;
int64_t total_size;
int64_t merged_size;
int result;
if (pCallbackArgs->trunk_array.count == 0)
{
return 0;
}
qsort(pCallbackArgs->trunk_array.trunks, pCallbackArgs->trunk_array.
count, sizeof(FDFSTrunkFullInfo *), trunk_compare_id_offset);
merge_count = 0;
merged_trunk_count = 0;
merged_size = 0;
ppEnd = pCallbackArgs->trunk_array.trunks +
pCallbackArgs->trunk_array.count;
ppTrunkInfo = pCallbackArgs->trunk_array.trunks;
ppMergeFirst = ppTrunkInfo;
total_size = (*ppTrunkInfo)->file.size;
while (++ppTrunkInfo < ppEnd)
{
total_size += (*ppTrunkInfo)->file.size;
previous = ppTrunkInfo - 1;
if (trunk_compare_path_and_id(*previous, *ppTrunkInfo) == 0 &&
(*previous)->file.offset + (*previous)->file.size ==
(*ppTrunkInfo)->file.offset)
{
continue;
}
if (ppTrunkInfo - ppMergeFirst == 1)
{
pTrunkInfo = *ppMergeFirst;
}
else
{
pTrunkInfo = &trunk_info;
memcpy(pTrunkInfo, *ppMergeFirst, sizeof(FDFSTrunkFullInfo));
pTrunkInfo->file.size = (*ppTrunkInfo)->file.offset -
(*ppMergeFirst)->file.offset;
merge_count++;
merged_size += pTrunkInfo->file.size;
merged_trunk_count += ppTrunkInfo - ppMergeFirst;
}
if ((result=save_one_trunk(pCallbackArgs, pTrunkInfo)) != 0)
{
return result;
}
ppMergeFirst = ppTrunkInfo;
ppTrunkInfo++;
}
if (ppEnd - ppMergeFirst == 1)
{
pTrunkInfo = *ppMergeFirst;
}
else
{
FDFSTrunkFullInfo **ppLast;
pTrunkInfo = &trunk_info;
ppLast = ppEnd - 1;
memcpy(pTrunkInfo, *ppMergeFirst, sizeof(FDFSTrunkFullInfo));
pTrunkInfo->file.size = (*ppLast)->file.offset -
(*ppMergeFirst)->file.offset + (*ppLast)->file.size;
merge_count++;
merged_size += pTrunkInfo->file.size;
merged_trunk_count += ppEnd - ppMergeFirst;
}
if ((result=save_one_trunk(pCallbackArgs, pTrunkInfo)) != 0)
{
return result;
}
logInfo("file: "__FILE__", line: %d, "
"trunk count: %d, total_size: %"PRId64", merge count: %d, "
"merged trunk count: %d, merged size: %"PRId64, __LINE__,
pCallbackArgs->trunk_array.count, total_size,
merge_count, merged_trunk_count, merged_size);
return 0;
}
static int do_save_trunk_data()
{
int64_t trunk_binlog_size;
@ -445,14 +672,32 @@ static int do_save_trunk_data()
pthread_mutex_lock(&trunk_mem_lock);
for (i=0; i<g_fdfs_store_paths.count; i++)
{
result = avl_tree_walk(tree_info_by_sizes + i,
tree_walk_callback, &callback_args);
if (g_trunk_free_space_merge)
{
result = avl_tree_walk(tree_info_by_sizes + i,
tree_walk_callback_to_list, &callback_args);
}
else
{
result = avl_tree_walk(tree_info_by_sizes + i,
tree_walk_callback_to_file, &callback_args);
}
if (result != 0)
{
break;
}
}
if (g_trunk_free_space_merge)
{
result = trunk_save_merged_spaces(&callback_args);
if (callback_args.trunk_array.trunks != NULL)
{
free(callback_args.trunk_array.trunks);
}
}
len = callback_args.pCurrent - callback_args.buff;
if (len > 0 && result == 0)
{

View File

@ -57,6 +57,7 @@ extern bool g_if_use_trunk_file; //if use trunk file
extern bool g_trunk_create_file_advance;
extern bool g_trunk_init_check_occupying;
extern bool g_trunk_init_reload_from_binlog;
extern bool g_trunk_free_space_merge;
extern int g_trunk_binlog_compress_stage;
extern bool g_if_trunker_self; //if am i trunk server
extern int64_t g_trunk_create_file_space_threshold;

View File

@ -598,6 +598,9 @@ int tracker_load_from_conf_file(const char *filename, \
g_trunk_init_reload_from_binlog = iniGetBoolValue(NULL,
"trunk_init_reload_from_binlog", &iniContext, false);
g_trunk_free_space_merge = iniGetBoolValue(NULL,
"trunk_free_space_merge", &iniContext, false);
if ((result=tracker_load_storage_id_info(
filename, &iniContext)) != 0)
{
@ -775,6 +778,7 @@ int tracker_load_from_conf_file(const char *filename, \
"trunk_create_file_space_threshold=%d GB, "
"trunk_init_check_occupying=%d, "
"trunk_init_reload_from_binlog=%d, "
"trunk_free_space_merge=%d, "
"trunk_compress_binlog_min_interval=%d, "
"trunk_compress_binlog_interval=%d, "
"trunk_compress_binlog_time_base=%02d:%02d, "
@ -818,6 +822,7 @@ int tracker_load_from_conf_file(const char *filename, \
(int)(g_trunk_create_file_space_threshold /
(FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour,

View File

@ -51,6 +51,7 @@ bool g_if_use_trunk_file = false; //if use trunk file
bool g_trunk_create_file_advance = false;
bool g_trunk_init_check_occupying = false;
bool g_trunk_init_reload_from_binlog = false;
bool g_trunk_free_space_merge = false;
int g_slot_min_size = 256; //slot min size, such as 256 bytes
int g_slot_max_size = 16 * 1024 * 1024; //slot max size, such as 16MB
int g_trunk_file_size = 64 * 1024 * 1024; //the trunk file size, such as 64MB

View File

@ -75,6 +75,7 @@ extern bool g_if_use_trunk_file; //if use trunk file
extern bool g_trunk_create_file_advance;
extern bool g_trunk_init_check_occupying;
extern bool g_trunk_init_reload_from_binlog;
extern bool g_trunk_free_space_merge;
extern int g_slot_min_size; //slot min size, such as 256 bytes
extern int g_slot_max_size; //slot max size, such as 16MB
extern int g_trunk_file_size; //the trunk file size, such as 64MB

View File

@ -695,6 +695,7 @@ static int tracker_deal_parameter_req(struct fast_task_info *pTask)
"trunk_create_file_space_threshold=%"PRId64"\n"
"trunk_init_check_occupying=%d\n"
"trunk_init_reload_from_binlog=%d\n"
"trunk_free_space_merge=%d\n"
"trunk_compress_binlog_min_interval=%d\n"
"trunk_compress_binlog_interval=%d\n"
"trunk_compress_binlog_time_base=%02d:%02d\n"
@ -716,6 +717,7 @@ static int tracker_deal_parameter_req(struct fast_task_info *pTask)
g_trunk_create_file_space_threshold,
g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour,