9 storage的状态转换

一、第一部分

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放在不同的机器上。不然测试会出现奇怪的问题。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值