// 我们不得不返回它而去尝试读更多的数据,因为我们不能保证
// 下层传输实际有更多的数据, 因此尝试阻塞式读取它。
if (have > 0) {
memcpy(buf, rBase_, have);//拷贝数据
setReadBuffer(rBuf_.get(), 0);//设置读缓存,基类实现该函数
return have;//返回缓存中已经存在的不完整数据
}
// 在我们的缓存中没有更多的数据可用。从下层传输得到更多以达到buffer的大小。
// 注意如果len小于rBufSize_可能会产生多种场景否则几乎是没有意义的。
setReadBuffer(rBuf_.get(), transport_->read(rBuf_.get(), rBufSize_));//读取数据并设置读缓存
// 处理我们已有的数据
uint32_t give = std::min(len, static_cast
memcpy(buf, rBase_, give);
rBase_ += give;
return give;
} 慢读函数主要考虑的问题就是缓存中还有一部分数据,但是不够我们需要读取的长度;还有比较麻烦的情况是虽然现在缓存中没有数据,但是我们从下层传输去读,读取的长度可能大于、小于或等于我们需要读取的长度,所以需要考虑各种情况。下面继续分析慢写函数实现细节:
[cpp]
void TBufferedTransport::writeSlow(const uint8_t* buf, uint32_t len) {
uint32_t have_bytes = wBase_ - wBuf_.get();//计算写缓存区中已有的字节数
uint32_t space = wBound_ - wBase_;//计算剩余写缓存空间
// 如果在缓存区的空闲空间不能容纳我们的数据,我们采用慢路径写(仅仅)
assert(wBound_ - wBase_ < static_cast
//已有数据加上需要写入的数据是否大于2倍写缓存区或者缓存区为空
if ((have_bytes + len >= 2*wBufSize_) || (have_bytes == 0)) {
if (have_bytes > 0) {//缓存大于0且加上需要再写入数据的长度大于2倍缓存区
transport_->write(wBuf_.get(), have_bytes);//先将已有数据写入下层传输
}
transport_->write(buf, len);//写入这次的len长度的数据
wBase_ = wBuf_.get();//重新得到写缓存的基地址
return;
}
memcpy(wBase_, buf, space);//填充我们的内部缓存区为了写
buf += space;
len -= space;
transport_->write(wBuf_.get(), wBufSize_);//写入下层传输
assert(len < wBufSize_);
memcpy(wBuf_.get(), buf, len);//拷贝剩余的数据到我们的缓存
wBase_ = wBuf_.get() + len;//重新得到写缓存基地址
return;
}
void TBufferedTransport::writeSlow(const uint8_t* buf, uint32_t len) {
uint32_t have_bytes = wBase_ - wBuf_.get();//计算写缓存区中已有的字节数
uint32_t space = wBound_ - wBase_;//计算剩余写缓存空间
// 如果在缓存区的空闲空间不能容纳我们的数据,我们采用慢路径写(仅仅)
assert(wBound_ - wBase_ < static_cast
//已有数据加上需要写入的数据是否大于2倍写缓存区或者缓存区为空
if ((have_bytes + len >= 2*wBufSize_) || (have_bytes == 0)) {
if (have_bytes > 0) {//缓存大于0且加上需要再写入数据的长度大于2倍缓存区
transport_->write(wBuf_.get(), have_bytes);//先将已有数据写入下层传输
}
transport_->write(buf, len);//写入这次的len长度的数据
wBase_ = wBuf_.get();//重新得到写缓存的基地址
return;
}
memcpy(wBase_, buf, space);//填充我们的内部缓存区为了写
buf += space;
len -= space;
transport_->write(wBuf_.get(), wBufSize_);//写入下层传输
assert(len < wBufSize_);
memcpy(wBuf_.get(), buf, len);//拷贝剩余的数据到我们的缓存
wBase_ = wBuf_.get() + len;//重新得到写缓存基地址
return;
} 慢写函数也有棘手的问题,就是我们应该拷贝我们的数据到我们的内部缓存并且从那儿发送出去,或者我们应该仅仅用一次系统调用把当前内部写缓存区的内容写出去,然后再用一次系统调用把我们当前需要写入长度为len的数据再次写入出去。如果当前缓存区的数据加上我们这次需要写入数据的长度至少是我们缓存区长度的两倍,我们将不得不至少调用两次系统调用(缓存区为空时有可能例外),那么我们就不拷贝了。否则我们就是按顺序递加的。具体实现分情况处理,最后我们在看看慢借函数的实现,借相关函数主要是为了实现可变长度编码。慢借函数实现细节如下:
[cpp]
const uint8_t* TBufferedTransport::borrowSlow(uint8_t* buf, uint32_t* len) {
(void) buf;
(void) len;
return NULL;//默认返回空
}
const uint8_t* TBufferedTransport::borrowSlow(uint8_t* buf, uint32_t* len) {
(void) buf;
(void) len;
return NULL;//默认返回空
}
在这个类我们可以看出,它什么也没有做,只是简单的返回NULL,所以需要阻塞去借。按照官方的说法,下面两种行为应该当前的版本中实现,在将来的版本可能会发生改变:
如果需要借的长度最多为缓存区的长度,那么永远不会返回NULL。依赖底层传输,它应该抛出一个异常或者永远不会挂掉;
一些借用请求可能内部字节拷贝,如果借用的长度最多是缓存区的一半,那么不去内部拷贝。为了优化性能保存这个限制。