Status 位于 Slice 同级目录下
Status 的定义在 include/leveldb/status.h 里,在 util/status.cc 为 Status 的实现
const char* state_;
enum Code {
kOk = 0,
kNotFound = 1,
kCorruption = 2,
kNotSupported = 3,
kInvalidArgument = 4,
kIOError = 5
};
Status 只有一个成员变量 state_,该成员变量是一个 char 指针,并且一经初始化便不能再改变。state_ 存储了所有和状态相关的信息,用 state_[0...3] 来表示其中包含的 message 的长度,用 state_[4] 来表示状态码,用 state_[5...] 之后的空间存储 message。
因为只用了一个字节来表示状态码,所以 Status 能表示的状态数量不超过 2^8 个。在 Status 内部,使用一个枚举值来表示可能存在的状态,主要有:kOk、kNotFound、kCorruption、kNotSupported、kInvalidArgument 和 kIOError 等六种状态码。
为了方便,Status 自己定义了一个私有的成员函数来从 state_ 中获取状态码:
Code code() const {
return (state_ == NULL) ? kOk : static_cast<Code>(state_[4]);
}
可以看出,当 state_ 为 NULL 的时候,默认的状态码是 kOk,否则的话就直接取 state_[4] 里的值作为状态码
虽然总共有六中状态,但是 Status 却只提供了其中四种状态的判断接口,他们分别是 kOk、kNotFound、kCorruption 和 kIOError:
// Returns true iff the status indicates success.
bool ok() const { return (state_ == NULL); }
// Returns true iff the status indicates a NotFound error.
bool IsNotFound() const { return code() == kNotFound; }
// Returns true iff the status indicates a Corruption error.
bool IsCorruption() const { return code() == kCorruption; }
// Returns true iff the status indicates an IOError.
bool IsIOError() const { return code() == kIOError; }
Status 对外提供了两个构造函数:
Status() : state_(NULL) { }
Status(const Status& s);
默认构造函数直接构造一个状态为 kOk 的Status,另外,提供了一个拷贝构造函数。
此外,Status 分别提供了构造所有六种状态的 Status 类方法:
// Return a success status.
static Status OK() { return Status(); }
// Return error status of an appropriate type.
static Status NotFound(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kNotFound, msg, msg2);
}
static Status Corruption(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kCorruption, msg, msg2);
}
static Status NotSupported(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kNotSupported, msg, msg2);
}
static Status InvalidArgument(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kInvalidArgument, msg, msg2);
}
static Status IOError(const Slice& msg, const Slice& msg2 = Slice()) {
return Status(kIOError, msg, msg2);
}
它们都使用到了一个私有的构造函数:
Status(Code code, const Slice& msg, const Slice& msg2);
它的实现如下:
Status::Status(Code code, const Slice& msg, const Slice& msg2) {
assert(code != kOk);
const uint32_t len1 = msg.size();
const uint32_t len2 = msg2.size();
const uint32_t size = len1 + (len2 ? (2 + len2) : 0);
char* result = new char[size + 5];
memcpy(result, &size, sizeof(size));
result[4] = static_cast<char>(code);
memcpy(result + 5, msg.data(), len1);
if (len2) {
result[5 + len1] = ':';
result[6 + len1] = ' ';
memcpy(result + 7 + len1, msg2.data(), len2);
}
state_ = result;
}
可以看到,该构造函数的意思是这样:构造一个非 kOk 状态的 Status,如果 msg2 为空,那么该 Status 的 Error Message 就是 msg 的内容,否则,该 Status 的 Error Message 的格式为:"msg: msg2",也就是说,认为 msg 是一个字段,而 msg2 是该字段的值。也可以很明显的看到,新建这个 Status 的时候,会从堆中分配一段内存用以存储 message 信息。
结合上面分别创建的五个 Error Status 来看,在创建他们的时候,Status 对象本身不会发生改变,变化的是其内部 Message 指针的值,分别调用那五个函数,其根本是在堆上分配一段内存用来存储 Error Code 和 Message 信息,然后把内部指针指向这段内存
在 Status 仅对 '=' 进行了重载。
inline void Status::operator=(const Status& s) {
// The following condition catches both aliasing (when this == &s),
// and the common case where both s and *this are ok.
if (state_ != s.state_) {
delete[] state_;
state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
}
}
这里用到了另一个私有的成员函数 static const char* CopyState(const char* s);
,先来看看它:
const char* Status::CopyState(const char* state) {
uint32_t size;
memcpy(&size, state, sizeof(size));
char* result = new char[size + 5];
memcpy(result, state, size + 5);
return result;
}
这个拷贝的过程比较简单:先获得整个 Error Message 的长度 size,然后从堆里申请 size + 5 字节的空间,最后把整个内容拷贝到这个新申请的空间中,最后把这段空间的首地址返回。
而对 '=' 的重载过程中,如果发现两个 Status 指向的 Message 地址不一样,先把自己原来的 Message 从堆里释放掉,然后执行拷贝动作(从堆里申请内存,拷贝 Error Message),最后把新的地址赋值给当前的 Message 指针。
最后我们还剩下一个了:
std::string Status::ToString() const {
if (state_ == NULL) {
return "OK";
} else {
char tmp[30];
const char* type;
switch (code()) {
case kOk:
type = "OK";
break;
case kNotFound:
type = "NotFound: ";
break;
case kCorruption:
type = "Corruption: ";
break;
case kNotSupported:
type = "Not implemented: ";
break;
case kInvalidArgument:
type = "Invalid argument: ";
break;
case kIOError:
type = "IO error: ";
break;
default:
snprintf(tmp, sizeof(tmp), "Unknown code(%d): ",
static_cast<int>(code()));
type = tmp;
break;
}
std::string result(type);
uint32_t length;
memcpy(&length, state_, sizeof(length));
result.append(state_ + 5, length);
return result;
}
}
其实 ToString() 的功能比较简单:返回 Error Code 对应的 Error Message,具体格式可以看代码