return;
}
writeSlow(buf, len);//缓存空间不足就调用慢写函数
}
const uint8_t* borrow(uint8_t* buf, uint32_t* len) {//快速路径借
if (TDB_LIKELY(static_cast
*len = static_cast
return rBase_;//返回借的基地址
}
return borrowSlow(buf, len);//不足就采用慢路径借
}
void consume(uint32_t len) {//消费函数
if (TDB_LIKELY(static_cast
rBase_ += len;//更新已经消耗的长度
} else {
throw TTransportException(TTransportException::BAD_ARGS,
"consume did not follow a borrow.");//不足抛异常
}
}
protected:
virtual uint32_t readSlow(uint8_t* buf, uint32_t len) = 0;//慢函数
virtual void writeSlow(const uint8_t* buf, uint32_t len) = 0;
virtual const uint8_t* borrowSlow(uint8_t* buf, uint32_t* len) = 0;
TBufferBase()
: rBase_(NULL)
, rBound_(NULL)
, wBase_(NULL)
, wBound_(NULL)
{}//构造函数,把所有的缓存空间设置为NULL
void setReadBuffer(uint8_t* buf, uint32_t len) {//设置读缓存空间地址
rBase_ = buf;//读缓存开始地址
rBound_ = buf+len;//读缓存地址界限
}
void setWriteBuffer(uint8_t* buf, uint32_t len) {//设置写缓存地址空间
wBase_ = buf;//起
wBound_ = buf+len;//边界
}
virtual ~TBufferBase() {}
uint8_t* rBase_;//读从这儿开始
uint8_t* rBound_;//读界限
uint8_t* wBase_;//写开始地址
uint8_t* wBound_;//写界限
}; 从TBufferBase定义可以看出,它也是从虚拟类继承,主要采用了memcpy函数来实现缓存的快速读取,在判断是否有足够的缓存空间可以操作时采用了分支预测技术来提供代码的执行效率,且所有快路径函数都是非虚拟的、内联的小代码量函数。下面继续看看一个具体实现缓存基类的一个子类的情况!
TBufferedTransport
缓存传输类是从缓存基类继承而来,它对于读:实际读数据的大小比实际请求的大很多,多余的数据将为将来超过本地缓存的数据服务;对于写:数据在它被发送出去以前将被先写入内存缓存。
缓存的大小默认是512字节(代码:static const int DEFAULT_BUFFER_SIZE = 512;),提供多个构造函数,可以只指定一个传输类(另一层次的)、也可以指定读写缓存公用的大小或者分别指定。因为它是一个可以实际使用的缓存类,所以需要实现慢读和慢写功能的函数。它还实现了打开函数open、关闭函数close、刷新函数flush等,判断是否有数据处于未决状态函数peek定义和实现如下:
[cpp]
bool peek() {
if (rBase_ == rBound_) {//判断读的基地址与读边界是否重合了,也就是已经读取完毕
setReadBuffer(rBuf_.get(), transport_->read(rBuf_.get(), rBufSize_));//是:重新读取底层来的数据
}
return (rBound_ > rBase_);//边界大于基地址就是有未决状态数据
}
下面继续看看慢读函数和慢写函数的实现细节(快读和快写继承基类的:也就是默认的读写都是直接从缓存中读取,所谓的快读和快写)。慢读函数实现如下(详细注释):
uint32_t TBufferedTransport::readSlow(uint8_t* buf, uint32_t len) {
uint32_t have = rBound_ - rBase_;//计算还有多少数据在缓存中
// 如果读取缓存中已经存在的数据不能满足我们,
// 我们(也仅仅在这种情况下)应该才从慢路径读数据。
assert(have < len);
// 如果我们有一些数据在缓存,拷贝出来并返回它
// 我们不得不返回它而去尝试读更多的数据,因为我们不能保证
// 下层传输实际有更多的数据, 因此尝试阻塞式读取它。
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;
}
bool peek() {
if (rBase_ == rBound_) {//判断读的基地址与读边界是否重合了,也就是已经读取完毕
setReadBuffer(rBuf_.get(), transport_->read(rBuf_.get(), rBufSize_));//是:重新读取底层来的数据
}
return (rBound_ > rBase_);//边界大于基地址就是有未决状态数据
}
下面继续看看慢读函数和慢写函数的实现细节(快读和快写继承基类的:也就是默认的读写都是直接从缓存中读取,所谓的快读和快写)。慢读函数实现如下(详细注释):
uint32_t TBufferedTransport::readSlow(uint8_t* buf, uint32_t len) {
uint32_t have = rBound_ - rBase_;//计算还有多少数据在缓存中
// 如果读取缓存中已经存在的数据不能满足我们,
// 我们(也仅仅在这种情况下)应该才从慢路径读数据。
assert(have < len);
// 如果我们有一些数据在缓存,拷贝出来并返回