一、第一部分
1、准备
此篇文章是第八篇文件同步的基础。状态改变相关的操作:storage的report线程,tracker的对应处理。本文storage的状态是从FDFS_STORAGE_STATUS_INIT开始的。
#define FDFS_STORAGE_STATUS_INIT 0 //初始化,尚未得到同步已有数据的源服务器
#define FDFS_STORAGE_STATUS_WAIT_SYNC 1 //等待同步,已得到同步已有数据的源服务器
#define FDFS_STORAGE_STATUS_SYNCING 2 //同步中
#define FDFS_STORAGE_STATUS_IP_CHANGED 3
#define FDFS_STORAGE_STATUS_DELETED 4 //已删除,该服务器从本组中摘除
#define FDFS_STORAGE_STATUS_OFFLINE 5 //离线
#define FDFS_STORAGE_STATUS_ONLINE 6 //在线,尚不能提供服务(当storage server向tracker发送一个心跳时,对应storage server状态就变为active。)
#define FDFS_STORAGE_STATUS_ACTIVE 7 //在线,可以提供服务
#define FDFS_STORAGE_STATUS_RECOVERY 9
#define FDFS_STORAGE_STATUS_NONE 99
2、 storage的tracker_sync_notify
storage的启动时状态为FDFS_STORAGE_STATUS_INIT。
storage的report线程tracker_report_thread_entrance中会调用 src_storage_status[tracker_index] = tracker_sync_notify(pTrackerServer)。该函数向tracker发送TRACKER_PROTO_CMD_STORAGE_SYNC_NOTIFY命令。tracker接收到此命令后,会将storage状态改变。
3、tracker的tracker_deal_storage_sync_notify
1、当tracker收到TRACKER_PROTO_CMD_STORAGE_SYNC_NOTIFY命令时,就会调用tracker_deal_storage_sync_notify。本例中,由于*(pBody->src_id) == '\0',即storage的g_sync_src_id为空(g_sync_src_id对应于data/.data_init_flag文件中的sync_src_server项),所以tracker将storage server状态改为FDFS_STORAGE_STATUS_ONLINE。之后tracker会接收到来自storage的心跳,那是就从ONLINE变为ACTIVE。所以storage的状态最终为ACTIVE。
static int tracker_deal_storage_sync_notify(struct fast_task_info *pTask)
{
TrackerStorageSyncReqBody *pBody;
char sync_src_id[FDFS_STORAGE_ID_MAX_SIZE];
bool bSaveStorages;
TrackerClientInfo *pClientInfo;
pClientInfo = (TrackerClientInfo *)pTask->arg;
if (pTask->length - sizeof(TrackerHeader) != \
sizeof(TrackerStorageSyncReqBody))
{
pTask->length = sizeof(TrackerHeader);
return EINVAL;
}
pBody=(TrackerStorageSyncReqBody *)(pTask->data+sizeof(TrackerHeader));
if (*(pBody->src_id) == '\0') //这是本例的执行情况。原因是storage的g_sync_src_id为0。为什么一直为0呢??
{
if (pClientInfo->pStorage->status == FDFS_STORAGE_STATUS_INIT || \
pClientInfo->pStorage->status == FDFS_STORAGE_STATUS_WAIT_SYNC || \
pClientInfo->pStorage->status == FDFS_STORAGE_STATUS_SYNCING)
{
pClientInfo->pStorage->status = FDFS_STORAGE_STATUS_ONLINE;
pClientInfo->pGroup->chg_count++;
tracker_save_storages();
}
pTask->length = sizeof(TrackerHeader);
return 0;
}
bSaveStorages = false;
if (pClientInfo->pStorage->status == FDFS_STORAGE_STATUS_INIT)
{
pClientInfo->pStorage->status = FDFS_STORAGE_STATUS_WAIT_SYNC; //见第二部分。
pClientInfo->pGroup->chg_count++;
bSaveStorages = true;
}
if (pClientInfo->pStorage->psync_src_server == NULL)
{
memcpy(sync_src_id, pBody->src_id, \
FDFS_STORAGE_ID_MAX_SIZE);
sync_src_id[FDFS_STORAGE_ID_MAX_SIZE - 1] = '\0';
pClientInfo->pStorage->psync_src_server = \
tracker_mem_get_storage(pClientInfo->pGroup, \
sync_src_id);
if (pClientInfo->pStorage->psync_src_server == NULL)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}
if (pClientInfo->pStorage->psync_src_server->status == \
FDFS_STORAGE_STATUS_DELETED)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}
if (pClientInfo->pStorage->psync_src_server->status == \
FDFS_STORAGE_STATUS_IP_CHANGED)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}
pClientInfo->pStorage->sync_until_timestamp = \
(int)buff2long(pBody->until_timestamp);
bSaveStorages = true;
}
if (bSaveStorages)
{
tracker_save_storages();
}
pTask->length = sizeof(TrackerHeader);
return 0;
}
二、第二部分
1、tracker_report_thread_entrance及sync_old_done=0
sync_old_done=g_sync_old_done,且g_sync_old_done被初始化为false,所以下面这段代码是每个storage在首次加入集群时,必然执行的。
下面这段代码是tracker_report_thread_entrance中的一部分,可以看到它最后会调用会调用 src_storage_status[tracker_index] = tracker_sync_notify(pTrackerServer)。前面第一部分只考虑了sync_old_done=1的情况下。如果sync_old_done=0,则会先执行以下代码。
if (!sync_old_done)
{
if ((result=pthread_mutex_lock(&reporter_thread_lock)) \
!= 0)
{
fdfs_quit(pTrackerServer);
sleep(g_heart_beat_interval);
continue;
}
if (!g_sync_old_done)
{
if (tracker_sync_dest_req(pTrackerServer) == 0) //发送TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ命令至tracker,获得同步源g_sync_src_id和g_sync_until_timestamp。
{
g_sync_old_done = true;
if (storage_write_to_sync_ini_file() \
!= 0) //记录g_sync_old_done、g_sync_src_id、g_sync_until_timestamp至.data_init_flag文件中。
{
logCrit("file: "__FILE__", line: %d, " \
"storage_write_to_sync_ini_file"\
" fail, program exit!", \
__LINE__);
g_continue_flag = false;
pthread_mutex_unlock( \
&reporter_thread_lock);
break;
}
}
else //request failed or need to try again
{
pthread_mutex_unlock( \
&reporter_thread_lock);
fdfs_quit(pTrackerServer);
sleep(g_heart_beat_interval);
continue;
}
}
else
{
if (tracker_sync_notify(pTrackerServer) != 0)
{
pthread_mutex_unlock( \
&reporter_thread_lock);
fdfs_quit(pTrackerServer);
sleep(g_heart_beat_interval);
continue;
}
}
if ((result=pthread_mutex_unlock(&reporter_thread_lock))
!= 0)
{
}
sync_old_done = true;
}
src_storage_status[tracker_index] = \
tracker_sync_notify(pTrackerServer);
2、tracker的tracker_deal_storage_sync_dest_req
tracker接收到TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ命令时,就会执行tracker_deal_storage_sync_dest_req。它的作用就是设置目标storage server的状态为wait_sync,以及设置分配一个psync_src_server(用于同步的源storage sever)、sync_until_timestamp(为tracker的当前时间戳)。
static int tracker_deal_storage_sync_dest_req(struct fast_task_info *pTask)
{
TrackerStorageSyncReqBody *pBody;
FDFSStorageDetail *pSrcStorage;
FDFSStorageDetail **ppServer;
FDFSStorageDetail **ppServerEnd;
int sync_until_timestamp;
int source_count;
TrackerClientInfo *pClientInfo;
pClientInfo = (TrackerClientInfo *)pTask->arg;
pSrcStorage = NULL;
sync_until_timestamp = (int)g_current_time;
do
{
if (pTask->length - sizeof(TrackerHeader) != 0)
{
logError("file: "__FILE__", line: %d, " \
"cmd=%d, client ip: %s, package size " \
PKG_LEN_PRINTF_FORMAT" is not correct, " \
"expect length: 0", \
__LINE__, TRACKER_PROTO_CMD_STORAGE_SYNC_DEST_REQ, \
pTask->client_ip, pTask->length - \
(int)sizeof(TrackerHeader));
pTask->length = sizeof(TrackerHeader);
return EINVAL;
}
if (pClientInfo->pGroup->count <= 1)
{
break;
}
source_count = 0;
ppServerEnd = pClientInfo->pGroup->all_servers + \
pClientInfo->pGroup->count;
for (ppServer=pClientInfo->pGroup->all_servers; \
ppServer<ppServerEnd; ppServer++)
{
if (strcmp((*ppServer)->id, \
pClientInfo->pStorage->id) == 0)
{
continue;
}
if ((*ppServer)->status ==FDFS_STORAGE_STATUS_OFFLINE
|| (*ppServer)->status == FDFS_STORAGE_STATUS_ONLINE
|| (*ppServer)->status == FDFS_STORAGE_STATUS_ACTIVE)
{
source_count++;
}
}
if (source_count == 0)
{
break;
}
pSrcStorage = tracker_get_group_sync_src_server( \
pClientInfo->pGroup, pClientInfo->pStorage);
if (pSrcStorage == NULL)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}
pBody=(TrackerStorageSyncReqBody *)(pTask->data+sizeof(TrackerHeader));
strcpy(pBody->src_id, pSrcStorage->id);
long2buff(sync_until_timestamp, pBody->until_timestamp);
} while (0);
if (pSrcStorage == NULL)
{
pClientInfo->pStorage->status = \
FDFS_STORAGE_STATUS_ONLINE;
pClientInfo->pGroup->chg_count++;
tracker_save_storages();
pTask->length = sizeof(TrackerHeader);
return 0;
}
pClientInfo->pStorage->psync_src_server = pSrcStorage;
pClientInfo->pStorage->sync_until_timestamp = sync_until_timestamp; //sync_until_timestamp = (int)g_current_time;
pClientInfo->pStorage->status = FDFS_STORAGE_STATUS_WAIT_SYNC; //对应的storage server状态变为wait_sync。
pClientInfo->pGroup->chg_count++;
tracker_save_storages();
pTask->length = sizeof(TrackerHeader)+sizeof(TrackerStorageSyncReqBody);
return 0;
}
三、第三部分:总结
我是在一台机子上启动的两个storage server,如果不做改动,这两个server之间是不会同步的。同时,第二个启动的storage server创建了/data/.data_init_flag,且设置g_sync_src_id为空。
后来我改写了is_local_host_ip检测,使得两个同台机子上的storage server会同步,同步完成后/data/.data_init_flag中的sync_old_done为1(以后启动时,会读取该参数。我应该没有注意到这次wait_sync状态的进入)。这样,后来启动的server再也不会进入wait_sync状态了(sync_old_done为1,g_sync_src_id为空)。只有删除这个.data_init_flag才行。这个状态废了我好大的劲。
但是问题并没有结束,改了is_local_host_ip函数之后,使得在给need_sync_old值,又会出现问题。所以最终结论是最好将两个storage server放在不同的机器上。不然测试会出现奇怪的问题。