2、storage主流程

一、概要

客户端和Storage server主动连接Tracker server。Storage server主动向Tracker server报告其状态信息,包括磁盘剩余空间、文件同步状况、文件上传下载次数等统计信息。Storage server会连接集群中所有的Tracker server,向他们报告自己的状态。Storage server启动一个单独的线程来完成对一台Tracker server的连接和定时报告。需要说明的是,一个组包含的Storage server不是通过配置文件设定的,而是通过Tracker server获取到的。

不同组的Storage server之间不会相互通信,同组内的Storage server之间会相互连接进行文件同步。

Storage server采用binlog文件记录文件上传、删除等更新操作。binlog中只记录文件名,不记录文件内容。

文件同步只在同组内的Storage server之间进行,采用push方式,即源头服务器同步给目标服务器。只有源头数据才需要同步,备份数据并不需要再次同步,否则就构成环路了。

Storage server中由专门的线程根据binlog进行文件同步。为了最大程度地避免相互影响以及出于系统简洁性考虑,Storage server对组内除自己以外的每台服务器都会启动一个线程来进行文件同步

二、storage_func_init

前半部分用于解析配置文件。

	//后半部分如下:
	if ((result=storage_get_my_tracker_client_ip()) != 0) //与各个tracker连接后,调用fdfs_quit(pTServer),然后关闭套接字(这只是为了初始化g_tracker_client_ip)
	{
		return result;
	}

	if ((result=storage_check_and_make_data_dirs()) != 0) //解析.data_init_flag文件,并在data_path文件夹下创建大量文件夹。
	{
		logCrit("file: "__FILE__", line: %d, " \
			"storage_check_and_make_data_dirs fail, " \
			"program exit!", __LINE__);
		return result;
	}

	if ((result=storage_get_params_from_tracker()) != 0) //重新建立连接,向tracker请求TRACKER_PROTO_CMD_STORAGE_PARAMETER_REQ,获得use_storage_id等多个参数。
	{
		return result;
	}

	if ((result=tracker_get_my_server_id()) != 0) //设置g_tracker_client_ip
	{
		logCrit("file: "__FILE__", line: %d, " \
			"get my server id from tracker server fail, " \
			"errno: %d, error info: %s", __LINE__, \
			result, STRERROR(result));
		return result;
	}

	if (g_use_storage_id) //本例为0
	{
		if ((result=fdfs_get_storage_ids_from_tracker_group( \
				&g_tracker_group)) != 0)
		{
			return result;
		}
	}

	if ((result=storage_check_ip_changed()) != 0)
	{
		return result;
	}

	if ((result=init_pthread_lock(&sync_stat_file_lock)) != 0)
	{
		return result;
	}

	return storage_open_stat_file();
}


三、tracker_sync_init

初始化g_binlog_index和g_binlog_fd。注意:Storage server采用binlog文件记录文件上传、删除等更新操作(只记录文件名,不记录文件内容)。


四、tracker_report_init

g_storage_servers和g_sorted_storage清零,初始化reporter_thread_lock。


五、storage_service_init

与tracker_serverce_init类似,free_queue_init;创建四个线程work_thread_entrance(管道可读事件加入libevent监听,处理函数为storage_recv_notify_read,并不断等待),每个线程分配一个storage_nio_thread_data结构体。


六、tracker_report_thread_start
对每一个tracker(保存在g_tracker_group.servers中),创建一个report线程(处理函数为tracker_report_thread_entrance),以及src_storage_status变量(int)和my_report_status变量(signed char)。

