/** * Copyright (C) 2008 Happy Fish / YuQing * * FastDFS may be copied only under the terms of the GNU General * Public License V3, which may be found in the FastDFS source kit. * Please visit the FastDFS Home Page http://www.csource.org/ for more detail. **/ #include #include #include #include "fastcommon/logger.h" #include "fastcommon/sockopt.h" #include "fastcommon/shared_func.h" #include "tracker_proto.h" #include "fdfs_global.h" #include "fdfs_shared_func.h" FDFSStorageIdInfo *g_storage_ids_by_ip = NULL; //sorted by group name and storage IP FDFSStorageIdInfo **g_storage_ids_by_id = NULL; //sorted by storage ID static FDFSStorageIdInfo **g_storage_ids_by_ip_port = NULL; //sorted by storage ip and port int g_storage_id_count = 0; int fdfs_get_tracker_leader_index_ex(TrackerServerGroup *pServerGroup, \ const char *leaderIp, const int leaderPort) { ConnectionInfo *pServer; ConnectionInfo *pEnd; if (pServerGroup->server_count == 0) { return -1; } pEnd = pServerGroup->servers + pServerGroup->server_count; for (pServer=pServerGroup->servers; pServerip_addr, leaderIp) == 0 && \ pServer->port == leaderPort) { return pServer - pServerGroup->servers; } } return -1; } int fdfs_parse_storage_reserved_space(IniContext *pIniContext, \ FDFSStorageReservedSpace *pStorageReservedSpace) { int result; int len; char *pReservedSpaceStr; int64_t storage_reserved; pReservedSpaceStr = iniGetStrValue(NULL, \ "reserved_storage_space", pIniContext); if (pReservedSpaceStr == NULL) { pStorageReservedSpace->flag = \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB; pStorageReservedSpace->rs.mb = FDFS_DEF_STORAGE_RESERVED_MB; return 0; } if (*pReservedSpaceStr == '\0') { logError("file: "__FILE__", line: %d, " \ "item \"reserved_storage_space\" is empty!", \ __LINE__); return EINVAL; } len = strlen(pReservedSpaceStr); if (*(pReservedSpaceStr + len - 1) == '%') { char *endptr; pStorageReservedSpace->flag = \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_RATIO; endptr = NULL; *(pReservedSpaceStr + len - 1) = '\0'; pStorageReservedSpace->rs.ratio = \ strtod(pReservedSpaceStr, &endptr); if (endptr != NULL && *endptr != '\0') { logError("file: "__FILE__", line: %d, " \ "item \"reserved_storage_space\": %s%%"\ " is invalid!", __LINE__, \ pReservedSpaceStr); return EINVAL; } if (pStorageReservedSpace->rs.ratio <= 0.00 || \ pStorageReservedSpace->rs.ratio >= 100.00) { logError("file: "__FILE__", line: %d, " \ "item \"reserved_storage_space\": %s%%"\ " is invalid!", __LINE__, \ pReservedSpaceStr); return EINVAL; } pStorageReservedSpace->rs.ratio /= 100.00; return 0; } if ((result=parse_bytes(pReservedSpaceStr, 1, &storage_reserved)) != 0) { return result; } pStorageReservedSpace->flag = TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB; pStorageReservedSpace->rs.mb = storage_reserved / FDFS_ONE_MB; return 0; } const char *fdfs_storage_reserved_space_to_string(FDFSStorageReservedSpace \ *pStorageReservedSpace, char *buff) { if (pStorageReservedSpace->flag == \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { sprintf(buff, "%d MB", pStorageReservedSpace->rs.mb); } else { sprintf(buff, "%.2f%%", 100.00 * \ pStorageReservedSpace->rs.ratio); } return buff; } const char *fdfs_storage_reserved_space_to_string_ex(const bool flag, \ const int space_mb, const int total_mb, const double space_ratio, \ char *buff) { if (flag == TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { sprintf(buff, "%d MB", space_mb); } else { sprintf(buff, "%d MB(%.2f%%)", (int)(total_mb * space_ratio), \ 100.00 * space_ratio); } return buff; } int fdfs_get_storage_reserved_space_mb(const int total_mb, \ FDFSStorageReservedSpace *pStorageReservedSpace) { if (pStorageReservedSpace->flag == \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { return pStorageReservedSpace->rs.mb; } else { return (int)(total_mb * pStorageReservedSpace->rs.ratio); } } bool fdfs_check_reserved_space(FDFSGroupInfo *pGroup, \ FDFSStorageReservedSpace *pStorageReservedSpace) { if (pStorageReservedSpace->flag == \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { return pGroup->free_mb > pStorageReservedSpace->rs.mb; } else { if (pGroup->total_mb == 0) { return false; } /* logInfo("storage=%.4f, rs.ratio=%.4f", ((double)pGroup->free_mb / (double)pGroup->total_mb), pStorageReservedSpace->rs.ratio); */ return ((double)pGroup->free_mb / (double)pGroup->total_mb) > \ pStorageReservedSpace->rs.ratio; } } bool fdfs_check_reserved_space_trunk(FDFSGroupInfo *pGroup, \ FDFSStorageReservedSpace *pStorageReservedSpace) { if (pStorageReservedSpace->flag == \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { return (pGroup->free_mb + pGroup->trunk_free_mb > pStorageReservedSpace->rs.mb); } else { if (pGroup->total_mb == 0) { return false; } /* logInfo("storage trunk=%.4f, rs.ratio=%.4f", ((double)(pGroup->free_mb + pGroup->trunk_free_mb) / \ (double)pGroup->total_mb), pStorageReservedSpace->rs.ratio); */ return ((double)(pGroup->free_mb + pGroup->trunk_free_mb) / \ (double)pGroup->total_mb) > pStorageReservedSpace->rs.ratio; } } bool fdfs_check_reserved_space_path(const int64_t total_mb, \ const int64_t free_mb, const int avg_mb, \ FDFSStorageReservedSpace *pStorageReservedSpace) { if (pStorageReservedSpace->flag == \ TRACKER_STORAGE_RESERVED_SPACE_FLAG_MB) { return free_mb > avg_mb; } else { if (total_mb == 0) { return false; } /* logInfo("storage path, free_mb=%"PRId64 \ ", total_mb=%"PRId64", " \ "real ratio=%.4f, rs.ratio=%.4f", \ free_mb, total_mb, ((double)free_mb / total_mb), \ pStorageReservedSpace->rs.ratio); */ return ((double)free_mb / (double)total_mb) > \ pStorageReservedSpace->rs.ratio; } } bool fdfs_is_server_id_valid(const char *id) { long n; char *endptr; char buff[FDFS_STORAGE_ID_MAX_SIZE]; if (*id == '\0') { return false; } endptr = NULL; n = strtol(id, &endptr, 10); if (endptr != NULL && *endptr != '\0') { return false; } if (n <= 0 || n > FDFS_MAX_SERVER_ID) { return false; } snprintf(buff, sizeof(buff), "%ld", n); return strcmp(buff, id) == 0; } int fdfs_get_server_id_type(const int id) { if (id > 0 && id <= FDFS_MAX_SERVER_ID) { return FDFS_ID_TYPE_SERVER_ID; } else { return FDFS_ID_TYPE_IP_ADDRESS; } } static int fdfs_cmp_group_name_and_ip(const void *p1, const void *p2) { int result; result = strcmp(((FDFSStorageIdInfo *)p1)->group_name, ((FDFSStorageIdInfo *)p2)->group_name); if (result != 0) { return result; } return strcmp(((FDFSStorageIdInfo *)p1)->ip_addr, \ ((FDFSStorageIdInfo *)p2)->ip_addr); } static int fdfs_cmp_server_id(const void *p1, const void *p2) { return strcmp((*((FDFSStorageIdInfo **)p1))->id, \ (*((FDFSStorageIdInfo **)p2))->id); } static int fdfs_cmp_ip_and_port(const void *p1, const void *p2) { int result; result = strcmp((*((FDFSStorageIdInfo **)p1))->ip_addr, (*((FDFSStorageIdInfo **)p2))->ip_addr); if (result != 0) { return result; } return (*((FDFSStorageIdInfo **)p1))->port - (*((FDFSStorageIdInfo **)p2))->port; } FDFSStorageIdInfo *fdfs_get_storage_id_by_ip(const char *group_name, \ const char *pIpAddr) { FDFSStorageIdInfo target; memset(&target, 0, sizeof(FDFSStorageIdInfo)); snprintf(target.group_name, sizeof(target.group_name), "%s", group_name); snprintf(target.ip_addr, sizeof(target.ip_addr), "%s", pIpAddr); return (FDFSStorageIdInfo *)bsearch(&target, g_storage_ids_by_ip, \ g_storage_id_count, sizeof(FDFSStorageIdInfo), \ fdfs_cmp_group_name_and_ip); } FDFSStorageIdInfo *fdfs_get_storage_by_id(const char *id) { FDFSStorageIdInfo target; FDFSStorageIdInfo *pTarget; FDFSStorageIdInfo **ppFound; memset(&target, 0, sizeof(FDFSStorageIdInfo)); snprintf(target.id, sizeof(target.id), "%s", id); pTarget = ⌖ ppFound = (FDFSStorageIdInfo **)bsearch(&pTarget, g_storage_ids_by_id, \ g_storage_id_count, sizeof(FDFSStorageIdInfo *), \ fdfs_cmp_server_id); if (ppFound == NULL) { return NULL; } else { return *ppFound; } } static int fdfs_init_ip_port_array() { int result; int alloc_bytes; int i; int port_count; FDFSStorageIdInfo *previous; alloc_bytes = sizeof(FDFSStorageIdInfo *) * g_storage_id_count; g_storage_ids_by_ip_port = (FDFSStorageIdInfo **)malloc(alloc_bytes); if (g_storage_ids_by_ip_port == NULL) { result = errno != 0 ? errno : ENOMEM; logError("file: "__FILE__", line: %d, " \ "malloc %d bytes fail, " \ "errno: %d, error info: %s", __LINE__, \ alloc_bytes, result, STRERROR(result)); return result; } port_count = 0; for (i=0; iport > 0) { port_count++; } } if (port_count > 0 && port_count != g_storage_id_count) { logError("file: "__FILE__", line: %d, " "config file: storage_ids.conf, some storages without port, " "must be the same format as host:port", __LINE__); free(g_storage_ids_by_ip_port); g_storage_ids_by_ip_port = NULL; return EINVAL; } qsort(g_storage_ids_by_ip_port, g_storage_id_count, sizeof(FDFSStorageIdInfo *), fdfs_cmp_ip_and_port); previous = g_storage_ids_by_ip_port[0]; for (i=1; iport > 0) { sprintf(szPortPart, ":%d", previous->port); } else { *szPortPart = '\0'; } logError("file: "__FILE__", line: %d, " "config file: storage_ids.conf, " "duplicate storage: %s%s", __LINE__, previous->ip_addr, szPortPart); free(g_storage_ids_by_ip_port); g_storage_ids_by_ip_port = NULL; return EEXIST; } previous = g_storage_ids_by_ip_port[i]; } return 0; } FDFSStorageIdInfo *fdfs_get_storage_id_by_ip_port(const char *pIpAddr, const int port) { FDFSStorageIdInfo target; FDFSStorageIdInfo *pTarget; FDFSStorageIdInfo **ppFound; int ports[2]; int i; if (g_storage_ids_by_ip_port == NULL) { if (fdfs_init_ip_port_array() != 0) { return NULL; } } pTarget = ⌖ memset(&target, 0, sizeof(FDFSStorageIdInfo)); snprintf(target.ip_addr, sizeof(target.ip_addr), "%s", pIpAddr); ports[0] = port; ports[1] = 0; for (i=0; i<2; i++) { target.port = ports[i]; ppFound = (FDFSStorageIdInfo **)bsearch(&pTarget, g_storage_ids_by_ip_port, g_storage_id_count, sizeof(FDFSStorageIdInfo *), fdfs_cmp_ip_and_port); if (ppFound != NULL) { return *ppFound; } } return NULL; } int fdfs_check_storage_id(const char *group_name, const char *id) { FDFSStorageIdInfo *pFound; pFound = fdfs_get_storage_by_id(id); if (pFound == NULL) { return ENOENT; } return strcmp(pFound->group_name, group_name) == 0 ? 0 : EINVAL; } int fdfs_load_storage_ids(char *content, const char *pStorageIdsFilename) { char **lines; char *line; char *id; char *group_name; char *pHost; char *pIpAddr; char *pPort; FDFSStorageIdInfo *pStorageIdInfo; FDFSStorageIdInfo **ppStorageIdInfo; FDFSStorageIdInfo **ppStorageIdEnd; int alloc_bytes; int result; int line_count; int i; lines = split(content, '\n', 0, &line_count); if (lines == NULL) { return ENOMEM; } result = 0; do { g_storage_id_count = 0; for (i=0; iport = atoi(pPort + 1); } else { pStorageIdInfo->port = 0; } if (getIpaddrByName(pIpAddr, pStorageIdInfo->ip_addr, \ sizeof(pStorageIdInfo->ip_addr)) == INADDR_NONE) { logError("file: "__FILE__", line: %d, " \ "invalid host name: %s", __LINE__, pIpAddr); result = EINVAL; break; } if (!fdfs_is_server_id_valid(id)) { logError("file: "__FILE__", line: %d, " \ "invalid server id: \"%s\", " \ "which must be a none zero start " \ "integer, such as 100001", __LINE__, id); result = EINVAL; break; } snprintf(pStorageIdInfo->id, \ sizeof(pStorageIdInfo->id), "%s", id); snprintf(pStorageIdInfo->group_name, \ sizeof(pStorageIdInfo->group_name), \ "%s", group_name); pStorageIdInfo++; } } while (0); freeSplit(lines); if (result != 0) { return result; } logDebug("file: "__FILE__", line: %d, " \ "g_storage_id_count: %d", __LINE__, g_storage_id_count); pStorageIdInfo = g_storage_ids_by_ip; for (i=0; iport > 0) { sprintf(szPortPart, ":%d", pStorageIdInfo->port); } else { *szPortPart = '\0'; } logDebug("%s %s %s%s", pStorageIdInfo->id, pStorageIdInfo->group_name, pStorageIdInfo->ip_addr, szPortPart); pStorageIdInfo++; } ppStorageIdEnd = g_storage_ids_by_id + g_storage_id_count; pStorageIdInfo = g_storage_ids_by_ip; for (ppStorageIdInfo=g_storage_ids_by_id; ppStorageIdInfo < \ ppStorageIdEnd; ppStorageIdInfo++) { *ppStorageIdInfo = pStorageIdInfo++; } qsort(g_storage_ids_by_ip, g_storage_id_count, \ sizeof(FDFSStorageIdInfo), fdfs_cmp_group_name_and_ip); qsort(g_storage_ids_by_id, g_storage_id_count, \ sizeof(FDFSStorageIdInfo *), fdfs_cmp_server_id); return result; } int fdfs_get_storage_ids_from_tracker_server(ConnectionInfo *pTrackerServer) { #define MAX_REQUEST_LOOP 32 TrackerHeader *pHeader; ConnectionInfo *conn; char out_buff[sizeof(TrackerHeader) + sizeof(int)]; char *p; char *response; struct data_info { char *buffer; //for free char *content; int length; } data_list[MAX_REQUEST_LOOP]; int list_count; int total_count; int current_count; int result; int i; int start_index; int64_t in_bytes; if ((conn=tracker_connect_server(pTrackerServer, &result)) == NULL) { return result; } memset(data_list, 0, sizeof(data_list)); memset(out_buff, 0, sizeof(out_buff)); pHeader = (TrackerHeader *)out_buff; p = out_buff + sizeof(TrackerHeader); pHeader->cmd = TRACKER_PROTO_CMD_STORAGE_FETCH_STORAGE_IDS; long2buff(sizeof(int), pHeader->pkg_len); start_index = 0; list_count = 0; result = 0; while (1) { int2buff(start_index, p); if ((result=tcpsenddata_nb(conn->sock, out_buff, \ sizeof(out_buff), g_fdfs_network_timeout)) != 0) { logError("file: "__FILE__", line: %d, " \ "send data to tracker server %s:%d fail, " \ "errno: %d, error info: %s", __LINE__, \ pTrackerServer->ip_addr, \ pTrackerServer->port, \ result, STRERROR(result)); } else { response = NULL; result = fdfs_recv_response(conn, \ &response, 0, &in_bytes); if (result != 0) { logError("file: "__FILE__", line: %d, " "fdfs_recv_response fail, result: %d", __LINE__, result); } } if (result != 0) { break; } if (in_bytes < 2 * sizeof(int)) { logError("file: "__FILE__", line: %d, " \ "tracker server %s:%d, recv data length: %d "\ "is invalid", __LINE__, pTrackerServer->ip_addr, \ pTrackerServer->port, (int)in_bytes); result = EINVAL; break; } total_count = buff2int(response); current_count = buff2int(response + sizeof(int)); if (total_count <= start_index) { logError("file: "__FILE__", line: %d, " \ "tracker server %s:%d, total storage " \ "count: %d is invalid, which <= start " \ "index: %d", __LINE__, pTrackerServer->ip_addr,\ pTrackerServer->port, total_count, start_index); result = EINVAL; break; } if (current_count <= 0) { logError("file: "__FILE__", line: %d, " \ "tracker server %s:%d, current storage " \ "count: %d is invalid, which <= 0", \ __LINE__, pTrackerServer->ip_addr,\ pTrackerServer->port, current_count); result = EINVAL; break; } data_list[list_count].buffer = response; data_list[list_count].content = response + 2 * sizeof(int); data_list[list_count].length = in_bytes - 2 * sizeof(int); list_count++; /* //logInfo("list_count: %d, total_count: %d, current_count: %d", list_count, total_count, current_count); */ start_index += current_count; if (start_index >= total_count) { break; } if (list_count == MAX_REQUEST_LOOP) { logError("file: "__FILE__", line: %d, " \ "response data from tracker " \ "server %s:%d is too large", \ __LINE__, pTrackerServer->ip_addr,\ pTrackerServer->port); result = ENOSPC; break; } } tracker_disconnect_server_ex(conn, result != 0); if (result == 0) { do { int total_length; char *content; total_length = 0; for (i=0; iservers + pTrackerGroup->server_count; leader_index = pTrackerGroup->leader_index; if (leader_index >= 0) { pServerStart = pTrackerGroup->servers + leader_index; } else { pServerStart = pTrackerGroup->servers; } result = ENOENT; for (i=0; i<5; i++) { for (pGServer=pServerStart; pGServersock = -1; result = fdfs_get_storage_ids_from_tracker_server(pTServer); if (result == 0) { return result; } } if (pServerStart != pTrackerGroup->servers) { pServerStart = pTrackerGroup->servers; } sleep(1); } return result; } int fdfs_load_storage_ids_from_file(const char *config_filename, \ IniContext *pItemContext) { char *pStorageIdsFilename; char *content; int64_t file_size; int result; pStorageIdsFilename = iniGetStrValue(NULL, "storage_ids_filename", \ pItemContext); if (pStorageIdsFilename == NULL) { logError("file: "__FILE__", line: %d, " \ "conf file \"%s\" must have item " \ "\"storage_ids_filename\"!", __LINE__, config_filename); return ENOENT; } if (*pStorageIdsFilename == '\0') { logError("file: "__FILE__", line: %d, " \ "conf file \"%s\", storage_ids_filename is emtpy!", \ __LINE__, config_filename); return EINVAL; } if (*pStorageIdsFilename == '/') //absolute path { result = getFileContent(pStorageIdsFilename, \ &content, &file_size); } else { const char *lastSlash = strrchr(config_filename, '/'); if (lastSlash == NULL) { result = getFileContent(pStorageIdsFilename, \ &content, &file_size); } else { char filepath[MAX_PATH_SIZE]; char full_filename[MAX_PATH_SIZE]; int len; len = lastSlash - config_filename; if (len >= sizeof(filepath)) { logError("file: "__FILE__", line: %d, " \ "conf filename: \"%s\" is too long!", \ __LINE__, config_filename); return ENOSPC; } memcpy(filepath, config_filename, len); *(filepath + len) = '\0'; snprintf(full_filename, sizeof(full_filename), \ "%s/%s", filepath, pStorageIdsFilename); result = getFileContent(full_filename, \ &content, &file_size); } } if (result != 0) { return result; } result = fdfs_load_storage_ids(content, pStorageIdsFilename); free(content); return result; } int fdfs_connection_pool_init(const char *config_filename, \ IniContext *pItemContext) { g_use_connection_pool = iniGetBoolValue(NULL, "use_connection_pool", \ pItemContext, false); if (!g_use_connection_pool) { return 0; } g_connection_pool_max_idle_time = iniGetIntValue(NULL, \ "connection_pool_max_idle_time", \ pItemContext, 3600); if (g_connection_pool_max_idle_time <= 0) { logError("file: "__FILE__", line: %d, " \ "connection_pool_max_idle_time: %d of conf " \ "filename: \"%s\" is invalid!", __LINE__, \ g_connection_pool_max_idle_time, config_filename); return EINVAL; } return conn_pool_init(&g_connection_pool, g_fdfs_connect_timeout, \ 0, g_connection_pool_max_idle_time); } void fdfs_connection_pool_destroy() { conn_pool_destroy(&g_connection_pool); } void fdfs_set_log_rotate_size(LogContext *pContext, const int64_t log_rotate_size) { if (log_rotate_size > 0) { pContext->rotate_size = log_rotate_size; log_set_rotate_time_format(pContext, "%Y%m%d_%H%M%S"); } else { pContext->rotate_size = 0; log_set_rotate_time_format(pContext, "%Y%m%d"); } }