/* idl.c - ldap id list handling routines */
/* $OpenLDAP$ */
/*
- * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
*/
unsigned base = 0;
unsigned cursor = 0;
- int val;
+ int val = 0;
unsigned n = ids[0];
#if IDL_DEBUG > 0
#endif
}
-static int idl_insert( ID *ids, ID id )
+int bdb_idl_insert( ID *ids, ID id )
{
unsigned x = bdb_idl_search( ids, id );
assert( ids != NULL );
DBTzero( &data );
+
+#ifdef BDB_IDL_MULTI
+ {
+ DBC *cursor;
+ ID buf[BDB_IDL_UM_SIZE];
+ ID *i, *j;
+ void *ptr;
+ size_t len;
+ int rc2;
+ int flags = bdb->bi_db_opflags | DB_MULTIPLE;
+ data.data = buf;
+ data.ulen = BDB_IDL_UM_SIZEOF;
+ data.flags = DB_DBT_USERMEM;
+
+ if ( tid )
+ flags |= DB_RMW;
+
+ rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
+ if( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
+ "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ rc = cursor->c_get( cursor, key, &data, flags | DB_SET );
+ if (rc == 0) {
+ i = ids;
+ while (rc == 0) {
+ DB_MULTIPLE_INIT( ptr, &data );
+ while (ptr) {
+ DB_MULTIPLE_NEXT(ptr, &data, j, len);
+ if (j) {
+ ++i;
+ AC_MEMCPY( i, j, sizeof(ID) );
+ }
+ }
+ rc = cursor->c_get( cursor, key, &data, flags | DB_NEXT_DUP );
+ }
+ if ( rc == DB_NOTFOUND ) rc = 0;
+ ids[0] = i - ids;
+ /* On disk, a range is denoted by 0 in the first element */
+ if (ids[1] == 0) {
+ if (ids[0] != BDB_IDL_RANGE_SIZE) {
+ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
+ "range size mismatch: expected %ld, got %ld\n",
+ BDB_IDL_RANGE_SIZE, ids[0], 0 );
+ cursor->c_close( cursor );
+ return -1;
+ }
+ BDB_IDL_RANGE( ids, ids[2], ids[3] );
+ }
+ data.size = BDB_IDL_SIZEOF(ids);
+ }
+ rc2 = cursor->c_close( cursor );
+ if (rc2) {
+ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
+ "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 );
+ return rc2;
+ }
+ }
+#else
data.data = ids;
data.ulen = BDB_IDL_UM_SIZEOF;
data.flags = DB_DBT_USERMEM;
-
/* fetch it */
rc = db->get( db, tid, key, &data, bdb->bi_db_opflags );
+#endif
if( rc == DB_NOTFOUND ) {
return rc;
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
int rc;
- ID ids[BDB_IDL_DB_SIZE];
DBT data;
+#ifndef BDB_IDL_MULTI
+ ID ids[BDB_IDL_DB_SIZE];
+#endif
/* for printable keys only */
Debug( LDAP_DEBUG_ARGS,
assert( id != NOID );
+ DBTzero( &data );
+#ifdef BDB_IDL_MULTI
+ {
+ ID buf[BDB_IDL_DB_MAX];
+ DBC *cursor;
+ ID lo, hi;
+ char *err;
+
+ data.size = sizeof( ID );
+ data.ulen = data.size;
+ data.flags = DB_DBT_USERMEM;
+
+ rc = bdb_idl_fetch_key( be, db, tid, key, buf );
+ if ( rc && rc != DB_NOTFOUND )
+ return rc;
+
+ /* If it never existed, or there's room in the current key,
+ * just store it.
+ */
+ if ( rc == DB_NOTFOUND || ( !BDB_IDL_IS_RANGE(buf) &&
+ BDB_IDL_N(buf) < BDB_IDL_DB_MAX ) ) {
+ data.data = &id;
+ rc = db->put( db, tid, key, &data, DB_NODUPDATA );
+ } else if ( BDB_IDL_IS_RANGE(buf) ) {
+ /* If it's a range and we're outside the boundaries,
+ * rewrite the range boundaries.
+ */
+ if ( id < BDB_IDL_RANGE_FIRST(buf) ||
+ id > BDB_IDL_RANGE_LAST(buf) ) {
+ rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
+ if ( rc != 0 ) {
+ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
+ "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
+ return rc;
+ }
+ if ( id < BDB_IDL_RANGE_FIRST(buf) ) {
+ data.data = buf+1;
+ } else {
+ data.data = buf+2;
+ }
+ rc = cursor->c_get( cursor, key, &data, DB_GET_BOTH | DB_RMW );
+ if ( rc != 0 ) {
+ err = "c_get";
+fail: Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
+ "%s failed: %s (%d)\n", err, db_strerror(rc), rc );
+ if ( cursor ) cursor->c_close( cursor );
+ return rc;
+ }
+ data.data = &id;
+ /* We should have been able to just overwrite the old
+ * value with the new, but apparently we have to delete
+ * it first.
+ */
+ rc = cursor->c_del( cursor, 0 );
+ if ( rc ) {
+ err = "c_del";
+ goto fail;
+ }
+ rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST );
+ if ( rc ) {
+ err = "c_put";
+ goto fail;
+ }
+ rc = cursor->c_close( cursor );
+ if ( rc ) {
+ cursor = NULL;
+ err = "c_close";
+ goto fail;
+ }
+ }
+ } else { /* convert to a range */
+ lo = BDB_IDL_FIRST(buf);
+ hi = BDB_IDL_LAST(buf);
+
+ if (id < lo)
+ lo = id;
+ else if (id > hi)
+ hi = id;
+
+ cursor = NULL;
+
+ /* Delete all of the old IDL so we can replace with a range */
+ rc = db->del( db, tid, key, 0 );
+ if ( rc ) {
+ err = "del";
+ goto fail;
+ }
+
+ /* Write the range */
+ data.data = &id;
+ id = 0;
+ rc = db->put( db, tid, key, &data, 0 );
+ if ( rc ) {
+ err = "put #1";
+ goto fail;
+ }
+ id = lo;
+ rc = db->put( db, tid, key, &data, 0 );
+ if ( rc ) {
+ err = "put #2";
+ goto fail;
+ }
+ id = hi;
+ rc = db->put( db, tid, key, &data, 0 );
+ if ( rc ) {
+ err = "put #3";
+ goto fail;
+ }
+ }
+ }
+#else
data.data = ids;
data.ulen = sizeof ids;
data.flags = DB_DBT_USERMEM;
}
} else {
- rc = idl_insert( ids, id );
+ rc = bdb_idl_insert( ids, id );
if( rc == -1 ) {
Debug( LDAP_DEBUG_TRACE, "=> bdb_idl_insert_key: dup\n",
}
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
- "idl_insert failed (%d)\n",
+ "bdb_idl_insert failed (%d)\n",
rc, 0, 0 );
return rc;
/* store the key */
rc = db->put( db, tid, key, &data, 0 );
+#endif
+ if( rc == DB_KEYEXIST ) rc = 0;
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
int rc;
- ID ids[BDB_IDL_DB_SIZE];
DBT data;
+#ifndef BDB_IDL_MULTI
+ ID ids[BDB_IDL_DB_SIZE];
+#endif
/* for printable keys only */
Debug( LDAP_DEBUG_ARGS,
assert( id != NOID );
+ DBTzero( &data );
+#ifdef BDB_IDL_MULTI
+ {
+ DBC *cursor;
+
+ data.data = &id;
+ data.size = sizeof( id );
+ data.ulen = data.size;
+ data.flags = DB_DBT_USERMEM;
+
+ rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
+ rc = cursor->c_get( cursor, key, &data, bdb->bi_db_opflags |
+ DB_GET_BOTH | DB_RMW );
+ if (rc == 0)
+ rc = cursor->c_del( cursor, 0 );
+ rc = cursor->c_close( cursor );
+ }
+#else
data.data = ids;
data.ulen = sizeof( ids );
data.flags = DB_DBT_USERMEM;
/* store the key */
rc = db->put( db, tid, key, &data, 0 );
+#endif /* BDB_IDL_MULTI */
+
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: put failed: %s (%d)\n",