美文网首页
LevelDB 跨平台编程(四)env

LevelDB 跨平台编程(四)env

作者: wayyyy | 来源:发表于2024-02-05 02:00 被阅读0次

Env 是一个抽象接口类,用纯虚函数的形式定义了一些与平台操作的相关接口,如文件系统,多线程,时间操作等。Env 抽象接口类的定义如下:

class LEVELDB_EXPORT Env
{
    public:
        Env();

        Env(const Env &) = delete;
        Env &operator=(const Env &) = delete;

        virtual ~Env();

        static Env* Default();

        // 创建一个顺序可读的文件
        virtual Status NewSequentialFile(const std::string &fname,
                                         SequentialFile **result) = 0;
        // 创建一个随机可读的文件
        virtual Status NewRandomAccessFile(const std::string &fname,
                                           RandomAccessFile **result) = 0;
        // 创建一个顺序可写的文件
        virtual Status NewWritableFile(const std::string &fname,
                                       WritableFile **result) = 0;
        // 创建一个顺序可写的文件,如果文件存在,则在原文件的基础上继续添加,如果文件不存在,则创建新文件
        virtual Status NewAppendableFile(const std::string &fname,
                                         WritableFile **result);
        // 判断某个文件是否存在
        virtual bool FileExists(const std::string &fname) = 0;

        // 返回指定路径下所有的子文件
        virtual Status GetChildren(const std::string &dir,
                                   std::vector<std::string> *result) = 0;
        // 删除指定的文件
        virtual Status RemoveFile(const std::string &fname);
        virtual Status DeleteFile(const std::string &fname);
        // 创建新的文件夹
        virtual Status CreateDir(const std::string &dirname) = 0;
        // 删除指定的文件夹
        virtual Status RemoveDir(const std::string &dirname);
        virtual Status DeleteDir(const std::string &dirname);
        //  获取文件大小
        virtual Status GetFileSize(const std::string &fname, uint64_t *file_size) = 0;
        // 给文件重命名
        virtual Status RenameFile(const std::string &src,
                                  const std::string &target) = 0;
        // 给文件加锁
        virtual Status LockFile(const std::string &fname, FileLock **lock) = 0;
        // 给文件解锁
        virtual Status UnlockFile(FileLock *lock) = 0;
        // 在后台线程中,调度执行一个指定的函数
        virtual void Schedule(void (*function)(void *arg), void *arg) = 0;
        // 启动一个新的线程,执行一个指定的函数
        virtual void StartThread(void (*function)(void *arg), void *arg) = 0;

        virtual Status GetTestDirectory(std::string *path) = 0;

        virtual Status NewLogger(const std::string &fname, Logger **result) = 0;

        virtual uint64_t NowMicros() = 0;

        virtual void SleepForMicroseconds(int micros) = 0;
};

可以发现,除了构造函数,析构函数以及Default 函数外,其他接口方法均为纯虚函数。

纯虚函数主要是为了实现1个接口,并起到规范的作用,指定继承这个类必须实现该函数,即任何派生类都要定义该纯虚函数的实现方法。有纯虚函数的类是抽象类,不能生成对象,只能派生。而如果派生类中的纯虚函数没有改写,那么派生类依然是抽象类。

Env 作为抽象类,有3个派生子类:

image.png
  • PosixEnv
  • InMemoryEnv
  • EnvWrapper

这里首先看下Env中唯一一个非纯虚的静态成员函数Default,实现在env_posix.cc中,如下:

template <typename EnvType>
class SingletonEnv
{
    public:
        SingletonEnv()
        {
            static_assert(sizeof(env_storage_) >= sizeof(EnvType), 
                "env_storage_ will not fit the Env");
            static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType),
                "env_storage_ does not meet the Env's alignment needs");
            
            new (&env_storage_) EnvType();
        }
        
        ~SingletonEnv() = default;

        SingletonEnv(const SingletonEnv &) = delete;
        SingletonEnv &operator=(const SingletonEnv &) = delete;

        Env *env() { return reinterpret_cast<Env *>(&env_storage_); }

    private:
        typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type env_storage_;
};

using PosixDefaultEnv = SingletonEnv<PosixEnv>;

Env* Env::Default()
{
    static PosixDefaultEnv env_container;
    return env_container.env();
}

PosixEnv 是LevelDB 中默认的Env实例对象,PosixEnv 的定义与实现主要在 util/env_posix.cc 文件中。所有,下面我们只看看 PosixEnv 对于 Env 的实现:

文件I/O相关
  • NewSequentialFile 主要实例化了一个PosixSequwntialFile对象
  • 实例化了一个或者
  • 均实例化了
  • 其他
    函数 底层实现
    FileExists access
    GetChildren readdir
    DeleteFile unlink
    CreateDir mkdir
线程操作相关

StartThread 函数则是启动 一个新的线程执行指定的函数:

void StartThread(void (*thread_main)(void *thread_main_arg),
                             void *thread_main_arg) override
{
    std::thread new_thread(thread_main, thread_main_arg);
    new_thread.detach();
}

Schedule 主要负责将某个函数调度到后台执行的线程中执行,后台线程长期存在,并不会随着函数执行而销毁。实现其实是一个阻塞队列。

class PosixEnv : public Env
{
...
    private:
        void BackgroundThreadMain();
        
        struct BackgroundWorkItem
        {
            explicit BackgroundWorkItem(void (*function)(void *arg), void *arg) : function(function), arg(arg) { }
            
            void (*const function)(void *);
            void *const arg;
        };

        port::Mutex background_work_mutex_;
        port::CondVar background_work_cv_ GUARDED_BY(background_work_mutex_);
        std::queue<BackgroundWorkItem> background_work_queue_  GUARDED_BY(background_work_mutex_);
        bool started_background_thread_ GUARDED_BY(background_work_mutex_);
}

void PosixEnv::BackgroundThreadMain()
{
    while (true)
    {
        background_work_mutex_.Lock();

        // Wait until there is work to be done.
        while (background_work_queue_.empty())
        {
            background_work_cv_.Wait();
        }

        assert(!background_work_queue_.empty());
        auto background_work_function = background_work_queue_.front().function;
        void *background_work_arg = background_work_queue_.front().arg;
        background_work_queue_.pop();

        background_work_mutex_.Unlock();

        background_work_function(background_work_arg);
    }
}


void PosixEnv::Schedule(
    void (*background_work_function)(void *background_work_arg),
    void *background_work_arg)
{
    background_work_mutex_.Lock();

        // Start the background thread, if we haven't done so already.
        if (!started_background_thread_)
        {
            started_background_thread_ = true;
            std::thread background_thread(PosixEnv::BackgroundThreadEntryPoint, this);
            background_thread.detach();
        }

        // If the queue is empty, the background thread may be waiting for work.
        if (background_work_queue_.empty())
        {
            background_work_cv_.Signal();
        }

    background_work_queue_.emplace(background_work_function, background_work_arg);
    background_work_mutex_.Unlock();
}

相关文章

网友评论

      本文标题:LevelDB 跨平台编程(四)env

      本文链接:https://www.haomeiwen.com/subject/gbcqadtx.html