一、准备工作
1、tracker leader的作用:
tracker server之间是对等的。客户端可以访问任意一台tracker server。
引入tracker leader是为了解决如下问题:
a. 新加入一台storage server时,由leader指定向其同步的源storage server;
b. 使用了合并存储特性时,leader为每个group选举和维护唯一的一个trunk server;
以上分配如果不由leader来完成的话,可能会出现混乱情况,尤其是第2条。
2、tracker启动时是不知道其他tracker的存在的。当随后的storage server(storage的配置文件中应当包含所有tracker的ip、port信息)启动时,storage server会去连接每一个tracker,并push 信息。这样tracker的g_tracker_servers才得以初始化(g_tracker_servers初始化在tracker_deal_storage_join->tracker_mem_add_group_and_storage->tracker_mem_first_add_tracker_servers中;后续添加tracker至g_tracker_servers位于tracker_mem_check_add_tracker_servers中)。所有tracker的位置信息都存于g_tracker_servers中,也是用于选主的最关键结构。(一个疑问,在一个正在运行的集群中,如何添加一个tracker server呢?)
3、数据结构
TrackerServerGroup g_tracker_servers = {0, 0, -1, NULL};
typedef struct
{
int server_count;
int server_index; //server index for roundrobin
int leader_index; //leader server index
ConnectionInfo *servers;
} TrackerServerGroup
二、relationship_thread_entrance
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) //ping主,发送TRACKER_PROTO_CMD_TRACKER_PING_LEADE命令。
{
fail_count = 0;
}
else
{
fail_count++;
if (fail_count >= 3) //超过三次发现leader ping不通,下次循环时就要选择新的leader了。
{
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;
}
三、relationship_select_leader
static int relationship_select_leader()
{
int result;
TrackerRunningStatus trackerStatus;
if (g_tracker_servers.server_count <= 0)
{
return 0;
}
logInfo("file: "__FILE__", line: %d, " \
"selecting leader...", __LINE__);
if ((result=relationship_get_tracker_leader(&trackerStatus)) != 0) //比较每个tracker的性能(比较函数为relationship_cmp_tracker_status:根据一些参数进行比较即可),得到最佳的tracker存于trackerStatus中。
{
return result;
}
if (trackerStatus.pTrackerServer->port == g_server_port && \
is_local_host_ip(trackerStatus.pTrackerServer->ip_addr))
{//如果就是当前tracker被选中为leader:
if ((result=relationship_notify_leader_changed( \
trackerStatus.pTrackerServer)) != 0) //通知所有其他tracker新的leader。
{
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) //如果是这样,就已经知道leader是谁了,不需要等待notify。
{
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)
{
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;
}