【LevelDB源码阅读】Status
是什么
status用来判断函数返回的状态信息,封装了错误码和错误信息。
为什么要用
- 为了便于管理和定位错误类型,一般大型系统都自定义自己的函数返回状态信息
学到什么
- void *memcpy(void *str1, const void *str2, size_t n):从存储区 str2 复制 n 个字节到存储区 str1
- 使用枚举类型定义多种状态
- 字符串可以分为多个部分,不同部分描述不同内容
- 通过static成员函数构造对象
- noexcept使用
- 格式化字符串snprint
- 字符串追加s.append(args)
源码分析
将不同返回值码定义为一个枚举类型。
enum Code {
kOk = 0,
kNotFound = 1,
kCorruption = 2,
kNotSupported = 3,
kInvalidArgument = 4,
kIOError = 5
};
枚举类型本质是一种int类型,4个字节,上述枚举类型定义不占用内存空间,只有当定义枚举类型变量时才占用空间,如: Code code,code只能使用声明中列出的字符串来初始化。
Status本质就一个成员变量const char *state_,为了节省内存,state_分为三部分使用:
- state_[0..3] == length of message
- state_[4] == code
- state_[5..] == message
拷贝控制
关键字noexcept声明符表明该函数不会抛出异常。
主要优点:
- 知道函数不会抛出异常有助于简化调用该函数代码
- 编译器可以执行某些特殊优化操作
// Create a success status.
Status() noexcept : state_(nullptr) {}
~Status() { delete[] state_; }
Status(const Status &rhs);
Status& operator=(const Status &rhs);
Status(Status &&rhs) noexcept : state_(rhs.state_) { rhs.state_ = nullptr; }
Status& operator=(Status &&rhs) noexcept;
具体实现
inline Status::Status(const Status &rhs) {
state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);
}
inline Status& Status::operator=(const Status &rhs) {
if (state_ != rhs.state_) {
delete[] state_;
state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);
}
return *this;
}
inline Status& Status::operator=(Status &&rhs) noexcept {
std::swap(state_, rhs.state_);
return *this;
}
其中拷贝构造和拷贝赋值本质都是调用CopyState来完成,重新开辟一块内存存储s.state_并将指针赋给调用函数的s.state_,CopyState实现如下:
const char* Status::CopyState(const char *state) {
uint32_t size;
memcpy(&size, state, sizeof(size)); // 复制长度到size
char *result = new char[size + 5]; // 结果总长度包括前面5个字节
memcpy(result, state, size + 5); // 复制完整state内容,长度为size + 5
return result;
}
主要对外接口
直接返回特定类型对象
// 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 s;
s = Status::Corruption("corrupted key for ", user_key); // 会用到赋值操作符
这几个函数又直接调用以下函数
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 = static_cast<uint32_t>(msg.size());
const uint32_t len2 = static_cast<uint32_t>(msg2.size());
const uint32_t size = len1 + (len2 ? (2 + len2) : 0); // 2表示':'和' '
char *result = new char[size + 5]; // state_总长度包括前面5个字节
memcpy(result, &size, sizeof(size)); // 信息长度存入前4个字节
result[4] = static_cast<char>(code); // 状态存入第5个字节
memcpy(result + 5, msg.data(), len1); // 从第6个字节开始存储信息内容
if (len2) { // 如果msg2不为空,则信息内容加上': ' + msg2
result[5 + len1] = ':';
result[6 + len1] = ' ';
memcpy(result + 7 + len1, msg2.data(), len2);
}
state_ = result;
}
判断状态成员方法
// 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()方法返回状态,Code()实现如下:
Code code() const {
return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);
}
输出状态
std::string Status::ToString() const {
if (state_ == nullptr) {
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)); // 取出state_信息长度存入length
result.append(state_ + 5, length); // 添加具体信息
return result; // 返回type + 具体信息
}
}
其中snprintf将格式化的n个字节数据写入字符串,函数原型如下:
int snprintf(char *str, int n, char * format [, argument, ...]);