(三).storage_service.c
//上传文件完成后的回调函数 static void storage_upload_file_done_callback(struct fast_task_info *pTask,const int err_no) { StorageClientInfo *pClientInfo; StorageFileContext *pFileContext; TrackerHeader *pHeader; int result; pClientInfo = (StorageClientInfo *)pTask->arg; pFileContext = &(pClientInfo->file_context); if (err_no == 0) { //检查文件是否写重复,然后在修改文件名 result = storage_service_upload_file_done(pTask); if (result == 0) { if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE) { result = storage_binlog_write(/ pFileContext->timestamp2log, / STORAGE_OP_TYPE_SOURCE_CREATE_FILE, / pFileContext->fname2log); } } } else { result = err_no; }
if (result == 0) { int filename_len; char *p;
if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE) { //将total_upload_count,success_upload_count自增加 CHECK_AND_WRITE_TO_STAT_FILE3( / g_storage_stat.total_upload_count, / g_storage_stat.success_upload_count, / g_storage_stat.last_source_update) } //组返回包,返回组名,文件名 filename_len = strlen(pFileContext->fname2log); //重新设置了返回包的总长度 pClientInfo->total_length = sizeof(TrackerHeader) + FDFS_GROUP_NAME_MAX_LEN + filename_len; p = pTask->data + sizeof(TrackerHeader); memcpy(p, g_group_name, FDFS_GROUP_NAME_MAX_LEN); p += FDFS_GROUP_NAME_MAX_LEN; memcpy(p, pFileContext->fname2log, filename_len); } else { pthread_mutex_lock(&stat_count_thread_lock); if (pFileContext->create_flag & STORAGE_CREATE_FLAG_FILE) { g_storage_stat.total_upload_count++; //否则如果上传失败,上传总数加 } pthread_mutex_unlock(&stat_count_thread_lock); pClientInfo->total_length = sizeof(TrackerHeader); } pClientInfo->total_offset = 0; //total_offset被重新设置为 pTask->length = pClientInfo->total_length; pHeader = (TrackerHeader *)pTask->data; pHeader->status = result; pHeader->cmd = STORAGE_PROTO_CMD_RESP; long2buff(pClientInfo->total_length - sizeof(TrackerHeader),pHeader->pkg_len); //在次触发事件void storage_recv_notify_read()而在接收最后一个包时pClientInfo->stage = FDFS_STORAGE_STAGE_NIO_SEND //已经更改了这个状态值,因此在该函数里面,直接去调用storage_send_add_event(pTask)函数,发送响应包 storage_nio_notify(pTask); }
//数据服务器服务初始化 int storage_service_init() { int result; struct storage_nio_thread_data *pThreadData; struct storage_nio_thread_data *pDataEnd; pthread_t tid; pthread_attr_t thread_attr;
if ((result=init_pthread_lock(&g_storage_thread_lock)) != 0) { return result; } if ((result=init_pthread_lock(&path_index_thread_lock)) != 0) { return result; } if ((result=init_pthread_lock(&stat_count_thread_lock)) != 0) { return result; } if ((result=init_pthread_attr(&thread_attr, g_thread_stack_size)) != 0) { logError("file: "__FILE__", line: %d, " / "init_pthread_attr fail, program exit!", __LINE__); return result; } //StorageClientInfo参数所以说在任务Task结构里面用void * 参数来代替 //g_buff_size缺省是K if ((result=free_queue_init(g_max_connections, g_buff_size, / g_buff_size, sizeof(StorageClientInfo))) != 0) { return result; } //分配工作线程空间 //需要注意的是socket工作线程跟磁盘io线程的是分开的 g_nio_thread_data = (struct storage_nio_thread_data *)malloc(sizeof( / struct storage_nio_thread_data) * g_work_threads); if (g_nio_thread_data == NULL) { logError("file: "__FILE__", line: %d, " / "malloc %d bytes fail, errno: %d, error info: %s", / __LINE__, (int)sizeof(struct storage_nio_thread_data) * / g_work_threads, errno, strerror(errno)); return errno != 0 ? errno : ENOMEM; } g_storage_thread_count = 0; pDataEnd = g_nio_thread_data + g_work_threads; for (pThreadData=g_nio_thread_data; pThreadData<pDataEnd; pThreadData++) { pThreadData->ev_base = event_base_new(); if (pThreadData->ev_base == NULL) { result = errno != 0 ? errno : ENOMEM; logError("file: "__FILE__", line: %d, " / "event_base_new fail.", __LINE__); return result; } if (pipe(pThreadData->pipe_fds) != 0) { result = errno != 0 ? errno : EPERM; logError("file: "__FILE__", line: %d, " / "call pipe fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); break; } if ((result=set_nonblock(pThreadData->pipe_fds[0])) != 0) { break; } //创建线程 if ((result=pthread_create(&tid, &thread_attr,work_thread_entrance, pThreadData)) != 0) { logError("file: "__FILE__", line: %d, " / "create thread failed, startup threads: %d, " / "errno: %d, error info: %s", / __LINE__, g_storage_thread_count, / result, strerror(result)); break; } else { if ((result=pthread_mutex_lock(&g_storage_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } g_storage_thread_count++; if ((result=pthread_mutex_unlock(&g_storage_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } } } pthread_attr_destroy(&thread_attr); last_stat_change_count = g_stat_change_count; return result; }
//数据服务器作为客户端监听socket请求 //具体的实现流程是: //1.创建工作线程,每个在工作线程里面,绑定socket读写事件 //2.数据服务器服务端监听客户端请求,接收到请求后,从任务队列表取一个任务(从头部取),然后 // pClientInfo->stage = FDFS_STORAGE_STAGE_NIO_INIT; // pClientInfo->nio_thread_index = pClientInfo->sock % g_work_threads;//工作线程取余数 // pThreadData = g_nio_thread_data + pClientInfo->nio_thread_index; //确定是哪一个工作线程 // write(pThreadData->pipe_fds[1], &task_addr, sizeof(task_addr)) //向那一个工作线程写入事件(其实是写的任务) //3.然后触发socket读的事件,注意读的也是Task任务 void storage_accept_loop(int server_sock) { int incomesock; struct sockaddr_in inaddr; unsigned int sockaddr_len; in_addr_t client_addr; char szClientIp[IP_ADDRESS_SIZE]; long task_addr; struct fast_task_info *pTask; StorageClientInfo *pClientInfo; struct storage_nio_thread_data *pThreadData; while (g_continue_flag) { sockaddr_len = sizeof(inaddr); incomesock = accept(server_sock, (struct sockaddr*)&inaddr, / &sockaddr_len); if (incomesock < 0) //error { if (!(errno == EINTR || errno == EAGAIN)) { logError("file: "__FILE__", line: %d, " / "accept failed, " / "errno: %d, error info: %s", / __LINE__, errno, strerror(errno)); }
continue; } client_addr = getPeerIpaddr(incomesock, szClientIp, IP_ADDRESS_SIZE); //判断是否允许在可连接的地址列表里面 if (g_allow_ip_count >= 0) { if (bsearch(&client_addr, g_allow_ip_addrs, / g_allow_ip_count, sizeof(in_addr_t), / cmp_by_ip_addr_t) == NULL) { logError("file: "__FILE__", line: %d, " / "ip addr %s is not allowed to access", / __LINE__, szClientIp);
close(incomesock); continue; } }
if (tcpsetnonblockopt(incomesock) != 0) { close(incomesock); continue; } pTask = free_queue_pop(); if (pTask == NULL) { logError("file: "__FILE__", line: %d, " / "malloc task buff failed", / __LINE__); close(incomesock); continue; } //在这里对pTask->arg的参数进行了赋值 pClientInfo = (StorageClientInfo *)pTask->arg; pClientInfo->sock = incomesock; pClientInfo->stage = FDFS_STORAGE_STAGE_NIO_INIT; pClientInfo->nio_thread_index = pClientInfo->sock % g_work_threads;//工作线程取余数:一个nio,一个dio pThreadData = g_nio_thread_data + pClientInfo->nio_thread_index; strcpy(pTask->client_ip, szClientIp); strcpy(pClientInfo->tracker_client_ip, szClientIp); //使用的这种方法 task_addr = (long)pTask; if (write(pThreadData->pipe_fds[1], &task_addr, / sizeof(task_addr)) != sizeof(task_addr)) { close(incomesock); free_queue_push(pTask); logError("file: "__FILE__", line: %d, " / "call write failed, " / "errno: %d, error info: %s", / __LINE__, errno, strerror(errno)); } } }
void storage_nio_notify(struct fast_task_info *pTask) { StorageClientInfo *pClientInfo; struct storage_nio_thread_data *pThreadData; long task_addr; pClientInfo = (StorageClientInfo *)pTask->arg; //去取工作线程,在写入客户端socket pThreadData = g_nio_thread_data + pClientInfo->nio_thread_index; task_addr = (long)pTask; if (write(pThreadData->pipe_fds[1], &task_addr, / sizeof(task_addr)) != sizeof(task_addr)) { logError("file: "__FILE__", line: %d, " / "call write failed, " / "errno: %d, error info: %s", / __LINE__, errno, strerror(errno)); task_finish_clean_up(pTask); } }
//工作线程入口 static void *work_thread_entrance(void* arg) { int result; struct storage_nio_thread_data *pThreadData; struct event ev_notify;
pThreadData = (struct storage_nio_thread_data *)arg; //暂时先不考虑是否检查文件是否重复 if (g_check_file_duplicate) { if ((result=fdht_copy_group_array(&(pThreadData->group_array),/ &g_group_array)) != 0) { pthread_mutex_lock(&g_storage_thread_lock); g_storage_thread_count--; pthread_mutex_unlock(&g_storage_thread_lock); return NULL; } } do { event_set(&ev_notify, pThreadData->pipe_fds[0], / EV_READ | EV_PERSIST, storage_recv_notify_read, NULL); if ((result=event_base_set(pThreadData->ev_base, &ev_notify)) != 0) { logCrit("file: "__FILE__", line: %d, " / "event_base_set fail.", __LINE__); break; } if ((result=event_add(&ev_notify, NULL)) != 0) { logCrit("file: "__FILE__", line: %d, " / "event_add fail.", __LINE__); break; } //调用libevent库实现socket读写 while (g_continue_flag) { event_base_loop(pThreadData->ev_base, 0); } } while (0);
event_base_free(pThreadData->ev_base);
if (g_check_file_duplicate) { if (g_keep_alive) { fdht_disconnect_all_servers(&(pThreadData->group_array)); }
fdht_free_group_array(&(pThreadData->group_array)); }
if ((result=pthread_mutex_lock(&g_storage_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } g_storage_thread_count--; if ((result=pthread_mutex_unlock(&g_storage_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); }
logDebug("file: "__FILE__", line: %d, " / "nio thread exited, thread count: %d", / __LINE__, g_storage_thread_count);
return NULL; }
//发送的时候,先发送包头,接收的时候也是这样,在发包体,服务端也在次来接收包体 static int storage_upload_file(struct fast_task_info *pTask) { StorageClientInfo *pClientInfo; StorageFileContext *pFileContext; char *p; char filename[128]; char file_ext_name[FDFS_FILE_PREFIX_MAX_LEN + 1]; int64_t nInPackLen; int64_t file_bytes; int store_path_index; int result; int filename_len; pClientInfo = (StorageClientInfo *)pTask->arg; pFileContext = &(pClientInfo->file_context); nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader);
if (nInPackLen < 1 + FDFS_PROTO_PKG_LEN_SIZE + FDFS_FILE_EXT_NAME_MAX_LEN) { logError("file: "__FILE__", line: %d, " / "cmd=%d, client ip: %s, package size " / INT64_PRINTF_FORMAT" is not correct, " / "expect length >= %d", __LINE__, / STORAGE_PROTO_CMD_UPLOAD_FILE, / pTask->client_ip, nInPackLen, / 1 + FDFS_PROTO_PKG_LEN_SIZE + / FDFS_FILE_EXT_NAME_MAX_LEN); pClientInfo->total_length = sizeof(TrackerHeader); return EINVAL; } p = pTask->data + sizeof(TrackerHeader); //首先取目录存储路径索引下标 store_path_index = *p++; if (store_path_index < 0 || store_path_index >= g_path_count) { logError("file: "__FILE__", line: %d, " / "client ip: %s, store_path_index: %d " / "is invalid", __LINE__, / pTask->client_ip, store_path_index); pClientInfo->total_length = sizeof(TrackerHeader); return EINVAL; } //再取文件长度(注释是整个的长度) file_bytes = buff2long(p); p += FDFS_PROTO_PKG_LEN_SIZE; if (file_bytes < 0 || file_bytes != nInPackLen - / (1 + FDFS_PROTO_PKG_LEN_SIZE + / FDFS_FILE_EXT_NAME_MAX_LEN)) { logError("file: "__FILE__", line: %d, " / "client ip: %s, pkg length is not correct, " / "invalid file bytes: "INT64_PRINTF_FORMAT / ", total body length: "INT64_PRINTF_FORMAT, / __LINE__, pTask->client_ip, file_bytes, nInPackLen); pClientInfo->total_length = sizeof(TrackerHeader); return EINVAL; } memcpy(file_ext_name, p, FDFS_FILE_EXT_NAME_MAX_LEN); *(file_ext_name + FDFS_FILE_EXT_NAME_MAX_LEN) = '/0'; p += FDFS_FILE_EXT_NAME_MAX_LEN; pFileContext->calc_file_hash = g_check_file_duplicate; pFileContext->extra_info.upload.gen_filename = true; //默认生成文件名 pFileContext->extra_info.upload.start_time = time(NULL); *filename = '/0'; filename_len = 0; if ((result=storage_get_filename(pClientInfo, / pFileContext->extra_info.upload.start_time, / store_path_index, file_bytes, file_ext_name, filename, / &filename_len, pFileContext->filename)) != 0) { pClientInfo->total_length = sizeof(TrackerHeader); return result; } sprintf(pFileContext->fname2log, "%c"STORAGE_DATA_DIR_FORMAT"/%s",FDFS_STORAGE_STORE_PATH_PREFIX_CHAR, store_path_index, filename); strcpy(pFileContext->extra_info.upload.file_ext_name, file_ext_name); pFileContext->sync_flag = STORAGE_OP_TYPE_SOURCE_CREATE_FILE; pFileContext->timestamp2log = pFileContext->extra_info.upload.start_time; pFileContext->extra_info.upload.store_path_index = store_path_index; pFileContext->op = FDFS_STORAGE_FILE_OP_WRITE; //写文件 //参数:任务指针,0 文件偏移量;file_bytes:文件的字节数p - pTask->data:相对于pTask->data的偏移量 return storage_write_to_file(pTask, 0, file_bytes, p - pTask->data,storage_upload_file_done_callback, store_path_index); }
//从数据服务器上下载文件 static int storage_server_download_file(struct fast_task_info *pTask) { StorageClientInfo *pClientInfo; StorageFileContext *pFileContext; char *p; int result; int store_path_index; char group_name[FDFS_GROUP_NAME_MAX_LEN + 1]; char true_filename[128]; char *filename; int filename_len; int64_t file_offset; int64_t download_bytes; int64_t file_bytes; struct stat stat_buf; int64_t nInPackLen; pClientInfo = (StorageClientInfo *)pTask->arg; pFileContext = &(pClientInfo->file_context); //实际上在接收包的过程中,设置了pClientInfo->total_length=pClientInfo->total_length+sizeof(TrackerHeader) //因此这里在重新减回去 nInPackLen = pClientInfo->total_length - sizeof(TrackerHeader); pClientInfo->total_length = sizeof(TrackerHeader); if (nInPackLen <= 16 + FDFS_GROUP_NAME_MAX_LEN) { logError("file: "__FILE__", line: %d, " / "cmd=%d, client ip: %s, package size " / INT64_PRINTF_FORMAT" is not correct, " / "expect length > %d", __LINE__, / STORAGE_PROTO_CMD_UPLOAD_FILE, / pTask->client_ip, / nInPackLen, 16 + FDFS_GROUP_NAME_MAX_LEN); return EINVAL; } if (nInPackLen >= pTask->size) { logError("file: "__FILE__", line: %d, " / "cmd=%d, client ip: %s, package size " / INT64_PRINTF_FORMAT" is too large, " / "expect length should < %d", __LINE__, / STORAGE_PROTO_CMD_UPLOAD_FILE, / pTask->client_ip, / nInPackLen, pTask->size); return EINVAL; } p = pTask->data + sizeof(TrackerHeader); //文件偏移量:下载传来的请求包里面值是 file_offset = buff2long(p); p += FDFS_PROTO_PKG_LEN_SIZE; download_bytes = buff2long(p); //需要下载的字节数 p += FDFS_PROTO_PKG_LEN_SIZE; if (file_offset < 0) { logError("file: "__FILE__", line: %d, " / "client ip:%s, invalid file offset: " / INT64_PRINTF_FORMAT, __LINE__, / pTask->client_ip, file_offset); return EINVAL; } if (download_bytes < 0) { logError("file: "__FILE__", line: %d, " / "client ip:%s, invalid download file bytes: " / INT64_PRINTF_FORMAT, __LINE__, / pTask->client_ip, download_bytes); return EINVAL; } memcpy(group_name, p, FDFS_GROUP_NAME_MAX_LEN); *(group_name + FDFS_GROUP_NAME_MAX_LEN) = '/0'; p += FDFS_GROUP_NAME_MAX_LEN; if (strcmp(group_name, g_group_name) != 0) { logError("file: "__FILE__", line: %d, " / "client ip:%s, group_name: %s " / "not correct, should be: %s", / __LINE__, pTask->client_ip, / group_name, g_group_name); return EINVAL; } filename = p; filename_len = nInPackLen - (16 + FDFS_GROUP_NAME_MAX_LEN); *(filename + filename_len) = '/0'; //拆分文件名,确定store_path_index磁盘目录索引值 if ((result=storage_split_filename_ex(filename, / &filename_len, true_filename, &store_path_index)) != 0) { return result; } if ((result=fdfs_check_data_filename(true_filename, filename_len)) != 0) { return result; } //在这里就直接确定了磁盘的目录名 sprintf(pFileContext->filename, "%s/data/%s",g_store_paths[store_path_index], true_filename); if (stat(pFileContext->filename, &stat_buf) == 0) { if (!S_ISREG(stat_buf.st_mode)) { logError("file: "__FILE__", line: %d, " / "%s is not a regular file", / __LINE__, pFileContext->filename); return EISDIR; } file_bytes = stat_buf.st_size; } else { file_bytes = 0; result = errno != 0 ? errno : ENOENT;
logError("file: "__FILE__", line: %d, " / "call stat fail, file: %s, "/ "error no: %d, error info: %s", / __LINE__, pFileContext->filename, / result, strerror(result)); return result; } //请求下载文件发来的包里面,下载字节数填写的是download_bytes=0,那么下载的字节数就是文件本身的字节大小 //并且文件偏移量file_offset=0 if (download_bytes == 0) { download_bytes = file_bytes - file_offset; } else if (download_bytes > file_bytes - file_offset) { logError("file: "__FILE__", line: %d, " / "client ip:%s, invalid download file bytes: " / INT64_PRINTF_FORMAT" > file remain bytes: " / INT64_PRINTF_FORMAT, __LINE__, / pTask->client_ip, download_bytes, / file_bytes - file_offset); return EINVAL; } return storage_read_from_file(pTask, file_offset,download_bytes,storage_download_file_done_callback, store_path_index); }
//从数据服务器读取文件 static int storage_read_from_file(struct fast_task_info *pTask, / const int64_t file_offset, const int64_t download_bytes, / FileDealDoneCallback done_callback, / const int store_path_index) { StorageClientInfo *pClientInfo; StorageFileContext *pFileContext; TrackerHeader *pHeader; int result; pClientInfo = (StorageClientInfo *)pTask->arg; pFileContext = &(pClientInfo->file_context); pClientInfo->deal_func = dio_deal_task; //在这里重新设置总的长度 pClientInfo->total_length = sizeof(TrackerHeader) + download_bytes; pClientInfo->total_offset = 0; pFileContext->fd = -1; pFileContext->op = FDFS_STORAGE_FILE_OP_READ; pFileContext->offset = file_offset; pFileContext->start = file_offset; pFileContext->end = file_offset + download_bytes; //获得磁盘ip读写的线程索引下标,从而确定是由哪个线程取进行读写的操作 pFileContext->dio_thread_index = storage_dio_get_thread_index(pTask, store_path_index, pFileContext->op); pFileContext->done_callback = done_callback; pTask->length = sizeof(TrackerHeader); //任务的数据长度重新进行了设置 pHeader = (TrackerHeader *)pTask->data; pHeader->status = 0; pHeader->cmd = STORAGE_PROTO_CMD_RESP; long2buff(download_bytes, pHeader->pkg_len); //这里连同包头+单片数据文件的包体一起进行了如磁盘线程的处理队列中 //客户端在接收时可以先指定接收包头,然后在接收后面的包体数据 if ((result=storage_dio_queue_push(pTask)) != 0) { pClientInfo->total_length = sizeof(TrackerHeader); return result; } return STORAGE_STATUE_DEAL_FILE; }
//数据服务器处理写文件 static int storage_write_to_file(struct fast_task_info *pTask, / const int64_t file_offset, const int64_t upload_bytes, / const int buff_offset, FileDealDoneCallback done_callback, / const int store_path_index) { StorageClientInfo *pClientInfo; StorageFileContext *pFileContext; int result; pClientInfo = (StorageClientInfo *)pTask->arg; pFileContext = &(pClientInfo->file_context); pClientInfo->deal_func = dio_deal_task; //处理任务函数指针 pFileContext->fd = -1; pFileContext->buff_offset = buff_offset; pFileContext->offset = file_offset; pFileContext->start = file_offset; pFileContext->end = file_offset + upload_bytes; //获得磁盘读写的线程 pFileContext->dio_thread_index = storage_dio_get_thread_index(pTask, store_path_index, pFileContext->op); pFileContext->done_callback = done_callback; //处理完成的回调函数 if (pFileContext->calc_file_hash) { INIT_HASH_CODES4(pFileContext->file_hash_codes) } //插入到磁盘处理队列中,而磁盘处理线程调用dio_thread_entrance()不断来处理队列里面的任务元素 if ((result=storage_dio_queue_push(pTask)) != 0) { pClientInfo->total_length = sizeof(TrackerHeader); return result; }
return STORAGE_STATUE_DEAL_FILE; }
|
(四).tracker_client_thread.c
//与跟踪服务器的报告线程 static void *tracker_report_thread_entrance(void *arg) { TrackerServerInfo *pTrackerServer; char tracker_client_ip[IP_ADDRESS_SIZE]; char szFailPrompt[36]; bool sync_old_done; int stat_chg_sync_count; int sync_time_chg_count; time_t current_time; time_t last_df_report_time; time_t last_sync_report_time; time_t last_beat_time; int result; int previousCode; int nContinuousFail; int tracker_index; bool bServerPortChanged; //判断数据服务器的端口是否改变 bServerPortChanged = (g_last_server_port != 0) &&(g_server_port != g_last_server_port); stat_chg_sync_count = 0; pTrackerServer = (TrackerServerInfo *)arg; pTrackerServer->sock = -1; //获得跟踪的下标 tracker_index = pTrackerServer - g_tracker_group.servers; logDebug("file: "__FILE__", line: %d, " / "report thread to tracker server %s:%d started", / __LINE__, pTrackerServer->ip_addr, pTrackerServer->port); //初始时g_sync_old_done=false sync_old_done = g_sync_old_done; //需要等待所有跟各个跟踪服务器的线程都启动,在去执行 while (g_continue_flag && g_tracker_reporter_count < g_tracker_group.server_count) { sleep(1); //waiting for all thread started } result = 0; previousCode = 0; nContinuousFail = 0; while (g_continue_flag) { if (pTrackerServer->sock >= 0) { //每次关闭,又重新进行连接 close(pTrackerServer->sock); } pTrackerServer->sock = socket(AF_INET, SOCK_STREAM, 0); if(pTrackerServer->sock < 0) { logCrit("file: "__FILE__", line: %d, " / "socket create failed, errno: %d, " / "error info: %s. program exit!", / __LINE__, errno, strerror(errno)); g_continue_flag = false; break; } if (g_client_bind_addr && *g_bind_addr != '/0') { socketBind(pTrackerServer->sock, g_bind_addr, 0); } //设置连接到跟踪服务器的网络超时时间,连接超时时间 tcpsetserveropt(pTrackerServer->sock, g_fdfs_network_timeout); if (tcpsetnonblockopt(pTrackerServer->sock) != 0) { nContinuousFail++; sleep(g_heart_beat_interval); //延时心跳间隔 continue; } //连接到跟踪服务器 if ((result=connectserverbyip_nb(pTrackerServer->sock,pTrackerServer->ip_addr,pTrackerServer->port,g_fdfs_connect_timeout)) != 0) { if (previousCode != result) { logError("file: "__FILE__", line: %d, " / "connect to tracker server %s:%d fail" / ", errno: %d, error info: %s", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, / result, strerror(result)); previousCode = result; } nContinuousFail++; if (g_continue_flag) { sleep(g_heart_beat_interval); continue; } else { break; } } getSockIpaddr(pTrackerServer->sock,tracker_client_ip, IP_ADDRESS_SIZE); if (nContinuousFail == 0) { *szFailPrompt = '/0'; } else { sprintf(szFailPrompt, ", continuous fail count: %d",nContinuousFail); } logInfo("file: "__FILE__", line: %d, " / "successfully connect to tracker server %s:%d%s, " / "as a tracker client, my ip is %s", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, szFailPrompt, tracker_client_ip); previousCode = 0; nContinuousFail = 0; //初始g_tracker_client_ip为空串 if (*g_tracker_client_ip == '/0') { strcpy(g_tracker_client_ip, tracker_client_ip); } else if (strcmp(tracker_client_ip, g_tracker_client_ip) != 0) { logError("file: "__FILE__", line: %d, " / "as a client of tracker server %s:%d, " / "my ip: %s != client ip: %s of other " / "tracker client", __LINE__, / pTrackerServer->ip_addr, pTrackerServer->port, / tracker_client_ip, g_tracker_client_ip);
close(pTrackerServer->sock); pTrackerServer->sock = -1; break; } //因为要连接多个跟踪服务器,每连接一个都会产生一个tracker_client_ip //因此插入这个g_local_host_ip_addrs 大串里面 insert_into_local_host_ip(tracker_client_ip); //向每一个跟踪服务器发起加入的请求 if (tracker_report_join(pTrackerServer, tracker_index, sync_old_done) != 0) { sleep(g_heart_beat_interval); continue; }
if (g_http_port != g_last_http_port) { g_last_http_port = g_http_port; if ((result=storage_write_to_sync_ini_file()) != 0) { } } if (!sync_old_done) { if ((result=pthread_mutex_lock(&reporter_thread_lock)) / != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); fdfs_quit(pTrackerServer); sleep(g_heart_beat_interval); continue; } //初始g_sync_old_done=false,如果旧的同步操作没有完成 if (!g_sync_old_done) { //获得向该storage server同步已有数据文件的源服务器请求 if (tracker_sync_dest_req(pTrackerServer) == 0) { g_sync_old_done = true; //获得源服务器请求完成后,旧的同步设为标记true //在写入同步状态的文件中 if (storage_write_to_sync_ini_file() / != 0) { 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) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_unlock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } sync_old_done = true; //旧的同步设为标记true } //获得源数据服务器的状态 src_storage_status[tracker_index] = tracker_sync_notify(pTrackerServer); if (src_storage_status[tracker_index] != 0) { int k; for (k=0; k<g_tracker_group.server_count; k++) { if (src_storage_status[k] != ENOENT) { break; } } //在这里是什么意思??? if (k == g_tracker_group.server_count) { //src storage server already be deleted int my_status; if (tracker_get_storage_status(&g_tracker_group, g_group_name, g_tracker_client_ip, &my_status) == 0) { tracker_sync_dest_query(pTrackerServer); if(my_status<FDFS_STORAGE_STATUS_OFFLINE && g_sync_old_done) { //need re-sync old files pthread_mutex_lock(&reporter_thread_lock); g_sync_old_done = false; sync_old_done = g_sync_old_done; storage_write_to_sync_ini_file(); pthread_mutex_unlock( &reporter_thread_lock); } } } fdfs_quit(pTrackerServer); sleep(g_heart_beat_interval); continue; } sync_time_chg_count = 0; last_df_report_time = 0; last_beat_time = 0; last_sync_report_time = 0; while (g_continue_flag) { current_time = time(NULL); //比较心跳的时间间隔 if (current_time - last_beat_time >= g_heart_beat_interval) { //发送心跳 if (tracker_heart_beat(pTrackerServer, / &stat_chg_sync_count, / &bServerPortChanged) != 0) { 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) { break; }
last_df_report_time = current_time; } 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) { logError("file: "__FILE__", line: %d, " / "connect to tracker server %s:%d fail, try count: %d" / ", errno: %d, error info: %s", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, nContinuousFail, / result, strerror(result)); } thracker_report_thread_exit(pTrackerServer); return NULL; }
//合并数据服务器:server_count参数:返回的数据服务器个数 static int tracker_merge_servers(TrackerServerInfo *pTrackerServer,FDFSStorageBrief *briefServers, const int server_count) { FDFSStorageBrief *pServer; FDFSStorageBrief *pEnd; FDFSStorageServer *pInsertedServer; FDFSStorageServer **ppFound; FDFSStorageServer **ppGlobalServer; FDFSStorageServer **ppGlobalEnd; FDFSStorageServer targetServer; FDFSStorageServer *pTargetServer; FDFSStorageBrief diffServers[FDFS_MAX_SERVERS_EACH_GROUP]; FDFSStorageBrief *pDiffServer; int res; int result; int nDeletedCount; memset(&targetServer, 0, sizeof(targetServer)); //pTargetServer指向它 pTargetServer = &targetServer; nDeletedCount = 0; pDiffServer = diffServers; //指向了指针数组 pEnd = briefServers + server_count; //storage server有个状态,如下: //FDFS_STORAGE_STATUS_INIT 0:初始化,尚未得到同步已有数据的源服务器 //FDFS_STORAGE_STATUS_WAIT_SYNC 1:等待同步,已得到同步已有数据的源服务器 //FDFS_STORAGE_STATUS_SYNCING 2:同步中 //FDFS_STORAGE_STATUS_DELETED 3:已删除,该服务器从本组中摘除(注:本状态的功能尚未实现) //FDFS_STORAGE_STATUS_OFFLINE 4:离线 //FDFS_STORAGE_STATUS_ONLINE 5:在线,尚不能提供服务 //FDFS_STORAGE_STATUS_ACTIVE 6:在线,可以提供服务 //FDFS_STORAGE_STATUS_NONE 99 //当storage server的状态为FDFS_STORAGE_STATUS_ONLINE时,当该storage server向tracker server发起一次heart beat时, //tracker server将其状态更改为FDFS_STORAGE_STATUS_ACTIVE。 //组内新增加一台storage server A时,由系统自动完成已有数据同步,处理逻辑如下: //1.storage server A连接tracker server,tracker server将storage server A的状态设置为FDFS_STORAGE_STATUS_INIT。storage server // A询问追加同步的源服务器和追加同步截至时间点,如果该组内只有storage serverA或该组内已成功上传的文件数为,则没有数据需要同步, // storage server A就可以提供在线服务,此时tracker将其状态设置为FDFS_STORAGE_STATUS_ONLINE,否则tracker server将其状态设置为 // FDFS_STORAGE_STATUS_WAIT_SYNC,进入第二步的处理; //2.假设tracker server分配向storage server A同步已有数据的源storage server为B。同组的storage server和tracker server通讯得知新 // 增了storage server A,将启动同步线程,并向tracker server询问向storage server A追加同步的源服务器和截至时间点。storage server // B将把截至时间点之前的所有数据同步给storage server A;而其余的storage server从截至时间点之后进行正常同步,只把源头数据同步 // 给storage server A。到了截至时间点之后,storage server B对storage server A的同步将由追加同步切换为正常同步,只同步源头数据; //3.storage server B向storage server A同步完所有数据,暂时没有数据要同步时,storage server B请求tracker server将storage server A的 // 状态设置为FDFS_STORAGE_STATUS_ONLINE; //4.当storage server A向tracker server发起heart beat时,tracker server将其状态更改为FDFS_STORAGE_STATUS_ACTIVE for (pServer=briefServers;pServer<pEnd;pServer++) { //拷贝targetServer.server memcpy(&(targetServer.server),pServer,sizeof(FDFSStorageBrief)); ppFound = (FDFSStorageServer **)bsearch(&pTargetServer,g_sorted_storages, g_storage_count,sizeof(FDFSStorageServer *),storage_cmp_by_ip_addr); //从排序的g_sorted_storages数据服务器列表进行查找 if (ppFound != NULL) { //logInfo("ip_addr=%s, local status: %d, tracker status: %d", pServer->ip_addr, (*ppFound)->server.status, pServer->status); //如果状态一致,不作处理 if ((*ppFound)->server.status == pServer->status) { continue; } //如果返回的是离线的状态 if (pServer->status == FDFS_STORAGE_STATUS_OFFLINE) { //与本地的状态进行比较 if ((*ppFound)->server.status == FDFS_STORAGE_STATUS_ACTIVE|| (*ppFound)->server.status == FDFS_STORAGE_STATUS_ONLINE) { //更新自己为离线的状态 (*ppFound)->server.status = FDFS_STORAGE_STATUS_OFFLINE; } else if ((*ppFound)->server.status != FDFS_STORAGE_STATUS_NONE&& (*ppFound)->server.status != FDFS_STORAGE_STATUS_INIT) { //将不同的数据服务器的状态进行拷贝 memcpy(pDiffServer++,&((*ppFound)->server),sizeof(FDFSStorageBrief)); } } else if ((*ppFound)->server.status == FDFS_STORAGE_STATUS_OFFLINE) { //如果本地是离线的状态,并且返回的状态不是离线状态,那么用新的返回的状态进行更新 (*ppFound)->server.status = pServer->status; } else if ((*ppFound)->server.status == FDFS_STORAGE_STATUS_NONE) //如果本地是未知的状态 { if (pServer->status == FDFS_STORAGE_STATUS_DELETED || pServer->status == FDFS_STORAGE_STATUS_IP_CHANGED) { //ignore } else { (*ppFound)->server.status = pServer->status; //如果本地是未知的状态,并且返回的不是删除状态,那么启动同步线程 if ((result=storage_sync_thread_start(&((*ppFound)->server))) != 0) { return result; } } } else if (((pServer->status==FDFS_STORAGE_STATUS_WAIT_SYNC)||(pServer->status==FDFS_STORAGE_STATUS_SYNCING))&&((*ppFound)->server.status>pServer->status)) { memcpy(pDiffServer++, &((*ppFound)->server), sizeof(FDFSStorageBrief)); } else { (*ppFound)->server.status = pServer->status; } } else if (pServer->status == FDFS_STORAGE_STATUS_DELETED|| pServer->status == FDFS_STORAGE_STATUS_IP_CHANGED) { //如果本地存在该数据服务器,返回的删除的暂时不做处理 nDeletedCount++; } else { //logInfo("ip_addr=%s, tracker status: %d", pServer->ip_addr, pServer->status); if ((res=pthread_mutex_lock(&reporter_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, "/ "call pthread_mutex_lock fail,"/ " errno: %d, error info: %s", / __LINE__, res, strerror(res)); } //在本地数据服务器列表找不到,那么它是新来的数据服务器 if (g_storage_count < FDFS_MAX_SERVERS_EACH_GROUP) { pInsertedServer = g_storage_servers + g_storage_count; memcpy(&(pInsertedServer->server), pServer, sizeof(FDFSStorageBrief)); if (tracker_insert_into_sorted_servers(pInsertedServer)) { g_storage_count++; } //在来启动同步线程:这个数据服务器是新加入的 result = storage_sync_thread_start(&(pInsertedServer->server)); } else { logError("file: "__FILE__", line: %d, " / "tracker server %s:%d, " / "storage servers of group /"%s/" " / "exceeds max: %d", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, / pTrackerServer->group_name, / FDFS_MAX_SERVERS_EACH_GROUP); result = ENOSPC; } if ((res=pthread_mutex_unlock( / &reporter_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, "/ "call pthread_mutex_unlock fail, " / "errno: %d, error info: %s", / __LINE__, res, strerror(res)); } if (result != 0) { return result; } } } if (g_storage_count + nDeletedCount == server_count) { if (pDiffServer - diffServers > 0) { return tracker_sync_diff_servers(pTrackerServer,diffServers, pDiffServer - diffServers); } return 0; } //比较得出发生改变的数据服务器:g_sorted_storages=本地的数据服务器briefServers=跟踪服务器返回的数据服务器 ppGlobalServer = g_sorted_storages; ppGlobalEnd = g_sorted_storages + g_storage_count; pServer = briefServers; while (pServer < pEnd && ppGlobalServer < ppGlobalEnd) { if ((*ppGlobalServer)->server.status == FDFS_STORAGE_STATUS_NONE) { ppGlobalServer++; continue; } res = strcmp(pServer->ip_addr, (*ppGlobalServer)->server.ip_addr); if (res < 0) { if (pServer->status != FDFS_STORAGE_STATUS_DELETED&& pServer->status != FDFS_STORAGE_STATUS_IP_CHANGED) { logError("file: "__FILE__", line: %d, " / "tracker server %s:%d, " / "group /"%s/", " / "enter impossible statement branch", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, / pTrackerServer->group_name); } //因为g_sorted_storages是已经排序好了(由大到小排序)的,所以直接查询pServer的下一个 pServer++; } else if (res == 0) { pServer++; ppGlobalServer++; } else { //显然ppGlobalServer后面都是小的,但pServer比ppGlobalServer大,因此不必在找下去了, //这一个直接就是不同的 memcpy(pDiffServer++, &((*ppGlobalServer)->server),sizeof(FDFSStorageBrief)); ppGlobalServer++; } } //这段代码有什么用??? while (ppGlobalServer < ppGlobalEnd) { if ((*ppGlobalServer)->server.status == FDFS_STORAGE_STATUS_NONE) { ppGlobalServer++; continue; } memcpy(pDiffServer++, &((*ppGlobalServer)->server),sizeof(FDFSStorageBrief)); ppGlobalServer++; } return tracker_sync_diff_servers(pTrackerServer,diffServers, pDiffServer - diffServers); }
//报告数据服务器磁盘容量 static int tracker_report_df_stat(TrackerServerInfo *pTrackerServer, / bool *bServerPortChanged) { char out_buff[sizeof(TrackerHeader) + / sizeof(TrackerStatReportReqBody) * 16]; char *pBuff; TrackerHeader *pHeader; TrackerStatReportReqBody *pStatBuff; struct statvfs sbuf; int body_len; int total_len; int i; int result; body_len = (int)sizeof(TrackerStatReportReqBody) * g_path_count; total_len = (int)sizeof(TrackerHeader) + body_len; if (total_len <= sizeof(out_buff)) { pBuff = out_buff; } else { pBuff = (char *)malloc(total_len); if (pBuff == NULL) { logError("file: "__FILE__", line: %d, " / "malloc %d bytes fail, " / "errno: %d, error info: %s", / __LINE__, total_len, / errno, strerror(errno)); return errno != 0 ? errno : ENOMEM; } } pHeader = (TrackerHeader *)pBuff; pStatBuff = (TrackerStatReportReqBody*) (pBuff + sizeof(TrackerHeader)); long2buff(body_len, pHeader->pkg_len); pHeader->cmd = TRACKER_PROTO_CMD_STORAGE_REPORT_DISK_USAGE; pHeader->status = 0; for (i=0; i<g_path_count; i++) { //直接调用取磁盘容量的函数 if (statvfs(g_store_paths[i], &sbuf) != 0) { logError("file: "__FILE__", line: %d, " / "call statfs fail, errno: %d, error info: %s.",/ __LINE__, errno, strerror(errno)); if (pBuff != out_buff) { free(pBuff); } return errno != 0 ? errno : EACCES; } long2buff((((int64_t)(sbuf.f_blocks) * sbuf.f_frsize) / FDFS_ONE_MB),/ pStatBuff->sz_total_mb); long2buff((((int64_t)(sbuf.f_bavail) * sbuf.f_frsize) / FDFS_ONE_MB),/ pStatBuff->sz_free_mb); pStatBuff++; } result = tcpsenddata_nb(pTrackerServer->sock, pBuff,total_len, g_fdfs_network_timeout); if (pBuff != out_buff) { free(pBuff); } if(result != 0) { logError("file: "__FILE__", line: %d, " / "tracker server %s:%d, send data fail, " / "errno: %d, error info: %s.", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, / result, strerror(result)); return result; } return tracker_check_response(pTrackerServer, bServerPortChanged); }
//向跟踪服务器发起心跳 static int tracker_heart_beat(TrackerServerInfo *pTrackerServer, / int *pstat_chg_sync_count, bool *bServerPortChanged) { char out_buff[sizeof(TrackerHeader) + sizeof(FDFSStorageStatBuff)]; TrackerHeader *pHeader; FDFSStorageStatBuff *pStatBuff; int body_len; int result; memset(out_buff, 0, sizeof(out_buff)); pHeader = (TrackerHeader *)out_buff; /*如果状态有发生改变*/ if (*pstat_chg_sync_count != g_stat_change_count) { pStatBuff = (FDFSStorageStatBuff *)(out_buff + sizeof(TrackerHeader)); long2buff(g_storage_stat.total_upload_count, / pStatBuff->sz_total_upload_count); long2buff(g_storage_stat.success_upload_count, / pStatBuff->sz_success_upload_count); long2buff(g_storage_stat.total_download_count, / pStatBuff->sz_total_download_count); long2buff(g_storage_stat.success_download_count, / pStatBuff->sz_success_download_count); long2buff(g_storage_stat.total_set_meta_count, / pStatBuff->sz_total_set_meta_count); long2buff(g_storage_stat.success_set_meta_count, / pStatBuff->sz_success_set_meta_count); long2buff(g_storage_stat.total_delete_count, / pStatBuff->sz_total_delete_count); long2buff(g_storage_stat.success_delete_count, / pStatBuff->sz_success_delete_count); long2buff(g_storage_stat.total_get_meta_count, / pStatBuff->sz_total_get_meta_count); long2buff(g_storage_stat.success_get_meta_count, / pStatBuff->sz_success_get_meta_count); long2buff(g_storage_stat.total_create_link_count, / pStatBuff->sz_total_create_link_count); long2buff(g_storage_stat.success_create_link_count, / pStatBuff->sz_success_create_link_count); long2buff(g_storage_stat.total_delete_link_count, / pStatBuff->sz_total_delete_link_count); long2buff(g_storage_stat.success_delete_link_count, / pStatBuff->sz_success_delete_link_count); long2buff(g_storage_stat.last_source_update, / pStatBuff->sz_last_source_update); long2buff(g_storage_stat.last_sync_update, / pStatBuff->sz_last_sync_update); *pstat_chg_sync_count = g_stat_change_count; //重新用全局变量赋值同步状态改变个数 body_len = sizeof(FDFSStorageStatBuff); } else { body_len = 0; } long2buff(body_len, pHeader->pkg_len); pHeader->cmd = TRACKER_PROTO_CMD_STORAGE_BEAT;
if((result=tcpsenddata_nb(pTrackerServer->sock, out_buff, / sizeof(TrackerHeader) + body_len, g_fdfs_network_timeout)) != 0) { logError("file: "__FILE__", line: %d, " / "tracker server %s:%d, send data fail, " / "errno: %d, error info: %s.", / __LINE__, pTrackerServer->ip_addr, / pTrackerServer->port, / result, strerror(result)); return result; } return tracker_check_response(pTrackerServer, bServerPortChanged); } //数据服务器启动向跟踪服务器的汇报线程 int tracker_report_thread_start() { TrackerServerInfo *pTrackerServer; TrackerServerInfo *pServerEnd; pthread_attr_t pattr; pthread_t tid; int result; if ((result=init_pthread_attr(&pattr, g_thread_stack_size)) != 0) { return result; } //获得跟踪服务器个数 report_tids = (pthread_t *)malloc(sizeof(pthread_t) * g_tracker_group.server_count); if (report_tids == NULL) { logError("file: "__FILE__", line: %d, " / "malloc %d bytes fail, " / "errno: %d, error info: %s", / __LINE__, (int)sizeof(pthread_t) * / g_tracker_group.server_count, / errno, strerror(errno)); return errno != 0 ? errno : ENOMEM; } memset(report_tids, 0, sizeof(pthread_t)*g_tracker_group.server_count); //源数据服务器状态列表====>对应于多个跟踪服务器 src_storage_status = (int *)malloc(sizeof(int) *g_tracker_group.server_count); if (src_storage_status == NULL) { logError("file: "__FILE__", line: %d, " / "malloc %d bytes fail, " / "errno: %d, error info: %s", __LINE__, / (int)sizeof(int) * g_tracker_group.server_count, / errno, strerror(errno)); return errno != 0 ? errno : ENOMEM; } //src_storage_status初始全部填为-1 memset(src_storage_status,-1,sizeof(int)*g_tracker_group.server_count); //报告状态数组 my_report_status = (signed char *)malloc(sizeof(signed char) *g_tracker_group.server_count); if (my_report_status == NULL) { logError("file: "__FILE__", line: %d, " / "malloc %d bytes fail, " / "errno: %d, error info: %s", __LINE__, / (int)sizeof(signed char) * g_tracker_group.server_count, / errno, strerror(errno)); return errno != 0 ? errno : ENOMEM; } //my_report_status初始全部填为-1 memset(my_report_status, -1, sizeof(char)*g_tracker_group.server_count); g_tracker_reporter_count = 0; pServerEnd = g_tracker_group.servers + g_tracker_group.server_count; //有多少个跟踪服务器就创建多少个线程 for (pTrackerServer=g_tracker_group.servers; pTrackerServer<pServerEnd; / pTrackerServer++) { if((result=pthread_create(&tid, &pattr, / tracker_report_thread_entrance, pTrackerServer)) != 0) { logError("file: "__FILE__", line: %d, " / "create thread failed, errno: %d, " / "error info: %s.", / __LINE__, result, strerror(result)); return result; } if ((result=pthread_mutex_lock(&reporter_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_lock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } //添加到线程列表中 report_tids[g_tracker_reporter_count] = tid; g_tracker_reporter_count++; if ((result=pthread_mutex_unlock(&reporter_thread_lock)) != 0) { logError("file: "__FILE__", line: %d, " / "call pthread_mutex_unlock fail, " / "errno: %d, error info: %s", / __LINE__, result, strerror(result)); } } pthread_attr_destroy(&pattr); return 0; |