学习了 巴山独钓 的levelDB源码分析-Status
1. 主要的声明和inline定义(隐式inline和利用显式inline关键字定义)都放在了status.h文件中。 只有CopyState,Status和ToString这3个代码比较多和复杂一些的函数放在了status.cc文件中去定义。
2. 发现leveldb中的显式inline都是采用如下形式定义在.h文件中。 我自己的话一般会在声明的同时显式inline定义,以后要学习leveldb中的用法,毕竟把声明和定义分离开更加清晰。 至于隐式inline的,那是因为定义式的代码本来就1-2行,声明式和定义式放一起也不影响清晰性。
inline Status::Status(const Status& s) {
state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
}
3. status类主要是封装了一个数组const char* state_; 至于这个变长数组的定义格式,源码注释写的很清楚,前4字节是长度,第5字节是错误code,第6字节以后是message。 错误code使用了enum进行了声明。总计是6种,名字都是k打头,这是谷歌规范里面的规定的,静态常量以k打头。
// OK status has a NULL state_. Otherwise, state_ is a new[] array
// of the following form:
// state_[0..3] == length of message
// state_[4] == code
// state_[5..] == message
const char* state_;
enum Code {
kOk = 0,
kNotFound = 1,
kCorruption = 2,
kNotSupported = 3,
kInvalidArgument = 4,
kIOError = 5
};
4. 由于state_的格式是固定的,所以像code()函数,也就是获取status对象的code码,可以直接取state_ 的第5个元素。
Code code() const {
return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);
}
5. 分析下 函数CopyState,也是利用state_的格式是已知的固定格式,来取得数据长度,进行mycpy的。
const char* Status::CopyState(const char* state) {
uint32_t size; //message的长度
memcpy(&size, state, sizeof(size)); //state的前4字节正好是表示message长度的。
char* result = new char[size + 5]; //state的长度是前面5个固定字节,再加上message的长度。 用此长度new出来数组。
memcpy(result, state, size + 5); //将state的内容取size+5也就是总长度,copy到新new出来的数组result里
return result;
}
6. 分析下构造函数Status,也是利用固定格式的state_
Status::Status(Code code, const Slice& msg, const Slice& msg2) {
assert(code != kOk); //如果是kOk,直接就是个空对象嘛。
const uint32_t len1 = msg.size(); //用到的第一个msg的长度
const uint32_t len2 = msg2.size();//用到的第二个msg的长度
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);//总长度是len1+len2+2,原因是msg和msg2之间要用:加上空格符号隔开。 这里做了个?:判断选择,如果len2是0的话,size直接就是len1了。
char* result = new char[size + 5];// size是新message的长度,还要加上5个字节的固定长度。 其中前4个字节是表示新message有多长的,第5个字节表示code码是啥的。
memcpy(result, &size, sizeof(size)); //前4个字节是表示新message多长的,直接用memcpy效率高啊。
result[4] = static_cast<char>(code);//第5个字节放置表示code嘛是啥的,这里把enum转换成了char类型。
memcpy(result + 5, msg.data(), len1); //先copy第一个msg到新message的内存里
if (len2) {
result[5 + len1] = ':'; //第一个msg后加:符号
result[6 + len1] = ' '; //然后再加空格符号
memcpy(result + 7 + len1, msg2.data(), len2); //最后把msg2整个copy到新message里。 注意这里的指针已经是result+7+len1了, 7是:符号加上空格符号,加上新messag的前5个固定字节。
}
state_ = result;
}