Skip to content

Commit 6de937d

Browse files
andrewgithubandrewgithub
andrewgithub
authored and
andrewgithub
committed
添加对比工具示例实现说明 Options bit cmp
1 parent 18c9c8a commit 6de937d

File tree

4 files changed

+258
-6
lines changed

4 files changed

+258
-6
lines changed

demo/test.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,28 @@
88
#include <string>
99
#include <algorithm>
1010

11+
#include <type_traits>
12+
#include <utility>
13+
1114
using namespace std;
1215

16+
17+
1318
const uint64_t CREATE_SQL_STR_LEN = 1024 * 1024;
1419

1520
int main(int argc, char *argv[]) {
1621

17-
char lpCreateSQL[CREATE_SQL_STR_LEN];
18-
memset(lpCreateSQL, 0 , sizeof(lpCreateSQL));
1922

20-
auto nRet = snprintf(lpCreateSQL, CREATE_SQL_STR_LEN, "%s", "create virtual table ");
23+
struct sql {
24+
sql() {std::cout << "==========" << std::endl;}
25+
uint64_t data;
26+
int sql_;
27+
char name[CREATE_SQL_STR_LEN];
28+
char tea;
29+
};
2130

22-
nRet += snprintf(lpCreateSQL + nRet, CREATE_SQL_STR_LEN- nRet, "%s", "create virtual table ");
23-
nRet += snprintf(lpCreateSQL + nRet, CREATE_SQL_STR_LEN- nRet, "%s", "create virtual table ");
31+
typename std::aligned_storage<sizeof(sql),
32+
alignof(sql)>::type instance_storage_;
2433

2534

2635
return 0;

doc/index.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ leveldb库提供了一个持久的键值存储。键和值可以是任意字节
3030
____
3131

3232

33-
3433
include::instruction/readme.adoc[readme]
3534
include::instruction/impl.adoc[impl]
3635

3736
include::persistence/log_format.adoc[log_format]
3837

38+
include::utils/c++_common_knowledge.adoc[common_knowledge]
39+
3940

4041

4142

doc/instruction/readme.adoc

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,133 @@ endif::rootpath[]
5757

5858
=== 打开一个数据库
5959

60+
使用 `static Status Open(const Options &options, const std::string &name, DB **dbptr)` 可以打开一个数据库, options填入数据库打开选项,name指定数据库名,DB给出一个数据库指针(原先指向nullptr),因为调用之后会把创建的数据库句柄赋值给对应的指针。
6061

62+
- Options 用来控制数据库行为的一些参数在调用 `DB::Open` 的时候使用。
63+
64+
[source,c++]
65+
----
66+
struct LEVELDB_EXPORT Options {
67+
// Create an Options object with default values for all fields.
68+
Options();
69+
70+
// -------------------
71+
// Parameters that affect behavior
72+
73+
// Comparator used to define the order of keys in the table.
74+
// Default: a comparator that uses lexicographic byte-wise ordering
75+
//
76+
// REQUIRES: The client must ensure that the comparator supplied
77+
// here has the same name and orders keys *exactly* the same as the
78+
// comparator provided to previous open calls on the same DB.
79+
const Comparator *comparator;
80+
81+
// If true, the database will be created if it is missing.
82+
bool create_if_missing = false;
83+
84+
// If true, an error is raised if the database already exists.
85+
bool error_if_exists = false;
86+
87+
// If true, the implementation will do aggressive checking of the
88+
// data it is processing and will stop early if it detects any
89+
// errors. This may have unforeseen ramifications: for example, a
90+
// corruption of one DB entry may cause a large number of entries to
91+
// become unreadable or for the entire DB to become unopenable.
92+
bool paranoid_checks = false;
93+
94+
// Use the specified object to interact with the environment,
95+
// e.g. to read/write files, schedule background work, etc.
96+
// Default: Env::Default()
97+
Env *env;
98+
99+
// Any internal progress/error information generated by the db will
100+
// be written to info_log if it is non-null, or to a file stored
101+
// in the same directory as the DB contents if info_log is null.
102+
Logger *info_log = nullptr;
103+
104+
// -------------------
105+
// Parameters that affect performance
106+
107+
// Amount of data to build up in memory (backed by an unsorted log
108+
// on disk) before converting to a sorted on-disk file.
109+
//
110+
// Larger values increase performance, especially during bulk loads.
111+
// Up to two write buffers may be held in memory at the same time,
112+
// so you may wish to adjust this parameter to control memory usage.
113+
// Also, a larger write buffer will result in a longer recovery time
114+
// the next time the database is opened.
115+
size_t write_buffer_size = 4 * 1024 * 1024;
116+
117+
// Number of open files that can be used by the DB. You may need to
118+
// increase this if your database has a large working set (budget
119+
// one open file per 2MB of working set).
120+
int max_open_files = 1000;
121+
122+
// Control over blocks (user data is stored in a set of blocks, and
123+
// a block is the unit of reading from disk).
124+
125+
// If non-null, use the specified cache for blocks.
126+
// If null, leveldb will automatically create and use an 8MB internal cache.
127+
Cache *block_cache = nullptr;
128+
129+
// Approximate size of user data packed per block. Note that the
130+
// block size specified here corresponds to uncompressed data. The
131+
// actual size of the unit read from disk may be smaller if
132+
// compression is enabled. This parameter can be changed dynamically.
133+
size_t block_size = 4 * 1024;
134+
135+
// Number of keys between restart points for delta encoding of keys.
136+
// This parameter can be changed dynamically. Most clients should
137+
// leave this parameter alone.
138+
int block_restart_interval = 16;
139+
140+
// Leveldb will write up to this amount of bytes to a file before
141+
// switching to a new one.
142+
// Most clients should leave this parameter alone. However if your
143+
// filesystem is more efficient with larger files, you could
144+
// consider increasing the value. The downside will be longer
145+
// compactions and hence longer latency/performance hiccups.
146+
// Another reason to increase this parameter might be when you are
147+
// initially populating a large database.
148+
size_t max_file_size = 2 * 1024 * 1024;
149+
150+
// Compress blocks using the specified compression algorithm. This
151+
// parameter can be changed dynamically.
152+
//
153+
// Default: kSnappyCompression, which gives lightweight but fast
154+
// compression.
155+
//
156+
// Typical speeds of kSnappyCompression on an Intel(R) Core(TM)2 2.4GHz:
157+
// ~200-500MB/s compression
158+
// ~400-800MB/s decompression
159+
// Note that these speeds are significantly faster than most
160+
// persistent storage speeds, and therefore it is typically never
161+
// worth switching to kNoCompression. Even if the input data is
162+
// incompressible, the kSnappyCompression implementation will
163+
// efficiently detect that and will switch to uncompressed mode.
164+
CompressionType compression = kSnappyCompression;
165+
166+
// EXPERIMENTAL: If true, append to existing MANIFEST and log files
167+
// when a database is opened. This can significantly speed up open.
168+
//
169+
// Default: currently false, but may become true later.
170+
bool reuse_logs = false;
171+
172+
// If non-null, use the specified filter policy to reduce disk reads.
173+
// Many applications will benefit from passing the result of
174+
// NewBloomFilterPolicy() here.
175+
const FilterPolicy *filter_policy = nullptr;
176+
};
177+
----
178+
179+
180+
// Open the database with the specified "name".
181+
// Stores a pointer to a heap-allocated database in *dbptr and returns
182+
// OK on success.
183+
// Stores nullptr in *dbptr and returns a non-OK status on error.
184+
// Caller should delete *dbptr when it is no longer needed.
185+
static Status Open(const Options &options, const std::string &name,
186+
DB **dbptr);
61187
A leveldb database has a name which corresponds to a file system directory. All
62188
of the contents of database are stored in this directory. The following example
63189
shows how to open a database, creating it if necessary:

doc/utils/c++_common_knowledge.adoc

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
2+
:toc:
3+
4+
:icons: font
5+
6+
// 保证所有的目录层级都可以正常显示图片
7+
:path: utils/
8+
:imagesdir: ../image/
9+
:srcdir: ../src
10+
11+
12+
// 只有book调用的时候才会走到这里
13+
ifdef::rootpath[]
14+
:imagesdir: {rootpath}{path}{imagesdir}
15+
:srcdir: {rootpath}../src/
16+
endif::rootpath[]
17+
18+
ifndef::rootpath[]
19+
:rootpath: ../
20+
:srcdir: {rootpath}{path}../src/
21+
endif::rootpath[]
22+
23+
24+
== Common Knowledge
25+
26+
在学习levelDB数据库的时候,可能遇见一些平常并不是很常见但是很实用的知识点,这里会对这些知识点进行总结。
27+
28+
=== 如何优雅创建一个实例
29+
30+
在创建数据库时,需要传入 `Options` 该对象在构造的时候需要传入一个对比工具,levelDB中数据库不支持并发,因此在进行创建数据库时每个数据库句柄都是创建之后一直到停止使用结束的,那么这个对比工具也是要保证数据库有效的时间内都能正常使用。
31+
32+
这个时候单例模式就体现出作用来了,这里levelDB使用了经典的饿汉式单例创建方式。这个单例创建模式没有什么新颖的地方,最主要的在这个示例对象中有需要学习的地方。
33+
34+
[source, cpp]
35+
----
36+
const Comparator *BytewiseComparator() {
37+
static NoDestructor<BytewiseComparatorImpl> singleton;
38+
return singleton.get();
39+
}
40+
----
41+
42+
- `alignof` 去对其长度,准确的来说就是一个结构体中对齐长度,比如下面的结构体:
43+
44+
[source, cpp]
45+
----
46+
struct sql {
47+
uint64_t data;
48+
int sql_;
49+
char name[CREATE_SQL_STR_LEN];
50+
char tea;
51+
};
52+
----
53+
54+
`alignof(sql)` 返回的结果就是8,也就是这个结构体需要按照8字节对其,当我们去除uint64_t的时候,再求对齐长度就会变成4,也就是一个结构体中按照最长位的那个类型进行对齐。
55+
56+
- 使用 `new (ptr) T(args)` 特性来实现对象的申请,当我们申请一个对象时,如果想要使用自己指定的内存来存储对象,就可以使用new提供的placement方法来事先,使用方法就是new 后面紧跟一个小括号,并在小括号中放入你想存放对象的内存地址。
57+
- 使用 `aligned_storage` 来确保定在定义的数据对象占用内存大小,肯定大于需要对外提供内存的大小。
58+
59+
aligned_storage是C++标准库中的一个模板类,定义在<type_traits>头文件中。它提供了一种用于按照指定对齐要求分配内存的机制。
60+
61+
aligned_storage模板类的定义如下:
62+
[souece, cpp]
63+
----
64+
template <std::size_t Len, std::size_t Align>
65+
struct aligned_storage;
66+
----
67+
其中,Len表示所需的内存大小,Align表示所需的对齐要求。
68+
69+
aligned_storage模板类在需要手动控制内存对齐的情况下非常有用。它提供了一种安全和便捷的方式来分配按照指定对齐要求的内存块,并可以通过类型别名来使用这个内存块。
70+
71+
需要注意的是,aligned_storage只提供了对齐内存的分配,但不会自动构造和析构对象。如果需要在对齐内存中存储对象,还需要进行适当的构造和析构操作。
72+
73+
*最终代码实现效果*
74+
[source, cpp]
75+
----
76+
// Wraps an instance whose destructor is never called.
77+
//
78+
// This is intended for use with function-level static variables.
79+
template <typename InstanceType>
80+
class NoDestructor {
81+
public:
82+
template <typename... ConstructorArgTypes>
83+
explicit NoDestructor(ConstructorArgTypes&&... constructor_args) {
84+
static_assert(sizeof(instance_storage_) >= sizeof(InstanceType),
85+
"instance_storage_ is not large enough to hold the instance");
86+
static_assert(
87+
alignof(decltype(instance_storage_)) >= alignof(InstanceType),
88+
"instance_storage_ does not meet the instance's alignment requirement");
89+
new (&instance_storage_)
90+
InstanceType(std::forward<ConstructorArgTypes>(constructor_args)...);
91+
}
92+
93+
~NoDestructor() = default;
94+
95+
NoDestructor(const NoDestructor&) = delete;
96+
NoDestructor& operator=(const NoDestructor&) = delete;
97+
98+
InstanceType* get() {
99+
return reinterpret_cast<InstanceType*>(&instance_storage_);
100+
}
101+
102+
private:
103+
// 注意这里只是申请了一块 >= 指定大小的内存,并不会调用对应对象的构造函数,在对象声明周期结束时也不会调用对象的析构函数,都需要用户自己手动调用
104+
typename std::aligned_storage<sizeof(InstanceType),
105+
alignof(InstanceType)>::type instance_storage_;
106+
};
107+
108+
----
109+
110+
*总结*
111+
112+
这一个实例的创建使用了三个比较重要的C++知识点,alignof取结构体对齐长度,`new(placement new)` 来实现预分配内存的new,在结合 `aligned_storage` 来保证已有对象内存绝对大于等于需要申请对象的内存,然后经过饿汉式单例模式封装,经过以上几个步骤之后,一个能长久陪伴数据库句柄的对比工具便诞生了。
113+
114+
115+
116+

0 commit comments

Comments
 (0)