|
|
|
@ -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
|
|
|
|
|
};
|