设为首页 加入收藏

TOP

leveldb学习:Env(一)
2015-11-21 01:43:20 来源: 作者: 【 】 浏览:2
Tags:leveldb 学习 Env

考虑到移植以及灵活性,leveldb将系统相关的处理(文件/进程/时间)抽象成Evn,用户可以自己实现相应的接口,作为option传入,默认使用自带的实现。
解压目录/util/中放有env的声明和实现代码。env.h中声明了:

虚基类env,在env_posix.cc中,派生类PosixEnv继承自env类,是leveldb的默认实现。 虚基类WritableFile、SequentialFile、RandomAccessFile,分别是文件的写抽象类,顺序读抽象类和随机读抽象类 类Logger,log文件的写入接口,log文件是防止系统异常终止造成数据丢失,是memtable在磁盘的备份 类FileLock,为文件上锁 WriteStringToFile、ReadFileToString、Log三个全局函数,封装了上述接口

下面来看看env_posix.cc中为我们写好的默认实现

顺序读:

class PosixSequentialFile: public SequentialFile {
 private:
  std::string filename_;
  FILE* file_;
 public:
  PosixSequentialFile(const std::string& fname, FILE* f)
      : filename_(fname), file_(f) { }
  virtual ~PosixSequentialFile() { fclose(file_); }
  virtual Status Read(size_t n, Slice* result, char* scratch) {
    Status s;
    size_t r = fread_unlocked(scratch, 1, n, file_);
    *result = Slice(scratch, r);
    if (r < n) {
      if (feof(file_)) {
        // We leave status as ok if we hit the end of the file
      } else {
        // A partial read with an error: return a non-ok status
        s = IOError(filename_, errno);
      }
    }
    return s;
  }
  virtual Status Skip(uint64_t n) {
    if (fseek(file_, n, SEEK_CUR)) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }
};

这就是leveldb从磁盘读取文件的接口了,用的是C的流文件操作和FILE结构体。

随机读:

class PosixRandomAccessFile: public RandomAccessFile { private: std::string filename_; int fd_; public: PosixRandomAccessFile(const std::string& fname, int fd) : filename_(fname), fd_(fd) { } virtual ~PosixRandomAccessFile() { close(fd_); } virtual Status Read(uint64_t offset, size_t n, Slice* result, char* scratch) const { Status s; ssize_t r = pread(fd_, scratch, n, static_cast
    
     (offset)); *result = Slice(scratch, (r < 0) ? 0 : r); if (r < 0) { // An error: return a non-ok status s = IOError(filename_, errno); } return s; } };
    

随机读取磁盘中文件的数据,可以定位读取文件中offset偏移量的数据,核心函数pread()函数,可以带偏移量地原子的从文件中读取数据,offset:读取的
其实地址偏移量,读取地址=文件地址+offset。

写入:

class PosixWritableFile : public WritableFile { private: std::string filename_; FILE* file_; public: PosixWritableFile(const std::string& fname, FILE* f) : filename_(fname), file_(f) { } ~PosixWritableFile() { if (file_ != NULL) { // Ignoring any potential errors fclose(file_); } } virtual Status Append(const Slice& data) { size_t r = fwrite_unlocked(data.data(), 1, data.size(), file_); if (r != data.size()) { return IOError(filename_, errno); } return Status::OK(); } virtual Status Close() { Status result; if (fclose(file_) != 0) { result = IOError(filename_, errno); } file_ = NULL; return result; } virtual Status Flush() { if (fflush_unlocked(file_) != 0) { return IOError(filename_, errno); } return Status::OK(); } Status SyncDirIfManifest() { const char* f = filename_.c_str(); const char* sep = strrchr(f, '/'); Slice basename; std::string dir; if (sep == NULL) { dir = "."; basename = f; } else { dir = std::string(f, sep - f); basename = sep + 1; } Status s; if (basename.starts_with("MANIFEST")) { int fd = open(dir.c_str(), O_RDONLY); if (fd < 0) { s = IOError(dir, errno); } else { if (fsync(fd) < 0) { s = IOError(dir, errno); } close(fd); } } return s; } virtual Status Sync() { // Ensure new files referred to by the manifest are in the filesystem. Status s = SyncDirIfManifest(); if (!s.ok()) { return s; } if (fflush_unlocked(file_) != 0 || fdatasync(fileno(file_)) != 0) { s = Status::IOError(filename_, strerror(errno)); } return s; } };

sync( )函数是同步缓存和磁盘中的数据,核心函数fflush(清空输出缓冲区,并把缓冲区内容输出),在比较关键的写入操作时,立即同步可以防止系统掉电时数据丢失。
定义完这三个文件的读写抽象类,把他们加入到PosixEnv类中,定义三个NewSequentialFile、NewRandomAccessFile、NewWritableFile函数,产生文件读写的对象,在程序上层中调用env_->NewWritableFile即可创建一个文件,并可写入数据。

文件的上锁:

static int LockOrUnlock(int fd, bool lock) { errno = 0; struct flock f; memset(&f, 0, sizeof(f)); f.l_type = (lock ? F_WRLCK : F_UNLCK); f.l_whence = SEEK_SET; f.l_start = 0; f.l_len = 0; // Lock/unlock entire file return fcntl(fd, F_SETLK, &f); }

fd是文件的i节点(linux每个文件和文件夹都对应一个唯一的i节点,用于管理文件)。核心调用函数fcntl,F_WRLK和F_UNLK是命令的参数,上锁和解锁。在PosixEnv的成员函数LockFile和UnlockFile都调用了此函数,此外还将上锁的文件保存在了PosixEnv::PosixLockTable locks_成员变量中,PosixLockTable是一个类,内有成员std::set locked_files_保存上锁的文件名,定义了insert和remove操作,然而并没看出用处o(?□?)o?

PosixEnv还有一个很重要的功能,计划任务,也就是后台的compact进程,compact目的是维护数据库的均衡性,保持数据库查找的高效率。PosixEnv中定义了

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇leveldb学习:skiplist 下一篇leveldb:dbimpl(1)

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: