Drop the experimental LMDB backend

In the three years that LMDB support has been in the tree, and four
since upstream promised 1.0.0 in a couple of months, there have been
no upstream changes towards eliminating the key size limitations that
we need. And in the meanwhile it has become clearer that LMDB is not
the promised land it seemed on the outset, instead it has issues
like requiring the database size to be pre-determined (#902).

Drop support for LMDB, there's active development going on in the area
of database backends and we cannot afford to drag along an experimental
backend that is blocked on upstream design limitations and shows no signs
of moving forward. We can always bring it back if the upstream situation
changes.
This commit is contained in:
Panu Matilainen 2020-03-19 10:25:11 +02:00
parent 8cd161b5bb
commit 7de982ac09
7 changed files with 0 additions and 987 deletions

View File

@ -608,30 +608,6 @@ AS_IF([test "$enable_bdb_ro" = yes],[
])
AM_CONDITIONAL([BDB_RO], [test "$enable_bdb_ro" = yes])
#=================
# Check for LMDB support
AC_ARG_ENABLE([lmdb],
[AS_HELP_STRING([--enable-lmdb=@<:@yes/no/auto@:>@ (EXPERIMENTAL)],
[build with LMDB rpm database format support (default=auto)])],
[enable_lmdb="$enableval"],
[enable_lmdb=auto])
AS_IF([test "x$enable_lmdb" != "xno"], [
PKG_CHECK_MODULES([LMDB], [lmdb], [have_lmdb=yes], [have_lmdb=no])
AS_IF([test "$enable_lmdb" = "yes"], [
if test "$have_lmdb" = "no"; then
AC_MSG_ERROR([--enable-lmdb specified, but not available])
fi
])
])
if test "x$have_lmdb" = "xyes"; then
AC_DEFINE([WITH_LMDB], [1], [Define if LMDB is available])
LMDB_REQUIRES=lmdb
AC_SUBST(LMDB_REQUIRES)
fi
AM_CONDITIONAL([LMDB], [test "x$have_lmdb" = "xyes"])
# Check for SQLITE support
AC_ARG_ENABLE([sqlite],
[AS_HELP_STRING([--enable-sqlite=@<:@yes/no/auto@:>@)],

View File

@ -7,7 +7,6 @@ AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
AM_CPPFLAGS += $(LMDB_CFLAGS)
AM_CPPFLAGS += -I$(top_srcdir)/misc
AM_CPPFLAGS += -DLOCALEDIR="\"$(localedir)\""
AM_CPPFLAGS += -DSYSCONFDIR="\"$(sysconfdir)\""
@ -83,13 +82,6 @@ librpm_la_SOURCES += \
backend/ndb/rpmxdb.h
endif
if LMDB
AM_CPPFLAGS += $(LMDB_CFLAGS)
librpm_la_LIBADD += $(LMDB_LIBS)
librpm_la_SOURCES += \
backend/lmdb.c
endif
if SQLITE
AM_CPPFLAGS += $(SQLITE_CFLAGS)
librpm_la_LIBADD += $(SQLITE_LIBS)

View File

@ -16,9 +16,6 @@ const struct rpmdbOps_s *backends[] = {
#if defined(WITH_SQLITE)
&sqlite_dbops,
#endif
#if defined(WITH_LMDB)
&lmdb_dbops,
#endif
#ifdef ENABLE_NDB
&ndb_dbops,
#endif

View File

@ -285,11 +285,6 @@ RPM_GNUC_INTERNAL
extern struct rpmdbOps_s ndb_dbops;
#endif
#if defined(WITH_LMDB)
RPM_GNUC_INTERNAL
extern struct rpmdbOps_s lmdb_dbops;
#endif
#if defined(WITH_SQLITE)
RPM_GNUC_INTERNAL
extern struct rpmdbOps_s sqlite_dbops;

View File

@ -1,945 +0,0 @@
/** \ingroup rpmdb
* \file lib/lmdb.c
*/
#include "system.h"
#include <ctype.h>
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
#include <lmdb.h>
#include <signal.h>
#include <rpm/rpmtypes.h>
#include <rpm/rpmmacro.h>
#include <rpm/rpmfileutil.h>
#include <rpm/rpmlog.h>
#include "lib/rpmdb_internal.h"
#include "debug.h"
static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
struct dbiCursor_s {
dbiIndex dbi;
const void *key;
unsigned int keylen;
int flags;
MDB_cursor * cursor;
MDB_txn * txn;
};
static const char * _EnvF(unsigned eflags)
{
static char t[256];
char *te = t;
*te = '\0';
#define _EF(_v) if (eflags & MDB_##_v) te = stpcpy(stpcpy(te,"|"),#_v)
_EF(FIXEDMAP);
_EF(NOSUBDIR);
_EF(NOSYNC);
_EF(RDONLY);
_EF(NOMETASYNC);
_EF(WRITEMAP);
_EF(MAPASYNC);
_EF(NOTLS);
_EF(NOLOCK);
_EF(NORDAHEAD);
_EF(NOMEMINIT);
#undef _EF
if (t[0] == '\0') te += sprintf(te, "|0x%x", eflags);
*te = '\0';
return t+1;
}
static const char * _OpenF(unsigned oflags)
{
static char t[256];
char *te = t;
*te = '\0';
#define _OF(_v) if (oflags & MDB_##_v) te = stpcpy(stpcpy(te,"|"),#_v)
_OF(REVERSEKEY);
_OF(DUPSORT);
_OF(INTEGERKEY);
_OF(DUPFIXED);
_OF(INTEGERDUP);
_OF(REVERSEDUP);
_OF(CREATE);
#undef _OF
if (t[0] == '\0') te += sprintf(te, "|0x%x", oflags);
*te = '\0';
return t+1;
}
static int dbapi_err(rpmdb rdb, const char * msg, int rc, int printit)
{
if (printit && rc) {
int lvl = RPMLOG_ERR;
if (msg)
rpmlog(lvl, _("%s:\trc(%d) = %s(): %s\n"),
rdb->db_descr, rc, msg, (rc ? mdb_strerror(rc) : ""));
else
rpmlog(lvl, _("%s:\trc(%d) = %s()\n"),
rdb->db_descr, rc, (rc ? mdb_strerror(rc) : ""));
}
return rc;
}
static int cvtdberr(dbiIndex dbi, const char * msg, int rc, int printit)
{
return dbapi_err(dbi->dbi_rpmdb, msg, rc, printit);
}
static void lmdb_assert(MDB_env *env, const char *msg)
{
rpmlog(RPMLOG_ERR, "%s: %s\n", __FUNCTION__, msg);
}
static void lmdb_dbSetFSync(rpmdb rdb, int enable)
{
}
static int lmdb_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
{
return 0;
}
static int db_fini(rpmdb rdb, const char * dbhome)
{
int rc = 0;
MDB_env * env = rdb->db_dbenv;
if (env == NULL)
goto exit;
if (--rdb->db_opens > 0)
goto exit;
mdb_env_close(env);
rdb->db_dbenv = env = NULL;
rpmlog(RPMLOG_DEBUG, "closed db environment %s\n", dbhome);
exit:
return rc;
}
static int db_init(rpmdb rdb, const char * dbhome)
{
int rc = EINVAL;
MDB_env * env = NULL;
int retry_open = 2;
uint32_t eflags = 0;
if (rdb->db_dbenv != NULL) {
rdb->db_opens++;
return 0;
}
MDB_dbi maxdbs = 32;
unsigned int maxreaders = 16;
size_t mapsize = 1024 * 1024 * 1024;
if ((rc = mdb_env_create(&env))
|| (rc = mdb_env_set_maxreaders(env, maxreaders))
|| (rc = mdb_env_set_mapsize(env, mapsize))
|| (rc = mdb_env_set_maxdbs(env, maxdbs))
|| (rc = mdb_env_set_assert(env, lmdb_assert))
|| (rc = mdb_env_set_userctx(env, rdb))
) {
rc = dbapi_err(rdb, "mdb_env_create", rc, _debug);
goto exit;
}
/*
* Actually open the environment. Fall back to private environment
* if we dont have permission to join/create shared environment or
* system doesn't support it..
*/
while (retry_open) {
rpmlog(RPMLOG_DEBUG, "opening db environment %s eflags=%s perms=0%o\n", dbhome, _EnvF(eflags), rdb->db_perms);
eflags = 0;
eflags |= MDB_WRITEMAP;
eflags |= MDB_MAPASYNC;
eflags |= MDB_NOTLS;
if (access(dbhome, W_OK) && (rdb->db_mode & O_ACCMODE) == O_RDONLY)
eflags |= MDB_RDONLY;
rc = mdb_env_open(env, dbhome, eflags, rdb->db_perms);
if (rc) {
rc = dbapi_err(rdb, "mdb_env_open", rc, _debug);
if (rc == EPERM)
rpmlog(RPMLOG_ERR, "lmdb: %s(%s/lock.mdb): %s\n", __FUNCTION__, dbhome, mdb_strerror(rc));
}
retry_open = 0; /* XXX EAGAIN might need a retry */
}
if (rc)
goto exit;
rdb->db_dbenv = env;
rdb->db_opens = 1;
exit:
if (rc && env) {
mdb_env_close(env);
rdb->db_dbenv = env = NULL;
}
return rc;
}
static int dbiSync(dbiIndex dbi, unsigned int flags)
{
int rc = 0;
MDB_dbi db = (unsigned long) dbi->dbi_db;
if (db != 0xdeadbeef && !dbi->cfg.dbi_no_dbsync) {
MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
unsigned eflags = 0;
rc = mdb_env_get_flags(env, &eflags);
if (rc) {
rc = cvtdberr(dbi, "mdb_env_get_flags", rc, _debug);
eflags |= MDB_RDONLY;
}
if (!(eflags & MDB_RDONLY)) {
int force = 0;
rc = mdb_env_sync(env, force);
if (rc)
rc = cvtdberr(dbi, "mdb_env_sync", rc, _debug);
}
}
return rc;
}
static dbiCursor lmdb_dbiCursorInit(dbiIndex dbi, unsigned int flags)
{
dbiCursor dbc = NULL;
if (dbi && dbi->dbi_db != (void *)0xdeadbeefUL) {
MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
MDB_txn * parent = NULL;
unsigned tflags = !(flags & DBC_WRITE) ? MDB_RDONLY : 0;
MDB_txn * txn = NULL;
MDB_cursor * cursor = NULL;
int rc = EINVAL;
rc = mdb_txn_begin(env, parent, tflags, &txn);
if (rc)
rc = cvtdberr(dbi, "mdb_txn_begin", rc, _debug);
if (rc == 0) {
MDB_dbi db = (unsigned long) dbi->dbi_db;
rc = mdb_cursor_open(txn, db, &cursor);
if (rc)
rc = cvtdberr(dbi, "mdb_cursor_open", rc, _debug);
}
if (rc == 0) {
dbc = xcalloc(1, sizeof(*dbc));
dbc->dbi = dbi;
dbc->flags = flags;
dbc->cursor = cursor;
dbc->txn = txn;
}
}
return dbc;
}
static dbiCursor lmdb_dbiCursorFree(dbiIndex dbi, dbiCursor dbc)
{
if (dbc) {
int rc = 0;
MDB_cursor * cursor = dbc->cursor;
MDB_txn * txn = dbc->txn;
dbiIndex dbi = dbc->dbi;
unsigned flags = dbc->flags;
mdb_cursor_close(cursor);
dbc->cursor = cursor = NULL;
if (rc)
cvtdberr(dbc->dbi, "mdb_cursor_close", rc, _debug);
/* Automatically commit close */
if (txn) {
rc = mdb_txn_commit(txn);
dbc->txn = txn = NULL;
if (rc)
rc = cvtdberr(dbc->dbi, "mdb_txn_commit", rc, _debug);
}
/* Automatically sync on write-cursor close */
if (flags & DBC_WRITE)
dbiSync(dbi, 0);
free(dbc);
rc = 0;
}
return NULL;
}
static int dbiCursorPut(dbiCursor dbc, MDB_val * key, MDB_val * data, unsigned flags)
{
int rc = EINVAL;
int sane = (key->mv_data != NULL && key->mv_size > 0 &&
data->mv_data != NULL && data->mv_size > 0);
if (dbc && sane) {
MDB_cursor * cursor = dbc->cursor;
rpmdb rdb = dbc->dbi->dbi_rpmdb;
rpmswEnter(&rdb->db_putops, (ssize_t) 0);
rc = mdb_cursor_put(cursor, key, data, flags);
if (rc) {
rc = cvtdberr(dbc->dbi, "mdb_cursor_put", rc, _debug);
if (dbc->txn) {
mdb_txn_abort(dbc->txn);
dbc->txn = NULL;
}
}
rpmswExit(&rdb->db_putops, (ssize_t) data->mv_size);
}
return rc;
}
static int dbiCursorGet(dbiCursor dbc, MDB_val *key, MDB_val *data, unsigned op)
{
int rc = EINVAL;
int sane = ((op == MDB_NEXT) || (key->mv_data != NULL && key->mv_size > 0));
if (dbc && sane) {
MDB_cursor * cursor = dbc->cursor;
rpmdb rdb = dbc->dbi->dbi_rpmdb;
rpmswEnter(&rdb->db_getops, 0);
/* XXX db4 does DB_FIRST on uninitialized cursor */
rc = mdb_cursor_get(cursor, key, data, op);
if (rc && rc != MDB_NOTFOUND) {
rc = cvtdberr(dbc->dbi, "mdb_cursor_get", rc, _debug);
if (dbc->txn) {
mdb_txn_abort(dbc->txn);
dbc->txn = NULL;
}
}
/* Remember the last key fetched */
if (rc == 0) {
dbc->key = key->mv_data;
dbc->keylen = key->mv_size;
} else {
dbc->key = NULL;
dbc->keylen = 0;
}
rpmswExit(&rdb->db_getops, data->mv_size);
}
return rc;
}
static int dbiCursorDel(dbiCursor dbc, MDB_val *key, MDB_val *data, unsigned int flags)
{
int rc = EINVAL;
int sane = (key->mv_data != NULL && key->mv_size > 0);
if (dbc && sane) {
MDB_cursor * cursor = dbc->cursor;
rpmdb rdb = dbc->dbi->dbi_rpmdb;
rpmswEnter(&rdb->db_delops, 0);
/* XXX TODO: ensure that cursor is positioned with duplicates */
rc = mdb_cursor_get(cursor, key, data, MDB_SET);
if (rc && rc != MDB_NOTFOUND) {
rc = cvtdberr(dbc->dbi, "mdb_cursor_get", rc, _debug);
if (dbc->txn)
dbc->txn = NULL;
}
if (rc == 0) {
rc = mdb_cursor_del(cursor, flags);
if (rc)
rc = cvtdberr(dbc->dbi, "mdb_cursor_del", rc, _debug);
}
rpmswExit(&rdb->db_delops, data->mv_size);
}
return rc;
}
static int lmdb_dbiVerify(dbiIndex dbi, unsigned int flags)
{
return 0;
}
static int lmdb_dbiClose(dbiIndex dbi, unsigned int flags)
{
int rc = 0;
rpmdb rdb = dbi->dbi_rpmdb;
const char * dbhome = rpmdbHome(rdb);
MDB_dbi db = (unsigned long) dbi->dbi_db;
if (db != 0xdeadbeef) {
MDB_env * env = dbi->dbi_rpmdb->db_dbenv;
mdb_dbi_close(env, db);
dbi->dbi_db = (void *) 0xdeadbeefUL;
rpmlog(RPMLOG_DEBUG, "closed db index %s/%s\n",
dbhome, dbi->dbi_file);
}
db_fini(rdb, dbhome ? dbhome : "");
dbi = dbiFree(dbi);
return rc;
}
static int lmdb_dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
{
int rc = 1;
const char *dbhome = rpmdbHome(rdb);
dbiIndex dbi = NULL;
int retry_open;
MDB_dbi db = 0;
uint32_t oflags;
if (dbip)
*dbip = NULL;
if ((dbi = dbiNew(rdb, rpmtag)) == NULL)
goto exit;
dbi->dbi_flags = 0;
dbi->dbi_db = (void *) 0xdeadbeefUL;
rc = db_init(rdb, dbhome);
retry_open = (rc == 0) ? 2 : 0;
do {
MDB_env * env = rdb->db_dbenv;
MDB_txn * parent = NULL;
unsigned tflags = access(dbhome, W_OK) ? MDB_RDONLY : 0;
MDB_txn * txn = NULL;
if (tflags & MDB_RDONLY)
dbi->dbi_flags |= DBI_RDONLY;
rc = mdb_txn_begin(env, parent, tflags, &txn);
if (rc)
rc = cvtdberr(dbi, "mdb_txn_begin", rc, _debug);
const char * name = dbi->dbi_file;
oflags = 0;
if (!(tflags & MDB_RDONLY))
oflags |= MDB_CREATE;
if (!strcmp(dbi->dbi_file, "Packages"))
oflags |= MDB_INTEGERKEY;
rpmlog(RPMLOG_DEBUG, "opening db index %s/%s oflags=%s\n",
dbhome, dbi->dbi_file, _OpenF(oflags));
db = 0xdeadbeef;
rc = mdb_dbi_open(txn, name, oflags, &db);
if (rc && rc != MDB_NOTFOUND) {
rc = cvtdberr(dbi, "mdb_dbi_open", rc, _debug);
if (txn) {
mdb_txn_abort(txn);
txn = NULL;
db = 0xdeadbeef;
}
}
if (txn) {
rc = mdb_txn_commit(txn);
if (rc)
rc = cvtdberr(dbi, "mdb_txn_commit", rc, _debug);
}
retry_open = 0;
} while (--retry_open > 0);
dbi->dbi_db = (void *) ((unsigned long)db);
if (!rc && dbip)
*dbip = dbi;
else
(void) dbiClose(dbi, 0);
exit:
return rc;
}
/* The LMDB btree implementation needs BIGENDIAN primary keys. */
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
static int _dbibyteswapped = 1;
#else
static int _dbibyteswapped = 0;
#endif
/**
* Convert retrieved data to index set.
* @param dbi index database handle
* @param data retrieved data
* @retval setp (malloc'ed) index set
* @return 0 on success
*/
static rpmRC dbt2set(dbiIndex dbi, MDB_val * data, dbiIndexSet * setp)
{
rpmRC rc = RPMRC_FAIL;
const char * sdbir;
dbiIndexSet set = NULL;
unsigned int i;
if (dbi == NULL || data == NULL || setp == NULL)
goto exit;
rc = RPMRC_OK;
if ((sdbir = data->mv_data) == NULL) {
*setp = NULL;
goto exit;
}
set = dbiIndexSetNew(data->mv_size / (2 * sizeof(int32_t)));
set->count = data->mv_size / (2 * sizeof(int32_t));
for (i = 0; i < set->count; i++) {
union _dbswap hdrNum, tagNum;
memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
sdbir += sizeof(hdrNum.ui);
memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
sdbir += sizeof(tagNum.ui);
if (_dbibyteswapped) {
_DBSWAP(hdrNum);
_DBSWAP(tagNum);
}
set->recs[i].hdrNum = hdrNum.ui;
set->recs[i].tagNum = tagNum.ui;
}
*setp = set;
exit:
return rc;
}
/**
* Convert index set to database representation.
* @param dbi index database handle
* @param data retrieved data
* @param set index set
* @return 0 on success
*/
static rpmRC set2dbt(dbiIndex dbi, MDB_val * data, dbiIndexSet set)
{
rpmRC rc = RPMRC_FAIL;
char * tdbir;
unsigned int i;
if (dbi == NULL || data == NULL || set == NULL)
goto exit;
rc = RPMRC_OK;
data->mv_size = set->count * (2 * sizeof(int32_t));
if (data->mv_size == 0) {
data->mv_data = NULL;
goto exit;
}
tdbir = data->mv_data = xmalloc(data->mv_size);
for (i = 0; i < set->count; i++) {
union _dbswap hdrNum, tagNum;
memset(&hdrNum, 0, sizeof(hdrNum));
memset(&tagNum, 0, sizeof(tagNum));
hdrNum.ui = set->recs[i].hdrNum;
tagNum.ui = set->recs[i].tagNum;
if (_dbibyteswapped) {
_DBSWAP(hdrNum);
_DBSWAP(tagNum);
}
memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
tdbir += sizeof(hdrNum.ui);
memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
tdbir += sizeof(tagNum.ui);
}
exit:
return rc;
}
static rpmRC lmdb_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
dbiIndexSet *set, int searchType)
{
rpmRC rc = RPMRC_FAIL; /* assume failure */
if (dbi != NULL && dbc != NULL) {
int cflags = MDB_NEXT;
int dbrc;
MDB_val key = { 0, NULL };
MDB_val data = { 0, NULL };
if (keyp) {
if (keylen == 0) { /* XXX "/" fixup */
keyp = "";
keylen = 1;
}
key.mv_data = (void *) keyp; /* discards const */
key.mv_size = keylen;
cflags = searchType == DBC_PREFIX_SEARCH ? MDB_SET_RANGE : MDB_SET;
}
for (;;) {
dbiIndexSet newset = NULL;
dbrc = dbiCursorGet(dbc, &key, &data, cflags);
if (dbrc != 0)
break;
if (searchType == DBC_PREFIX_SEARCH &&
(key.mv_size < keylen || memcmp(key.mv_data, keyp, keylen) != 0))
break;
if (set) {
dbt2set(dbi, &data, &newset);
if (*set == NULL) {
*set = newset;
} else {
dbiIndexSetAppendSet(*set, newset, 0);
dbiIndexSetFree(newset);
}
}
if (searchType != DBC_PREFIX_SEARCH)
break;
key.mv_data = NULL;
key.mv_size = 0;
cflags = MDB_NEXT;
}
/* fixup result status for prefix search */
if (searchType == DBC_PREFIX_SEARCH && set) {
if (dbrc == MDB_NOTFOUND && *set != NULL && (*set)->count > 0)
dbrc = 0;
else if (dbrc == 0 && (*set == NULL || (*set)->count == 0))
dbrc = MDB_NOTFOUND;
}
if (dbrc == 0) {
rc = RPMRC_OK;
} else if (dbrc == MDB_NOTFOUND) {
rc = RPMRC_NOTFOUND;
} else {
rpmlog(RPMLOG_ERR,
_("rc(%d) getting \"%s\" records from %s index: %s\n"),
dbrc, keyp ? keyp : "???", dbiName(dbi), mdb_strerror(dbrc));
}
}
return rc;
}
/* Update secondary index. NULL set deletes the key */
static rpmRC updateIndex(dbiCursor dbc, const char *keyp, unsigned int keylen,
dbiIndexSet set)
{
rpmRC rc = RPMRC_FAIL;
if (dbc && keyp) {
dbiIndex dbi = dbc->dbi;
int dbrc;
MDB_val key = { 0, NULL };
MDB_val data = { 0, NULL };
key.mv_data = (void *) keyp; /* discards const */
key.mv_size = keylen;
if (set)
set2dbt(dbi, &data, set);
if (dbiIndexSetCount(set) > 0) {
dbrc = dbiCursorPut(dbc, &key, &data, 0);
if (dbrc) {
rpmlog(RPMLOG_ERR,
_("rc(%d) storing record \"%s\" into %s index: %s\n"),
dbrc, (char*)key.mv_data, dbiName(dbi), mdb_strerror(dbrc));
}
free(data.mv_data);
} else {
dbrc = dbiCursorDel(dbc, &key, &data, 0);
if (dbrc) {
rpmlog(RPMLOG_ERR,
_("rc(%d) removing record \"%s\" from %s index: %s\n"),
dbrc, (char*)key.mv_data, dbiName(dbi), mdb_strerror(dbrc));
}
}
if (dbrc == 0)
rc = RPMRC_OK;
}
return rc;
}
static rpmRC lmdb_idxdbPutOne(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
dbiIndexItem rec)
{
dbiIndexSet set = NULL;
rpmRC rc;
if (keyp && keylen == 0) { /* XXX "/" fixup */
keyp = "";
keylen++;
}
rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
/* Not found means a new key and is not an error. */
if (rc && rc != RPMRC_NOTFOUND)
goto exit;
if (set == NULL)
set = dbiIndexSetNew(1);
dbiIndexSetAppend(set, rec, 1, 0);
rc = updateIndex(dbc, keyp, keylen, set);
dbiIndexSetFree(set);
exit:
return rc;
}
static rpmRC lmdb_idxdbPut(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
{
return tag2index(dbi, rpmtag, hdrNum, h, lmdb_idxdbPutOne);
}
static rpmRC lmdb_idxdbDelOne(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
dbiIndexItem rec)
{
rpmRC rc = RPMRC_FAIL;
dbiIndexSet set = NULL;
if (keyp && keylen == 0) { /* XXX "/" fixup */
keyp = "";
keylen++;
}
rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
if (rc)
goto exit;
if (dbiIndexSetPrune(set, rec, 1, 1)) {
/* Nothing was pruned. XXX: Can this actually happen? */
rc = RPMRC_OK;
} else {
/* If there's data left, update data. Otherwise delete the key. */
if (dbiIndexSetCount(set) > 0) {
rc = updateIndex(dbc, keyp, keylen, set);
} else {
rc = updateIndex(dbc, keyp, keylen, NULL);
}
};
dbiIndexSetFree(set);
exit:
return rc;
}
static rpmRC lmdb_idxdbDel(dbiIndex dbi, rpmTagVal rpmtag, unsigned int hdrNum, Header h)
{
return tag2index(dbi, rpmtag, hdrNum, h, lmdb_idxdbDelOne);
}
static const void * lmdb_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
{
const void *key = NULL;
if (dbc) {
key = dbc->key;
if (key && keylen)
*keylen = dbc->keylen;
}
return key;
}
/* Update primary Packages index. NULL hdr means remove */
static rpmRC updatePackages(dbiCursor dbc, unsigned int hdrNum, MDB_val *hdr)
{
int rc = RPMRC_FAIL;
int dbrc = EINVAL;
if (dbc == NULL || hdrNum == 0)
goto exit;
union _dbswap mi_offset;
mi_offset.ui = hdrNum;
if (_dbibyteswapped)
_DBSWAP(mi_offset);
MDB_val key = { 0, NULL };
key.mv_data = (void *) &mi_offset;
key.mv_size = sizeof(mi_offset.ui);
MDB_val data = { 0, NULL };
dbrc = dbiCursorGet(dbc, &key, &data, MDB_SET);
if (dbrc && dbrc != MDB_NOTFOUND) {
rpmlog(RPMLOG_ERR,
_("rc(%d) positioning header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
goto exit;
}
if (hdr) {
dbrc = dbiCursorPut(dbc, &key, hdr, 0);
if (dbrc) {
rpmlog(RPMLOG_ERR,
_("rc(%d) adding header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
}
} else {
dbrc = dbiCursorDel(dbc, &key, &data, 0);
if (dbrc) {
rpmlog(RPMLOG_ERR,
_("rc(%d) deleting header #%d record: %s\n"), dbrc, hdrNum, mdb_strerror(dbrc));
}
}
exit:
rc = dbrc == 0 ? RPMRC_OK : RPMRC_FAIL;
return rc;
}
/* Get current header instance number or try to allocate a new one */
static unsigned int pkgInstance(dbiCursor dbc, int alloc)
{
unsigned int hdrNum = 0;
MDB_val key = { 0, NULL };
MDB_val data = { 0, NULL };
unsigned int firstkey = 0;
union _dbswap mi_offset;
int rc;
/* Key 0 holds the current largest instance, fetch it */
key.mv_data = &firstkey;
key.mv_size = sizeof(firstkey);
rc = dbiCursorGet(dbc, &key, &data, MDB_SET);
if (!rc && data.mv_data) {
memcpy(&mi_offset, data.mv_data, sizeof(mi_offset.ui));
if (_dbibyteswapped)
_DBSWAP(mi_offset);
hdrNum = mi_offset.ui;
}
if (alloc) {
/* Rather complicated "increment by one", bswapping as needed */
++hdrNum;
mi_offset.ui = hdrNum;
if (_dbibyteswapped)
_DBSWAP(mi_offset);
data.mv_data = &mi_offset;
data.mv_size = sizeof(mi_offset.ui);
/* Unless we manage to insert the new instance number, we failed */
rc = dbiCursorPut(dbc, &key, &data, 0);
if (rc) {
hdrNum = 0;
rpmlog(RPMLOG_ERR,
_("rc(%d) allocating new package instance: %s\n"), rc, mdb_strerror(rc));
}
}
return hdrNum;
}
static rpmRC lmdb_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum,
unsigned char *hdrBlob, unsigned int hdrLen)
{
rpmRC rc = RPMRC_FAIL;
unsigned int hnum = *hdrNum;
MDB_val hdr;
hdr.mv_data = hdrBlob;
hdr.mv_size = hdrLen;
if (hnum == 0)
hnum = pkgInstance(dbc, 1);
if (hnum)
rc = updatePackages(dbc, hnum, &hdr);
if (rc == RPMRC_OK)
*hdrNum = hnum;
return rc;
}
static rpmRC lmdb_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
{
return updatePackages(dbc, hdrNum, NULL);
}
static rpmRC lmdb_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
unsigned char **hdrBlob, unsigned int *hdrLen)
{
union _dbswap mi_offset;
MDB_val key = { 0, NULL };
MDB_val data = { 0, NULL };
rpmRC rc = RPMRC_FAIL;
if (dbc == NULL)
goto exit;
if (hdrNum) {
mi_offset.ui = hdrNum;
if (_dbibyteswapped)
_DBSWAP(mi_offset);
key.mv_data = (void *) &mi_offset;
key.mv_size = sizeof(mi_offset.ui);
}
rc = dbiCursorGet(dbc, &key, &data, hdrNum ? MDB_SET : MDB_NEXT);
if (rc == 0) {
if (hdrBlob)
*hdrBlob = data.mv_data;
if (hdrLen)
*hdrLen = data.mv_size;
rc = RPMRC_OK;
} else if (rc == MDB_NOTFOUND)
rc = RPMRC_NOTFOUND;
else
rc = RPMRC_FAIL;
exit:
return rc;
}
static unsigned int lmdb_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
{
union _dbswap mi_offset;
if (dbc == NULL || dbc->key == NULL)
return 0;
memcpy(&mi_offset, dbc->key, sizeof(mi_offset.ui));
if (_dbibyteswapped)
_DBSWAP(mi_offset);
return mi_offset.ui;
}
struct rpmdbOps_s lmdb_dbops = {
.name = "lmdb",
.path = "data.mdb",
.open = lmdb_dbiOpen,
.close = lmdb_dbiClose,
.verify = lmdb_dbiVerify,
.setFSync = lmdb_dbSetFSync,
.ctrl = lmdb_Ctrl,
.cursorInit = lmdb_dbiCursorInit,
.cursorFree = lmdb_dbiCursorFree,
.pkgdbGet = lmdb_pkgdbGet,
.pkgdbPut = lmdb_pkgdbPut,
.pkgdbDel = lmdb_pkgdbDel,
.pkgdbKey = lmdb_pkgdbKey,
.idxdbGet = lmdb_idxdbGet,
.idxdbPut = lmdb_idxdbPut,
.idxdbDel = lmdb_idxdbDel,
.idxdbKey = lmdb_idxdbKey
};

View File

@ -616,7 +616,6 @@ package or when debugging this package.\
#
# Select backend database. The following values are supported:
# bdb Berkeley DB
# lmdb Lightning Memory-mapped Database
# ndb new data base format
# sqlite Sqlite database
# dummy dummy backend (no actual functionality)

View File

@ -29,7 +29,6 @@ build/spec.c
lib/backend/db3.c
lib/backend/dbi.c
lib/backend/dummydb.c
lib/backend/lmdb.c
lib/backend/ndb/glue.c
lib/backend/ndb/rpmidx.c
lib/backend/ndb/rpmpkg.c