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

View File

@ -161,6 +161,11 @@ slot_max_size = 1MB
# fragmentation, but the more space is wasted. # fragmentation, but the more space is wasted.
trunk_alloc_alignment_size = 512 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 # the trunk file size, should >= 4MB
# default value is 64MB # default value is 64MB
# since V3.00 # since V3.00

View File

@ -142,6 +142,8 @@ int storage_get_params_from_tracker()
"trunk_init_check_occupying", &iniContext, false); "trunk_init_check_occupying", &iniContext, false);
g_trunk_init_reload_from_binlog = iniGetBoolValue(NULL, g_trunk_init_reload_from_binlog = iniGetBoolValue(NULL,
"trunk_init_reload_from_binlog", &iniContext, false); "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, g_trunk_compress_binlog_min_interval = iniGetIntValue(NULL,
"trunk_compress_binlog_min_interval", &iniContext, 0); "trunk_compress_binlog_min_interval", &iniContext, 0);
g_trunk_compress_binlog_interval = iniGetIntValue(NULL, 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_create_file_space_threshold=%d GB, "
"trunk_init_check_occupying=%d, " "trunk_init_check_occupying=%d, "
"trunk_init_reload_from_binlog=%d, " "trunk_init_reload_from_binlog=%d, "
"trunk_free_space_merge=%d, "
"trunk_compress_binlog_min_interval=%d, " "trunk_compress_binlog_min_interval=%d, "
"trunk_compress_binlog_interval=%d, " "trunk_compress_binlog_interval=%d, "
"trunk_compress_binlog_time_base=%02d:%02d, " "trunk_compress_binlog_time_base=%02d:%02d, "
@ -224,6 +227,7 @@ int storage_get_params_from_tracker()
(int)(g_trunk_create_file_space_threshold / (int)(g_trunk_create_file_space_threshold /
(FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying, (FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog, g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval, g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval, g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour, 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_create_file_advance = false;
bool g_trunk_init_check_occupying = false; bool g_trunk_init_check_occupying = false;
bool g_trunk_init_reload_from_binlog = 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; int g_trunk_binlog_compress_stage = STORAGE_TRUNK_COMPRESS_STAGE_NONE;
int64_t g_trunk_total_free_space = 0; int64_t g_trunk_total_free_space = 0;
int64_t g_trunk_create_file_space_threshold = 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; return stat_buf.st_size;
} }
struct trunk_info_array {
FDFSTrunkFullInfo **trunks;
int count;
int alloc;
};
struct walk_callback_args { struct walk_callback_args {
int fd; int fd;
char buff[16 * 1024]; char buff[16 * 1024];
char temp_trunk_filename[MAX_PATH_SIZE]; char temp_trunk_filename[MAX_PATH_SIZE];
char *pCurrent; 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; struct walk_callback_args *pCallbackArgs;
FDFSTrunkFullInfo *pTrunkInfo;
FDFSTrunkNode *pCurrent; FDFSTrunkNode *pCurrent;
int len;
int result; int result;
pCallbackArgs = (struct walk_callback_args *)args; pCallbackArgs = (struct walk_callback_args *)args;
pCurrent = ((FDFSTrunkSlot *)data)->head; pCurrent = ((FDFSTrunkSlot *)data)->head;
while (pCurrent != NULL) while (pCurrent != NULL)
{ {
pTrunkInfo = &pCurrent->trunk; if ((result=save_one_trunk(pCallbackArgs, &pCurrent->trunk)) != 0)
len = sprintf(pCallbackArgs->pCurrent, {
"%d %c %d %d %d %d %d %d\n", return result;
(int)g_current_time, TRUNK_OP_TYPE_ADD_SPACE, }
pTrunkInfo->path.store_path_index, pCurrent = pCurrent->next;
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_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; pCurrent = pCurrent->next;
} }
@ -404,6 +492,145 @@ static int tree_walk_callback(void *data, void *args)
return 0; 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() static int do_save_trunk_data()
{ {
int64_t trunk_binlog_size; int64_t trunk_binlog_size;
@ -445,14 +672,32 @@ static int do_save_trunk_data()
pthread_mutex_lock(&trunk_mem_lock); pthread_mutex_lock(&trunk_mem_lock);
for (i=0; i<g_fdfs_store_paths.count; i++) for (i=0; i<g_fdfs_store_paths.count; i++)
{ {
result = avl_tree_walk(tree_info_by_sizes + i, if (g_trunk_free_space_merge)
tree_walk_callback, &callback_args); {
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) if (result != 0)
{ {
break; 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; len = callback_args.pCurrent - callback_args.buff;
if (len > 0 && result == 0) 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_create_file_advance;
extern bool g_trunk_init_check_occupying; extern bool g_trunk_init_check_occupying;
extern bool g_trunk_init_reload_from_binlog; extern bool g_trunk_init_reload_from_binlog;
extern bool g_trunk_free_space_merge;
extern int g_trunk_binlog_compress_stage; extern int g_trunk_binlog_compress_stage;
extern bool g_if_trunker_self; //if am i trunk server extern bool g_if_trunker_self; //if am i trunk server
extern int64_t g_trunk_create_file_space_threshold; 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, g_trunk_init_reload_from_binlog = iniGetBoolValue(NULL,
"trunk_init_reload_from_binlog", &iniContext, false); "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( if ((result=tracker_load_storage_id_info(
filename, &iniContext)) != 0) filename, &iniContext)) != 0)
{ {
@ -775,6 +778,7 @@ int tracker_load_from_conf_file(const char *filename, \
"trunk_create_file_space_threshold=%d GB, " "trunk_create_file_space_threshold=%d GB, "
"trunk_init_check_occupying=%d, " "trunk_init_check_occupying=%d, "
"trunk_init_reload_from_binlog=%d, " "trunk_init_reload_from_binlog=%d, "
"trunk_free_space_merge=%d, "
"trunk_compress_binlog_min_interval=%d, " "trunk_compress_binlog_min_interval=%d, "
"trunk_compress_binlog_interval=%d, " "trunk_compress_binlog_interval=%d, "
"trunk_compress_binlog_time_base=%02d:%02d, " "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 / (int)(g_trunk_create_file_space_threshold /
(FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying, (FDFS_ONE_MB * 1024)), g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog, g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval, g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval, g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour, 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_create_file_advance = false;
bool g_trunk_init_check_occupying = false; bool g_trunk_init_check_occupying = false;
bool g_trunk_init_reload_from_binlog = 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_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_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 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_create_file_advance;
extern bool g_trunk_init_check_occupying; extern bool g_trunk_init_check_occupying;
extern bool g_trunk_init_reload_from_binlog; 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_min_size; //slot min size, such as 256 bytes
extern int g_slot_max_size; //slot max size, such as 16MB 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 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_create_file_space_threshold=%"PRId64"\n"
"trunk_init_check_occupying=%d\n" "trunk_init_check_occupying=%d\n"
"trunk_init_reload_from_binlog=%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_min_interval=%d\n"
"trunk_compress_binlog_interval=%d\n" "trunk_compress_binlog_interval=%d\n"
"trunk_compress_binlog_time_base=%02d:%02d\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_create_file_space_threshold,
g_trunk_init_check_occupying, g_trunk_init_check_occupying,
g_trunk_init_reload_from_binlog, g_trunk_init_reload_from_binlog,
g_trunk_free_space_merge,
g_trunk_compress_binlog_min_interval, g_trunk_compress_binlog_min_interval,
g_trunk_compress_binlog_interval, g_trunk_compress_binlog_interval,
g_trunk_compress_binlog_time_base.hour, g_trunk_compress_binlog_time_base.hour,