• LevelDB的错误处理和Status类


    LevelDB错误处理基本套路

    LevelDB在需要判断是否出现异常的部分,都会产生一个Status类对象,例如打开数据库

    leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);

    了解Status类的设计思路,即了解了LevelDB错误处理的基本思路

    Status类分析

    类的变量

    Status类包含一个枚举类型的错误码Code和描述详细错误信息的state_

    enum Code {
        kOk = 0,
        kNotFound = 1,
        kCorruption = 2,
        kNotSupported = 3,
        kInvalidArgument = 4,
        kIOError = 5
      };  
      Code code() const {
        return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);
      }
    
      Status(Code code, const Slice& msg, const Slice& msg2);
    static const char* CopyState(const char* s);
    
      // 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_;

    Code类中我们知道了Status可以表示的所有错误类型

    根据Code函数我们知道对于无异常的表示其实就是state_为空, 不然才需要使用错误编码

    state_根据注释可知, 其组合前4个字节是错误信息的长度, 第5个字节是错误编码, 第6个字节往后剩下的是错误信息

    Status的初始化

    //两个msg的意义:应该是出错位置和出错原因
    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是在msg和msg2中间加入":_"
      char* result = new char[size + 5];//5 表示0-4的固定头部, 即信息长度和错误码
      std::memcpy(result, &size, sizeof(size));//0..3 length of message
      result[4] = static_cast<char>(code);//错误码
      std::memcpy(result + 5, msg.data(), len1);
      if (len2) {
        result[5 + len1] = ':';
        result[6 + len1] = ' ';
        std::memcpy(result + 7 + len1, msg2.data(), len2);
      }
      state_ = result;
    }

    应用Status初始化的案例: 是函数Status DBImpl::Recover(VersionEdit* edit, bool* save_manifest)中的一部分代码, 我们可以看到Status使用的基本方法

    if (!env_->FileExists(CurrentFileName(dbname_))) {
        if (options_.create_if_missing) {
          Log(options_.info_log, "Creating DB %s since it was missing.",
              dbname_.c_str());
          s = NewDB();
          if (!s.ok()) {
            return s;
          }
        } else {
          return Status::InvalidArgument(
              dbname_, "does not exist (create_if_missing is false)");
        }
      } else {
        if (options_.error_if_exists) {
          return Status::InvalidArgument(dbname_,
                                         "exists (error_if_exists is true)");
        }
      }

    CopyState类函数

    这个函数在错误处理使用的不多, 摘出来主要是因为其非常优雅的解决了对保存有长度和内容的char*数据的复制

    const char* Status::CopyState(const char* state) {
      uint32_t size;
      std::memcpy(&size, state, sizeof(size));//这里memcpy直接用来复制整型是我以前没想过的用法, 其是memcpy对是对第一个参数指针指向的位置复制第二个参中size个字节, 并不一定是char
      char* result = new char[size + 5];
      std::memcpy(result, state, size + 5);
      return result;
    }

    问题解决

    Status类中使用枚举变量是否会浪费空间?

    参考一下文章:

    (1条消息) C++类中的枚举类型_qinhan728的专栏-CSDN博客

    简单总结:

    在类中使用枚举类不会占用变量空间

    这样做的目的是让某些常量只在类中有效

    源码

    /usr/local/include/leveldb/status.h

    // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file. See the AUTHORS file for names of contributors.
    //
    // A Status encapsulates the result of an operation.  It may indicate success,
    // or it may indicate an error with an associated error message.
    //
    // Multiple threads can invoke const methods on a Status without
    // external synchronization, but if any of the threads may call a
    // non-const method, all threads accessing the same Status must use
    // external synchronization.
    
    #ifndef STORAGE_LEVELDB_INCLUDE_STATUS_H_
    #define STORAGE_LEVELDB_INCLUDE_STATUS_H_
    
    #include <algorithm>
    #include <string>
    
    #include "leveldb/export.h"
    #include "leveldb/slice.h"
    
    namespace leveldb {
    
    class LEVELDB_EXPORT Status {
    public:
      // 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;
    
      // 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);
      }
    
      // 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; }
    
      // Return a string representation of this status suitable for printing.
      // Returns the string "OK" for success.
      std::string ToString() const;
    
    private:
      enum Code {
        kOk = 0,
        kNotFound = 1,
        kCorruption = 2,
        kNotSupported = 3,
        kInvalidArgument = 4,
        kIOError = 5
      };
    
      Code code() const {
        return (state_ == nullptr) ? kOk : static_cast<Code>(state_[4]);
      }
    
      Status(Code code, const Slice& msg, const Slice& msg2);
      static const char* CopyState(const char* s);
    
      // 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_;
    };
    
    inline Status::Status(const Status& rhs) {
      state_ = (rhs.state_ == nullptr) ? nullptr : CopyState(rhs.state_);
    }
    inline Status& Status::operator=(const Status& rhs) {
      // The following condition catches both aliasing (when this == &rhs),
      // and the common case where both rhs and *this are ok.
      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;
    }
    
    }  // namespace leveldb
    
    #endif  // STORAGE_LEVELDB_INCLUDE_STATUS_H_
    




  • 相关阅读:
    Java入门:基础算法之求数组元素的和
    Java入门:基础算法之计算三角形面积
    Java入门:基础算法之计算园的面积
    Java入门:创建多个对象
    编程语言教程书该怎么写: 向K&R学习!
    Java入门:一些初学者需要掌握的基础算法程序——二分查找
    Java入门:一些初学者需要掌握的基础算法程序——逆序输出
    Java入门:Java中获取键盘输入值的三种方法
    Java注释规范整理
    8大排序算法图文讲解
  • 原文地址:https://www.cnblogs.com/yyjjtt/p/14362231.html
Copyright © 2020-2023  润新知