tracker_report_thread_entrance部分代码如下:

                ......
		if (tracker_report_join(pTrackerServer, tracker_index, \
					sync_old_done) != 0)  //向tracker发送TRACKER_PROTO_CMD_STORAGE_JOIN消息,my_report_status[tracker_index]记录返回状态。
		{
			sleep(g_heart_beat_interval);
			continue;
		}
                ......
		if (!sync_old_done)
		{
		}

		src_storage_status[tracker_index] = \
					tracker_sync_notify(pTrackerServer);//向tracker发送TRACKER_PROTO_CMD_STORAGE_SYNC_NOTIFY。
		if (src_storage_status[tracker_index] != 0)
		{
			int k;
			for (k=0; k= \
					g_heart_beat_interval)
			{
				if (tracker_heart_beat(pTrackerServer, \
					&stat_chg_sync_count, \
					&bServerPortChanged) != 0) //发送TRACKER_PROTO_CMD_STORAGE_BEAT至tracker,获得leader tracker和所有其他tracker的信息,并更新本地信息。
				{
					break;
				}

				if (g_storage_ip_changed_auto_adjust && \
					tracker_storage_changelog_req( \
						pTrackerServer) != 0)
				{
					break;
				}

				last_beat_time = current_time;
			}

			if (sync_time_chg_count != g_sync_change_count && \
				current_time - last_sync_report_time >= \
					g_heart_beat_interval)
			{
				if (tracker_report_sync_timestamp( \
					pTrackerServer, &bServerPortChanged)!=0) 
				{
					break;
				}

				sync_time_chg_count = g_sync_change_count;
				last_sync_report_time = current_time;
			}

			if (current_time - last_df_report_time >= \
					g_stat_report_interval)
			{
				if (tracker_report_df_stat(pTrackerServer, \
						&bServerPortChanged) != 0)  //发送TRACKER_PROTO_CMD_STORAGE_REPORT_DISK_USAGE命令。
				{
					break;
				}

				last_df_report_time = current_time;
			}

			if (g_if_trunker_self)
			{
			if (last_trunk_file_id < g_current_trunk_file_id)
			{
				if (tracker_report_trunk_fid(pTrackerServer)!=0)
				{
					break;
				}
				last_trunk_file_id = g_current_trunk_file_id;
			}

			if (last_trunk_total_free_space != g_trunk_total_free_space)
			{
			if (tracker_report_trunk_free_space(pTrackerServer)!=0)
			{
				break;
			}
			last_trunk_total_free_space = g_trunk_total_free_space;
			}
			}

			sleep(1);
		}

		if ((!g_continue_flag) && fdfs_quit(pTrackerServer) != 0)
		{
		}

		close(pTrackerServer->sock);
		pTrackerServer->sock = -1;
		if (g_continue_flag)
		{
			sleep(1);
		}
	}

	if (nContinuousFail > 0)
	{
	}

	thracker_report_thread_exit(pTrackerServer);

	return NULL;
}

七、sched_start

产生一个调度线程,调度以下任务:log_sync_func,fdfs_binlog_sync_func,fdfs_stat_file_sync_func,以及可能存在的trunk_binlog_sync_fun,log_sync_func(&g_access_log_contex),log_notify_rotate。


八、storage_dio_init

为每一个store_path(本例的storage只有一个store_path)创建一个读线程和一个写线程。线程的处理函数都是dio_thread_entrance

static void *dio_thread_entrance(void* arg) 
{
	int result;
	struct storage_dio_context *pContext; 
	struct fast_task_info *pTask;

	pContext = (struct storage_dio_context *)arg; 

	pthread_mutex_lock(&(pContext->lock));
	while (g_continue_flag)
	{
		if ((result=pthread_cond_wait(&(pContext->cond), \
			&(pContext->lock))) != 0)   //等待被唤醒。
		{
		}

		while ((pTask=task_queue_pop(&(pContext->queue))) != NULL)
		{
			((StorageClientInfo *)pTask->arg)->deal_func(pTask); //处理读写任务
		}
	}
	pthread_mutex_unlock(&(pContext->lock));

	if ((result=pthread_mutex_lock(&g_dio_thread_lock)) != 0)
	{
	}
	g_dio_thread_count--;
	if ((result=pthread_mutex_unlock(&g_dio_thread_lock)) != 0)
	{
	}

	return NULL;
}

九、storage_accept_loop

监听是否有连接到来,如果有,则向一个工作线程发送一个信息(fast_task_info结构的地址),从而交给工作线程处理。


十、总结

storage使用4个工作线程(work_thread_entrance,当管道可读事件触发时,调用storage_recv_notify_read),每个tracker一个report线程(tracker_report_thread_entrance),一个调度线程(调度一些同步任务),每个store_path分别一个读写线程(dio_thread_entrance)。

你可能感兴趣的:(Fastdfs)