fastdfs之upload源码解析

1. upload简介
fastdfs集群上传文件,由client发起。client先连接tracker,获取目标storage和存储相关信息;连接目标storage,上传文件。
2. client upload源代码解析
2.1 upload_file函数
根据client upload流程提炼出的代码为:
int upload_file(const char* local_filename)
{
int result;
ConnectionInfo *pTrackerServer;
ConnectionInfo *pStorageServer;
ConnectionInfo storageServer;
int store_path_index = 0;
char group_name[FDFS_GROUP_NAME_MAX_LEN + 1];
char remote_filename[256];
FDFSMetaData meta_list[32];
int meta_count;
const char *file_ext_name;

/* 连接tracker [client/tracker_client.c]
根据配置文件的tracker服务组:g_tracker_group,和轮询tracker服务指向标志:server_index,尝试连接tracker。如果连接成功,返回连接上的tracker服务;如果不成功,自增server_index,尝试连接。如果轮询全部,连接不上,返回NULL。
*/
pTrackerServer = tracker_get_connection();
if (pTrackerServer == NULL)
{
return errno != 0 ? errno : ECONNREFUSED;
}

*group_name = '\0';


/* 查询目标storage [client/tracker_client.c]
发送命令:TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE,从tracker获取storage ip地址和端口号,组名,挂载点指向标志。
*/
if ((result=tracker_query_storage_store(pTrackerServer, \
&storageServer, group_name, &store_path_index)) != 0)
{
/* 断开tracker服务连接 */
tracker_disconnect_server_ex(pTrackerServer, true);
return result;
}

printf("group_name=%s, ip_addr=%s, port=%d\n", \
group_name, storageServer.ip_addr, \
storageServer.port);

/* 连接storage [tracker/tracker_proto.c]
根据storage的ip_addr和port,client用socket无阻塞模式连接storage。
*/
if ((pStorageServer=tracker_connect_server(&storageServer, \
&result)) == NULL)
{
/* 断开tracker服务连接 */
tracker_disconnect_server_ex(pTrackerServer, true);
return result;
}

// 需上传文件的文件属性
memset(&meta_list, 0, sizeof(meta_list));
meta_count = 0;
strcpy(meta_list[meta_count].name, "ext_name");
strcpy(meta_list[meta_count].value, "jpg");
meta_count++;
strcpy(meta_list[meta_count].name, "width");
strcpy(meta_list[meta_count].value, "160");
meta_count++;
strcpy(meta_list[meta_count].name, "height");
strcpy(meta_list[meta_count].value, "80");
meta_count++;
strcpy(meta_list[meta_count].name, "file_size");
strcpy(meta_list[meta_count].value, "115120");
meta_count++;

// 获取文件后缀
file_ext_name = fdfs_get_file_ext_name(local_filename);
*group_name = '\0';

/* 上传文件 [client/storage_client.c]
上传文件有三个模式:文件fd上传、缓存buf上传,回调callback上传。
这里用了文件fd上传,其特点是利用sendfile函数上传文件。先发送包头,其中命令为:STORAGE_PROTO_CMD_UPLOAD_FILE,再用sendfile发送文件内容。
*/
result = storage_upload_by_filename(pTrackerServer, \
pStorageServer, store_path_index, \
local_filename, file_ext_name, \
meta_list, meta_count, \
group_name, remote_filename);

printf("storage_upload_by_filename\n");

if (result != 0)
{
printf("upload file fail, " \
"error no: %d, error info: %s\n", \
result, STRERROR(result));
}

// 断开连接
tracker_disconnect_server_ex(pStorageServer, true);
tracker_disconnect_server_ex(pTrackerServer, true);
return result;
}
3. tracker upload相关源码解析
upload文件,需先连接tracker,再查询storage。其中连接是纯socket连接,不涉及业务,这里不做分析;查询storage:tracker_query_storage_store,发送了命令:TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE。
tracker在nio线程[tracker/tracker_nio.c]接收函数client_sock_read接收完后,调用tracker_deal_task [tracker/tracker_service.c]处理。
根据tracker_deal_task其中代码:
case TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITHOUT_GROUP_ONE:
result = tracker_deal_service_query_storage( \
pTask, pHeader->cmd);
break;
其调用了tracker_deal_service_query_storage [tracker/tracker_service.c]函数。
3.1 tracker_deal_service_query_storage函数
tracker/tracker_service.c
static int tracker_deal_service_query_storage( \
struct fast_task_info *pTask, char cmd)
{
int expect_pkg_len;
FDFSGroupInfo *pStoreGroup;
FDFSGroupInfo **ppFoundGroup;
FDFSGroupInfo **ppGroup;
FDFSStorageDetail *pStorageServer;
char *group_name;
char *p;
bool bHaveActiveServer;
int write_path_index;
int avg_reserved_mb;

/* 1. 判断接收包长
如果是携带组名的,应另加组名长度;如果是不携带组名的,另加应为0.
*/
if (cmd == TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE
|| cmd == TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL)
{
expect_pkg_len = FDFS_GROUP_NAME_MAX_LEN;
}
else
{
expect_pkg_len = 0;
}

if (pTask->length - sizeof(TrackerHeader) != expect_pkg_len)
{
logError("file: "__FILE__", line: %d, " \
"cmd=%d, client ip: %s, package size " \
PKG_LEN_PRINTF_FORMAT"is not correct, " \
"expect length: %d", __LINE__, \
cmd, pTask->client_ip, \
pTask->length - (int)sizeof(TrackerHeader), \
expect_pkg_len);
pTask->length = sizeof(TrackerHeader);
return EINVAL;
}

// 2. 获取storage组
// 如果不存在storage组,返回ENOENT。
if (g_groups.count == 0)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}

// 携带组名的请求
if (cmd == TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ONE
|| cmd == TRACKER_PROTO_CMD_SERVICE_QUERY_STORE_WITH_GROUP_ALL)
{
// 在接收到网络包中提取组名。
group_name = pTask->data + sizeof(TrackerHeader);
group_name[FDFS_GROUP_NAME_MAX_LEN] = '\0';

// 根据组名,获取组内的storage列表。
pStoreGroup = tracker_mem_get_group(group_name);
if (pStoreGroup == NULL)
{
logError("file: "__FILE__", line: %d, " \
"client ip: %s, invalid group name: %s", \
__LINE__, pTask->client_ip, group_name);
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}

// 判断storage组是否存在活动active的storage。
if (pStoreGroup->active_count == 0)
{
pTask->length = sizeof(TrackerHeader);
return ENOENT;
}

// 判断存储空间
if (!tracker_check_reserved_space(pStoreGroup))
{
// 存储空间不足,不使用“合并存储”,返回ENOSPCÿ
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值