[LevelDB]状态类的设计.md
LevelDB的状态类是leveldb::Status
,以下简称Status
。
状态信息的存储
Status
中使用char*
来存储状态信息。
// 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_;
如注释所说,其内容分为三部分,前4个字节存储从第6个字节开始的提示信息的长度,第5个字节存储状态码,之后的字节存储提示信息。
状态码使用枚举类型表示。
enum Code {
kOk = 0,
kNotFound = 1,
kCorruption = 2,
kNotSupported = 3,
kInvalidArgument = 4,
kIOError = 5
};
状态码一共有6个状态。但其实kOk
不用于记录正常状态,而是用于与其他状态比对。当返回状态为正产时,理论上不需要任何提示信息,state_
第一部分和第二部分存储的信息就不必存储信息,空留状态码意义不大,所以作者的做法是创建Ok类型的状态类时,直接将state_
设置为空指针。
创建状态信息
状态信息的声明周期应为短暂的、一次性的,只需要创建状态信息,然后验证状态信息即可。LevelDB正是这样做的,去除默认构造函数和拷贝构造函数外,Status
类中设计了6个静态成员函数,正好对应状态码的6个状态。其中生成Ok状态的函数直接调用默认构造函数,生成一个空状态对象。其余函数在调用时均需要传入1或2条提示信息,状态码在函数内自动赋予。
以上静态函数是供调用者使用,实际上产生异常状态对象时,它们都调用同一个私有构造函数。
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;
}
在这个函数中可以看到状态信息的存储过程。
创建状态码示例:
Status LockFile(const std::string& fname, FileLock** lock) override {
*lock = new FileLock;
return Status::OK();
}
获取状态信息
同创建状态信息一致,LevelDB也提供了6个获取状态类型的接口。
// Returns true iff the status indicates success.
bool ok() const { return (state_ == nullptr); }
// 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; }
// Returns true iff the status indicates a NotSupportedError.
bool IsNotSupportedError() const { return code() == kNotSupported; }
// Returns true iff the status indicates an InvalidArgument.
bool IsInvalidArgument() const { return code() == kInvalidArgument; }
除验证状态是否正常函数外,其他函数内部都是通过code()
函数获取status_
的第5位状态码值之后,与期望状态码值比较,返回布尔值。注意,当状态为正常时,code()
函数会范围kOk
的状态码,这就上文所说的kOk
状态码的作用。
获取状态信息示例:
Status s = impl->Recover(&edit, &save_manifest);
if (s.ok() && impl->mem_ == nullptr) {
// Create new log and a corresponding memtable.
uint64_t new_log_number = impl->versions_->NewFileNumber();
WritableFile* lfile;
s = options.env->NewWritableFile(LogFileName(dbname, new_log_number), &lfile);
if (s.ok()) {
edit.SetLogNumber(new_log_number);
impl->logfile_ = lfile;
impl->logfile_number_ = new_log_number;
impl->log_ = new log::Writer(lfile);
impl->mem_ = new MemTable(impl->internal_comparator_);
impl->mem_->Ref();
}
}
网友评论