/** * 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 #include #include #include #include #include #include #include #include #include "fdfs_define.h" #include "fastcommon/logger.h" #include "fastcommon/sockopt.h" #include "fdfs_global.h" #include "fastcommon/shared_func.h" #include "fastcommon/pthread_func.h" #include "tracker_global.h" #include "tracker_proto.h" #include "tracker_mem.h" #include "tracker_relationship.h" bool g_if_leader_self = false; //if I am leader static int fdfs_ping_leader(ConnectionInfo *pTrackerServer) { TrackerHeader header; int result; int success_count; int64_t in_bytes; char in_buff[(FDFS_GROUP_NAME_MAX_LEN + FDFS_STORAGE_ID_MAX_SIZE) * \ FDFS_MAX_GROUPS]; char *pInBuff; char *p; char *pEnd; FDFSGroupInfo *pGroup; char group_name[FDFS_GROUP_NAME_MAX_LEN + 1]; char trunk_server_id[FDFS_STORAGE_ID_MAX_SIZE]; memset(&header, 0, sizeof(header)); header.cmd = TRACKER_PROTO_CMD_TRACKER_PING_LEADER; result = tcpsenddata_nb(pTrackerServer->sock, &header, \ sizeof(header), g_fdfs_network_timeout); if(result != 0) { logError("file: "__FILE__", line: %d, " \ "tracker server ip: %s, send data fail, " \ "errno: %d, error info: %s", \ __LINE__, pTrackerServer->ip_addr, \ result, STRERROR(result)); return result; } pInBuff = in_buff; if ((result=fdfs_recv_response(pTrackerServer, &pInBuff, \ sizeof(in_buff), &in_bytes)) != 0) { logError("file: "__FILE__", line: %d, " "fdfs_recv_response fail, result: %d", __LINE__, result); return result; } if (in_bytes == 0) { return 0; } else if (in_bytes % (FDFS_GROUP_NAME_MAX_LEN + \ FDFS_STORAGE_ID_MAX_SIZE) != 0) { logError("file: "__FILE__", line: %d, " \ "tracker server ip: %s, invalid body length: " \ "%"PRId64, __LINE__, \ pTrackerServer->ip_addr, in_bytes); return EINVAL; } success_count = 0; memset(group_name, 0, sizeof(group_name)); memset(trunk_server_id, 0, sizeof(trunk_server_id)); pEnd = in_buff + in_bytes; for (p=in_buff; pip_addr, group_name); continue; } if (*trunk_server_id == '\0') { *(pGroup->last_trunk_server_id) = '\0'; pGroup->pTrunkServer = NULL; success_count++; continue; } pGroup->pTrunkServer = tracker_mem_get_storage(pGroup, \ trunk_server_id); if (pGroup->pTrunkServer == NULL) { logWarning("file: "__FILE__", line: %d, " \ "tracker server ip: %s, group: %s, " \ "trunk server: %s not exists", \ __LINE__, pTrackerServer->ip_addr, \ group_name, trunk_server_id); } snprintf(pGroup->last_trunk_server_id, sizeof( \ pGroup->last_trunk_server_id), "%s", trunk_server_id); success_count++; } if (success_count > 0) { tracker_save_groups(); } return 0; } static int relationship_cmp_tracker_status(const void *p1, const void *p2) { TrackerRunningStatus *pStatus1; TrackerRunningStatus *pStatus2; ConnectionInfo *pTrackerServer1; ConnectionInfo *pTrackerServer2; int sub; pStatus1 = (TrackerRunningStatus *)p1; pStatus2 = (TrackerRunningStatus *)p2; sub = pStatus1->if_leader - pStatus2->if_leader; if (sub != 0) { return sub; } sub = pStatus1->running_time - pStatus2->running_time; if (sub != 0) { return sub; } sub = pStatus2->restart_interval - pStatus1->restart_interval; if (sub != 0) { return sub; } pTrackerServer1 = pStatus1->pTrackerServer; pTrackerServer2 = pStatus2->pTrackerServer; sub = strcmp(pTrackerServer1->ip_addr, pTrackerServer2->ip_addr); if (sub != 0) { return sub; } return pTrackerServer1->port - pTrackerServer2->port; } static int relationship_get_tracker_leader(TrackerRunningStatus *pTrackerStatus) { ConnectionInfo *pTrackerServer; ConnectionInfo *pTrackerEnd; TrackerRunningStatus *pStatus; TrackerRunningStatus trackerStatus[FDFS_MAX_TRACKERS]; int count; int result; int r; int i; memset(pTrackerStatus, 0, sizeof(TrackerRunningStatus)); pStatus = trackerStatus; result = 0; pTrackerEnd = g_tracker_servers.servers + g_tracker_servers.server_count; for (pTrackerServer=g_tracker_servers.servers; \ pTrackerServerpTrackerServer = pTrackerServer; r = fdfs_get_tracker_status(pTrackerServer, pStatus); if (r == 0) { pStatus++; } else if (r != ENOENT) { result = r; } } count = pStatus - trackerStatus; if (count == 0) { logError("file: "__FILE__", line: %d, " "get tracker status fail, " "tracker server count: %d", __LINE__, g_tracker_servers.server_count); return result == 0 ? ENOENT : result; } qsort(trackerStatus, count, sizeof(TrackerRunningStatus), \ relationship_cmp_tracker_status); for (i=0; iip_addr, \ trackerStatus[i].pTrackerServer->port, \ trackerStatus[i].if_leader, \ trackerStatus[i].running_time, \ trackerStatus[i].restart_interval); } memcpy(pTrackerStatus, trackerStatus + (count - 1), \ sizeof(TrackerRunningStatus)); return 0; } #define relationship_notify_next_leader(pTrackerServer, pLeader, bConnectFail) \ do_notify_leader_changed(pTrackerServer, pLeader, \ TRACKER_PROTO_CMD_TRACKER_NOTIFY_NEXT_LEADER, bConnectFail) #define relationship_commit_next_leader(pTrackerServer, pLeader, bConnectFail) \ do_notify_leader_changed(pTrackerServer, pLeader, \ TRACKER_PROTO_CMD_TRACKER_COMMIT_NEXT_LEADER, bConnectFail) static int do_notify_leader_changed(ConnectionInfo *pTrackerServer, \ ConnectionInfo *pLeader, const char cmd, bool *bConnectFail) { char out_buff[sizeof(TrackerHeader) + FDFS_PROTO_IP_PORT_SIZE]; char in_buff[1]; ConnectionInfo *conn; TrackerHeader *pHeader; char *pInBuff; int64_t in_bytes; int result; pTrackerServer->sock = -1; if ((conn=tracker_connect_server(pTrackerServer, &result)) == NULL) { *bConnectFail = true; return result; } *bConnectFail = false; do { memset(out_buff, 0, sizeof(out_buff)); pHeader = (TrackerHeader *)out_buff; pHeader->cmd = cmd; sprintf(out_buff + sizeof(TrackerHeader), "%s:%d", \ pLeader->ip_addr, pLeader->port); long2buff(FDFS_PROTO_IP_PORT_SIZE, pHeader->pkg_len); 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)); result = (result == ENOENT ? EACCES : result); break; } pInBuff = in_buff; result = fdfs_recv_response(conn, &pInBuff, \ 0, &in_bytes); if (result != 0) { logError("file: "__FILE__", line: %d, " "fdfs_recv_response fail, result: %d", __LINE__, result); break; } if (in_bytes != 0) { logError("file: "__FILE__", line: %d, " \ "tracker server %s:%d response data " \ "length: %"PRId64" is invalid, " \ "expect length: %d.", __LINE__, \ pTrackerServer->ip_addr, pTrackerServer->port, \ in_bytes, 0); result = EINVAL; break; } } while (0); if (pTrackerServer->port == g_server_port && \ is_local_host_ip(pTrackerServer->ip_addr)) { tracker_disconnect_server_ex(conn, true); } else { tracker_disconnect_server_ex(conn, result != 0); } return result; } static int relationship_notify_leader_changed(ConnectionInfo *pLeader) { ConnectionInfo *pTrackerServer; ConnectionInfo *pTrackerEnd; int result; bool bConnectFail; int success_count; result = ENOENT; pTrackerEnd = g_tracker_servers.servers + g_tracker_servers.server_count; success_count = 0; for (pTrackerServer=g_tracker_servers.servers; \ pTrackerServerport == g_server_port && \ is_local_host_ip(trackerStatus.pTrackerServer->ip_addr)) { if ((result=relationship_notify_leader_changed( \ trackerStatus.pTrackerServer)) != 0) { return result; } logInfo("file: "__FILE__", line: %d, " \ "I am the new tracker leader %s:%d", \ __LINE__, trackerStatus.pTrackerServer->ip_addr, \ trackerStatus.pTrackerServer->port); tracker_mem_find_trunk_servers(); } else { if (trackerStatus.if_leader) { g_tracker_servers.leader_index = \ trackerStatus.pTrackerServer - \ g_tracker_servers.servers; if (g_tracker_servers.leader_index < 0 || \ g_tracker_servers.leader_index >= \ g_tracker_servers.server_count) { logError("file: "__FILE__", line: %d, " "invalid leader_index: %d", __LINE__, g_tracker_servers.leader_index); g_tracker_servers.leader_index = -1; return EINVAL; } logInfo("file: "__FILE__", line: %d, " \ "the tracker leader %s:%d", __LINE__, \ trackerStatus.pTrackerServer->ip_addr, \ trackerStatus.pTrackerServer->port); } else { logDebug("file: "__FILE__", line: %d, " \ "waiting for leader notify", __LINE__); return ENOENT; } } return 0; } static int relationship_ping_leader() { int result; int leader_index; ConnectionInfo *pTrackerServer; if (g_if_leader_self) { return 0; //do not need ping myself } leader_index = g_tracker_servers.leader_index; if (leader_index < 0) { return EINVAL; } pTrackerServer = g_tracker_servers.servers + leader_index; if (pTrackerServer->sock < 0) { if ((result=conn_pool_connect_server(pTrackerServer, \ g_fdfs_connect_timeout)) != 0) { return result; } } if ((result=fdfs_ping_leader(pTrackerServer)) != 0) { close(pTrackerServer->sock); pTrackerServer->sock = -1; } return result; } static void *relationship_thread_entrance(void* arg) { #define MAX_SLEEP_SECONDS 10 int fail_count; int sleep_seconds; fail_count = 0; while (g_continue_flag) { sleep_seconds = 1; if (g_tracker_servers.servers != NULL) { if (g_tracker_servers.leader_index < 0) { if (relationship_select_leader() != 0) { sleep_seconds = 1 + (int)((double)rand() * (double)MAX_SLEEP_SECONDS / RAND_MAX); } } else { if (relationship_ping_leader() == 0) { fail_count = 0; } else { fail_count++; if (fail_count >= 3) { g_tracker_servers.leader_index = -1; } } } } if (g_last_tracker_servers != NULL) { tracker_mem_file_lock(); free(g_last_tracker_servers); g_last_tracker_servers = NULL; tracker_mem_file_unlock(); } sleep(sleep_seconds); } return NULL; } int tracker_relationship_init() { int result; pthread_t tid; pthread_attr_t thread_attr; if ((result=init_pthread_attr(&thread_attr, g_thread_stack_size)) != 0) { logError("file: "__FILE__", line: %d, " \ "init_pthread_attr fail, program exit!", __LINE__); return result; } if ((result=pthread_create(&tid, &thread_attr, \ relationship_thread_entrance, NULL)) != 0) { logError("file: "__FILE__", line: %d, " \ "create thread failed, errno: %d, error info: %s", \ __LINE__, result, STRERROR(result)); return result; } pthread_attr_destroy(&thread_attr); return 0; } int tracker_relationship_destroy() { return 0; }