【发布时间】:2019-08-14 08:34:54
【问题描述】:
我正在使用 LMDB 在我的应用程序中记录时间序列数据。条目会定期或在特定事件中添加到数据库中。我正在添加清除旧条目的机制,以避免数据库不成比例地增长。但是,我希望能够处理在执行任何清理之前达到地图大小限制的情况 (MDB_MAP_FULL)。
我的问题是,一旦达到 MDB_MAP_FULL,在删除条目时也会出现 MDB_MAP_FULL 错误。也就是说,我无法通过从数据库中删除条目来恢复到有效状态。
在获得 MDB_MAP_FULL 后增加环境映射大小似乎可以解决问题,但我不想每次达到大小限制时都必须增加映射大小。此外,这会导致线程安全问题,因为如果同一进程中有活动事务,则无法调用 mdb_env_set_mapsize。
有没有办法在不增加地图大小的情况下恢复到有效状态?我在代码中做错了什么使数据库处于无效状态吗?
以下代码 sn-p 重现了我的问题。我将条目添加到数据库中,直到出现 MDB_MAP_FULL 错误。然后,我尝试从数据库中删除所有条目。获得 MDB_MAP_FULL 后,我可以删除一些条目,但最终我会再次获得 MDB_MAP_FULL。
// Create environment
MDB_env* env;
int ec = mdb_env_create(&env);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to create database environment", ec);
}
// Set mapsize
size_t maxSizeInBytes = 20*boost::interprocess::mapped_region::get_page_size();
ec = mdb_env_set_mapsize(env, maxSizeInBytes);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to configure database environment memory map size", ec);
}
// Open environment
ec = mdb_env_open(env, dbPath.c_str(), 0, 0644);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to open database environment", ec);
}
// Open database
MDB_dbi dbi;
{
MDB_txn* txn;
ec = mdb_txn_begin(env, nullptr, 0, &txn);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to start database transaction", ec);
}
ec = mdb_dbi_open(txn, nullptr, MDB_INTEGERKEY, &dbi);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to open database", ec);
}
ec = mdb_txn_commit(txn);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to commit database transaction", ec);
}
}
// Fill DB
size_t elementsAdded = 0;
size_t maxCount = 1000000; // Set limit to ensure test does not hang in case of some error
for (size_t i = 0; i < maxCount; i++) {
MDB_txn* txn;
ec = mdb_txn_begin(env, nullptr, 0, &txn);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to start database transaction", ec);
}
int value = std::rand();
MDB_val db_key{sizeof(size_t), (void*)(&i)};
MDB_val db_data{sizeof(int), (void*)(&value)};
ec = mdb_put(txn, dbi, &db_key, &db_data, 0);
if (ec != MDB_SUCCESS) {
mdb_txn_abort(txn);
throw Lmdb::LmdbError("Unable to add database entry", ec);
}
ec = mdb_txn_commit(txn);
if (ec == MDB_MAP_FULL) {
elementsAdded = i;
SqPrintMessage("Reached max size on put commit at index: %d", i);
break;
} else if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to commit database transaction", ec);
}
}
// Attempt deleting entries
for (size_t i = 0; i < elementsAdded; i++) {
MDB_txn* txn;
ec = mdb_txn_begin(env, nullptr, 0, &txn);
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to start database transaction", ec);
}
MDB_val db_key{sizeof(size_t), (void*)(&i)};
ec = mdb_del(txn, dbi, &db_key, nullptr);
if (ec != MDB_SUCCESS) {
mdb_txn_abort(txn);
throw Lmdb::LmdbError("Unable to delete database entry", ec);
}
ec = mdb_txn_commit(txn);
if (ec == MDB_MAP_FULL) {
SqPrintMessage("Reached max size on delete commit at index: %d", i);
break;
} else if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to commit database transaction", ec);
}
}
// Close environment
mdb_env_close(env);
输出:
Reached max size on put commit at index: 1657
Reached max size on delete commit at index: 137
添加
ec = mdb_env_set_mapsize(env, maxSizeInBytes + 2*boost::interprocess::mapped_region::get_page_size());
if (ec != MDB_SUCCESS) {
throw Lmdb::LmdbError("Unable to configure database environment memory map size", ec);
}
在第一个循环之后,删除元素时我没有得到 MDB_MAP_FULL。
【问题讨论】:
标签: lmdb