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个派生子类:
![](https://img.haomeiwen.com/i7304940/c1e6f6376c479e58.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();
}
网友评论