[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#9039) key corruption using mdb_put and differing data



Full_Name: Jonny Wilkes
Version: 2.4.2
OS: Linux
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (67.160.82.31)


The following code shows key corruption.

I am probably using the API wrong, but I don't see how.  I apologize in advance
for not having a clue.

And now, on to the test.  It can be compiled and run like so:

gcc t1.c -llmdb && ./a.out

--------- t1.c starts here ---------
/*

The output of this program using liblmdb0 v0.9.21-1 on Ubuntu is:

--- dump ---
key12345
key67890
--- dump ---
key12345
y12345

Why?  What happened to key67890?

 */

#include <lmdb.h>
#if USE_SOURCE
#include "midl.c"
#include "mdb.c"
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define P(K) printf("%s\n", (char *)K.mv_data)

#define X(x) do { int _x = x; if (_x) fprintf(stderr, "%d %s\n", _x,
mdb_strerror(_x)); } while (0)

const char *path = "/tmp/lmdb-why.tmp";
MDB_env *env;

/*
 * setup creates /tmp/lmdb-why.tmp with 2 keys with the data "hey":
 *
 * 1. key12345 : hey
 * 2. key67890 : hey
 */
int
setup(void)
{
  unlink(path);
  if (!env) {
    X(mdb_env_create(&env));
    X(mdb_env_open(env, path, MDB_NOSUBDIR, 0664));
  }

  MDB_txn *txn; X(mdb_txn_begin(env, NULL, 0, &txn));
  MDB_dbi dbi;  X(mdb_dbi_open(txn, NULL, 0, &dbi));

  const char *keys[] = {
    "key12345",
    "key67890"
  };
  for (unsigned i = 0; i < 2; ++i) {
    MDB_val key, data;
    key.mv_data = (void *)keys[i];
    key.mv_size = strlen(keys[i])+1;
    data.mv_data = "hey";
    data.mv_size = 4;
    X(mdb_put(txn, dbi, &key, &data, 0));
  }
  X(mdb_txn_commit(txn));
  return 0;
}

int
dump(void)
{
  printf("--- dump ---\n");

  MDB_txn *txn;       X(mdb_txn_begin(env, NULL, 0, &txn));
  MDB_dbi dbi;        X(mdb_dbi_open(txn, NULL, 0, &dbi));
  MDB_cursor *cursor; X(mdb_cursor_open(txn, dbi, &cursor));

  MDB_val key;
  int rc;
  while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT)) == 0) {
    P(key);
  }

  mdb_cursor_close(cursor);
  if (MDB_NOTFOUND != rc)
    return rc;
  mdb_txn_abort(txn);
  return 0;
}

/*
 * change_data change the data for each key to "there" using mdb_put.
 * After it completes, the keys are corrupt.
 */
int
change_data(void)
{
  MDB_txn *txn;       X(mdb_txn_begin(env, NULL, 0, &txn));
  MDB_dbi dbi;        X(mdb_dbi_open(txn, NULL, 0, &dbi));
  MDB_cursor *cursor; X(mdb_cursor_open(txn, dbi, &cursor));

  MDB_val key;
  int rc;
  while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT)) == 0) {
    MDB_val data;
    data.mv_data = (void *)"there";
    data.mv_size = 6;           /* ! */
    X(mdb_put(txn, dbi, &key, &data, 0));
  }
  mdb_cursor_close(cursor);
  if (MDB_NOTFOUND != rc)
    return rc;

  X(mdb_txn_commit(txn));
  return 0;
}

int main(void)
{
  X(setup());
  X(dump());
  X(change_data());
  X(dump());
  return 0;
}