c++ - 具有并发读写的嵌入式数据库
问题描述
我正在寻找并发写入器和读取器问题的数据库解决方案。我需要一个嵌入式数据库,它将由单个编写器进程编写。同一个数据库将由单个读取器进程读取,并且这些进程同时运行。
我看过像RocksDB这样的解决方案,但是我们可以有多个读取器和一个写入器,但是读取器在打开一次后没有数据库的最新视图,因此必须再次打开数据库。
任何帮助都会很棒。
编辑
我为 RocksDB 编写的代码 -
作家.cc
#include <cstdio>
#include <string>
#include <unistd.h>
#include <iostream>
#include "rocksdb/db.h"
#include "rocksdb/slice.h"
#include "rocksdb/options.h"
using namespace rocksdb;
std::string kDBPath = "./db";
int main() {
DB* db;
Options options;
options.IncreaseParallelism();
options.OptimizeLevelStyleCompaction();
options.create_if_missing = true;
Status s = DB::Open(options, kDBPath, &db);
assert(s.ok());
for (int i = 0 ; ; i++) {
int key = i;
Slice kslice((char*)&key, sizeof(int));
int value = i*i;
Slice vslice((char*)&value, sizeof(value));
s = db->Put(WriteOptions(), kslice, vslice);
std::cout << "writing " << i << " : " << i*i << std::endl;
assert(s.ok());
sleep(1);
}
delete db;
return 0;
}
输出如预期:
writing 0 : 0
writing 1 : 1
writing 2 : 4
writing 3 : 9
writing 4 : 16
writing 5 : 25
writing 6 : 36
writing 7 : 49
writing 8 : 64
writing 9 : 81
...
读者.cc
#include <cstdio>
#include <string>
#include <unistd.h>
#include <iostream>
#include "rocksdb/db.h"
#include "rocksdb/slice.h"
#include "rocksdb/options.h"
using namespace rocksdb;
using namespace std;
std::string kDBPath = "./db";
int main() {
DB* db;
Options options;
options.IncreaseParallelism();
options.OptimizeLevelStyleCompaction();
Status s = DB::OpenForReadOnly(options, kDBPath, &db);
assert(s.ok());
int i = 0;
while(true) {
sleep(1);
std::string value;
Slice kslice((char*)&i, sizeof(int));
Status s = db->Get(ReadOptions(), kslice, &value);
if (!s.ok()) {
std::cout << i << " " << s.ToString() << std::endl;
break;
}
int a;
memcpy(&a, value.c_str(), sizeof(a));
std::cout << i << ":" << a << std::endl;
i++;
}
delete db;
return 0;
}
输出是(在添加键 3 而不是键 4 之后开始)
0:0
1:1
2:4
3:9
4 NotFound:
我尝试过的一种可能的解决方案是:
Iterator* it = db->NewIterator(ReadOptions());
int start = 0;
Slice kslice((char*)&start, sizeof(int));
it->Seek(kslice);
bool flag = true;
while (true) {
int key, value;
for ( ; it->Valid() ; it->Next()) {
memcpy(&key, it->key().ToString().c_str(), sizeof(int));
memcpy(&value, it->value().ToString().c_str(), sizeof(int));
cout << key << " - " << value << endl;
if (!it->status().ok()) {
cout << s.ToString() << endl;
flag = false;
}
}
if (!flag)
break;
sleep(1);
Status s = DB::OpenForReadOnly(options, kDBPath, &db);
assert(s.ok());
Slice kslice((char*)&key, sizeof(int));
it = db->NewIterator(ReadOptions());
it->Seek(kslice);
it->Next();
}
输出如预期:
writing 0 : 0
writing 1 : 1
writing 2 : 4
writing 3 : 9
writing 4 : 16
writing 5 : 25
writing 6 : 36
writing 7 : 49
writing 8 : 64
writing 9 : 81
...
但是,我想避免每次更新时一次又一次地读取数据库。
解决方案
RocksDB 被明确记录为仅支持单个进程中的多线程并发。您不能从多个进程中安全地使用它。
LMDB 被明确记录以支持多进程并发,并且 LMDB 读取器和写入器运行时不会相互阻塞。它会做你想做的事。
推荐阅读
- angular - 给出错误结果的时刻日期格式
- python - Python:打印列差异
- javascript - Angular / Typescript使用方法中的参数值作为js对象值
- r - 整个矩阵行只取 3 个数值的最后一个值
- java - 具有不支持线程的函数的 Java ExecutorService 线程
- c# - 在 C# 中,`new List 的结果容量是什么
() {3,5};`? - javascript - Vuetify - 如何使用 setTimeout 函数更改 v-img 源
- javascript - 使用 npx create-react-app newapp 命令,但在一段时间后它显示 57 个包正在寻找资金
- python - 错误:命令出错,退出状态为 1
- angular - API POST 请求:空值与空值与已删除值