看了TFS文件系统的代码,描述一下TFS的写文件时数据块复制的处理过程:
客户端接口函数:
//写文件操作组包的方法:写文件时的协议的方法是会发送多个独立的消息包过去 int TfsFile::tfs_write(char *data, const int32_t len) { if (is_open_flag_ == TFS_FILE_OPEN_FLAG_NO) { snprintf(error_message_, ERR_MSG_SIZE, "tfs file(%s) don't open file", file_name_); return -2; } if (!(mode_ & WRITE_MODE)) { snprintf(error_message_, ERR_MSG_SIZE, "open file mode isn't write."); return -1; } //发起写操作 WriteDataMessage dsmessage; dsmessage.set_file_number(file_number_); dsmessage.set_block_id(block_id_); dsmessage.set_file_id(file_id_); dsmessage.set_offset(offset_); dsmessage.set_length(len); //要写入的字节长度 dsmessage.set_ds_list(ds_list_); //数据服务器列表 dsmessage.set_data(data); //写的buf区 Message *message = client_->call(&dsmessage); //客户端发送数据包 } |
从这个接口函数可以看出,写文件时,会分成多个数据包发送.
接下来看看一下具体的实现过程:
(1).在client_->call(&dsmessage)方法里面,会把数据包放入到发送队列里面:
//发送packet到发送队列 bool Connection::postPacket(Packet *packet, IPacketHandler *packetHandler, void *args, bool noblocking) { if (!isConnectState()) { if (_iocomponent == NULL || _iocomponent->isAutoReconn() == false) { return false; } else if (_outputQueue.size()>10) { return false; } else { TCPComponent *ioc = dynamic_cast<TCPComponent*>(_iocomponent); bool ret = false; if (ioc != NULL) { _outputCond.lock(); ret = ioc->init(false); //在做一次连接,写事件 _outputCond.unlock(); } if (!ret) return false; } } // 如果是client, 并且有queue长度的限制 _outputCond.lock(); _queueTotalSize = _outputQueue.size() + _channelPool.getUseListCount() + _myQueue.size(); //如果操作队列限制数,直接返回 if (!_isServer && _queueLimit > 0 && noblocking && _queueTotalSize >= _queueLimit) { _outputCond.unlock(); return false; } _outputCond.unlock(); Channel *channel = NULL; packet->setExpireTime(_queueTimeout); // 设置超时 if (_streamer->existPacketHeader()) { // 存在包头 uint32_t chid = packet->getChannelId(); // 从packet中取 if (_isServer) { assert(chid != 0); // 不能为空 } else { channel = _channelPool.allocChannel(); // channel没找到了 if (channel == NULL) { TBSYS_LOG(WARN, "分配channel出错, id: %u", chid); return false; } channel->setHandler(packetHandler); channel->setArgs(args); packet->setChannel(channel); //设置渠道 } } _outputCond.lock(); // 写入到outputqueue中 _outputQueue.push(packet); if (_iocomponent != NULL && _outputQueue.size() == 1U) { _iocomponent->enableWrite(true); } _outputCond.unlock(); //如果是客户端,并且有队列数限制的话 if (!_isServer && _queueLimit > 0) { _outputCond.lock(); _queueTotalSize = _outputQueue.size() + _channelPool.getUseListCount() + _myQueue.size(); if ( _queueTotalSize > _queueLimit && noblocking == false) { bool *stop = NULL; if (_iocomponent && _iocomponent->getOwner()) { stop = _iocomponent->getOwner()->getStop(); } while (_queueTotalSize > _queueLimit && stop && *stop == false) { if (_outputCond.wait(1000) == false) { if (!isConnectState()) { break; } _queueTotalSize = _outputQueue.size() + _channelPool.getUseListCount() + _myQueue.size(); } } } _outputCond.unlock(); }
if (_isServer && _iocomponent) { _iocomponent->subRef(); }
return true; } |
将数据包发送到发送队列后,有一个线程在扫描socket事件:
//socket event 的检测, 被run函数调用,在线程里面被调用/ void Transport::eventLoop(SocketEvent *socketEvent) { IOEvent events[MAX_SOCKET_EVENTS]; while (!_stop) { // 检查是否有事件发生 int cnt = socketEvent->getEvents(1000, events, MAX_SOCKET_EVENTS); if (cnt < 0) { TBSYS_LOG(INFO, "得到events出错了: %s(%d)/n" |