LevelDB Explained - Preparing the Development Environment

LevelDB is an excellent LSM Tree storage component developed in C++. Although its overall codebase is not large, its design is ingenious and worth studying. During the process of reading the source code, I have compiled a series of articles to gradually break down the implementation details of LevelDB. However, before reading the code, it’s best to prepare the entire development environment.

This article will start from the most basic step of pulling the code, recording my process of preparing the entire environment, including configuring the VSCode IDE and using the clangd plugin, as well as how to configure compilation options. Then, through a simple read and write code demo, we’ll briefly use LevelDB to gain a perceptual understanding of this library. Additionally, we’ll introduce how to run test cases. LevelDB’s test cases are well-written, and during the code reading process, we can use these cases to better understand the code.

Read More

LevelDB Explained - Posix File Operation Details

LevelDB supports running on various operating systems. To adapt to different operating systems, it needs to encapsulate some system calls, such as file operations, thread operations, time operations, etc. In the exposed include files, the env.h file defines various interfaces used by LevelDB. This includes the Env class, which encapsulates file operations, directory operations, etc., as well as some file abstract classes such as SequentialFile, WritableFile, and RandomAccessFile for sequential reading, random reading, and writing files.

Through abstract interfaces, LevelDB can run on different operating systems by implementing the corresponding Env subclass for each platform. This article takes the POSIX system environment as an example to first look at how the abstracted file operation-related interfaces are implemented.

Read More

LevelDB Explained - Preventing C++ Object Destruction

In the LevelDB source code, there’s a function for getting a Comparator that seemed a bit strange when I first saw it. It looks like it constructs a singleton, but it’s slightly more complex. The complete code is as follows:

1
2
3
4
5
// util/comparator.cc
const Comparator* BytewiseComparator() {
static NoDestructor<BytewiseComparatorImpl> singleton;
return singleton.get();
}

Here, NoDestructor is a template class that, judging by its name, is used to prevent object destruction. Why prevent object destruction, and how is it achieved? This article will delve into these questions.

Read More