openldap/servers/slapd/back-bdb/idl.c

301 lines
5.6 KiB
C
Raw Normal View History

2000-09-20 15:21:09 +08:00
/* idl.c - ldap id list handling routines */
/* $OpenLDAP$ */
/*
* Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
*/
#include "portable.h"
#include <stdio.h>
#include <ac/string.h>
#include "back-bdb.h"
#define IDL_CMP(x,y) ( x < y ? -1 : ( x > y ? 1 : 0 ) )
2000-09-27 06:22:42 +08:00
unsigned bdb_idl_search( ID *ids, ID id )
2000-09-20 15:21:09 +08:00
{
#if BDB_IDL_BINARY_SEARCH
/*
* binary search of id in ids
* if found, returns position of id
* if not found, returns first postion greater than id
*/
2000-09-27 06:22:42 +08:00
unsigned base = 0;
unsigned cursor = 0;
int val;
2000-09-27 06:22:42 +08:00
unsigned n = ids[0];
while( 0 < n ) {
int pivot = n >> 1;
cursor = base + pivot;
val = IDL_CMP( id, ids[cursor + 1] );
if( val < 0 ) {
n = pivot;
} else if ( val > 0 ) {
base = cursor + 1;
n -= pivot + 1;
} else {
return cursor + 1;
2000-09-20 15:21:09 +08:00
}
}
2000-09-26 02:59:15 +08:00
if( val > 0 ) {
return cursor + 2;
2000-09-26 02:59:15 +08:00
} else {
return cursor + 1;
}
#else
/* (reverse) linear search */
int i;
for( i=ids[0]; i; i-- ) {
if( id > ids[i] ) {
break;
}
}
return i+1;
#endif
2000-09-20 15:21:09 +08:00
}
static int idl_insert( ID *ids, ID id )
{
2000-09-27 06:22:42 +08:00
unsigned x = bdb_idl_search( ids, id );
2000-09-20 15:21:09 +08:00
assert( x > 0 );
2000-09-26 12:28:17 +08:00
if( x < 1 ) {
/* internal error */
2000-09-26 12:28:17 +08:00
return -2;
2000-09-20 15:21:09 +08:00
}
2000-09-26 12:28:17 +08:00
if ( x <= ids[0] && ids[x] == id ) {
/* duplicate */
return -1;
}
2000-09-20 15:21:09 +08:00
if ( ++ids[0] >= BDB_IDL_DB_MAX ) {
2000-09-27 06:22:42 +08:00
if( id < ids[1] ) {
ids[1] = id;
ids[2] = ids[ids[0]-1];
} else if ( ids[ids[0]-1] < id ) {
ids[2] = id;
} else {
ids[2] = ids[ids[0]-1];
}
2000-09-20 15:21:09 +08:00
ids[0] = NOID;
} else {
/* insert id */
2000-09-21 07:29:41 +08:00
AC_MEMCPY( &ids[x+1], &ids[x], (ids[0]-x) * sizeof(ID) );
2000-09-20 15:21:09 +08:00
ids[0]++;
ids[x] = id;
}
return 0;
}
2000-09-21 07:29:41 +08:00
static int idl_delete( ID *ids, ID id )
{
2000-09-27 06:22:42 +08:00
unsigned x = bdb_idl_search( ids, id );
2000-09-21 07:29:41 +08:00
assert( x > 0 );
if( x <= 0 ) {
/* internal error */
return -1;
}
if( x > ids[0] || ids[x] != id ) {
2000-09-21 07:29:41 +08:00
/* not found */
return -1;
} else if ( --ids[0] == 0 ) {
if( x != 1 ) {
return -1;
}
2000-09-21 07:29:41 +08:00
} else {
AC_MEMCPY( &ids[x], &ids[x+1], (1+ids[0]-x) * sizeof(ID) );
}
return 0;
}
2000-09-20 15:21:09 +08:00
int
bdb_idl_insert_key(
BackendDB *be,
DB *db,
2000-09-20 15:21:09 +08:00
DB_TXN *tid,
DBT *key,
ID id )
2000-09-20 15:21:09 +08:00
{
int rc;
2000-09-26 02:59:15 +08:00
ID ids[BDB_IDL_DB_SIZE];
2000-09-20 15:21:09 +08:00
DBT data;
2000-09-26 12:28:17 +08:00
/* for printable keys only */
Debug( LDAP_DEBUG_ARGS,
"=> bdb_idl_insert_key: %s %ld\n",
key->data, (long) id, 0 );
2000-09-20 15:21:09 +08:00
assert( id != NOID );
data.data = ids;
data.ulen = sizeof( ids );
data.flags = DB_DBT_USERMEM;
/* fetch the key and grab a write lock */
rc = db->get( db, tid, key, &data, DB_RMW );
if( rc == DB_NOTFOUND ) {
ids[0] = 1;
ids[1] = id;
data.size = 2 * sizeof( ID );
} else if ( rc != 0 ) {
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: get failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
2000-09-20 15:21:09 +08:00
return rc;
} else if ( data.size == 0 || data.size % sizeof( ID ) ) {
/* size not multiple of ID size */
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: odd size: expected %ld multiple, got %ld\n",
(long) sizeof( ID ), (long) data.size, 0 );
2000-09-20 15:21:09 +08:00
return -1;
2000-09-27 06:22:42 +08:00
} else if ( BDB_IDL_IS_RANGE(ids) ) {
if( id < ids[1] ) {
ids[1] = id;
} else if ( ids[2] > id ) {
ids[2] = id;
} else {
return 0;
}
2000-09-20 15:21:09 +08:00
} else if ( data.size != (1 + ids[0]) * sizeof( ID ) ) {
/* size mismatch */
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: get size mismatch: expected %ld, got %ld\n",
(long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
2000-09-20 15:21:09 +08:00
return -1;
} else {
rc = idl_insert( ids, id );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: idl_insert failed (%d)\n",
rc, 0, 0 );
return rc;
}
2000-09-20 15:21:09 +08:00
2000-09-27 06:22:42 +08:00
if( BDB_IDL_IS_RANGE( ids ) ) {
data.size = BDB_IDL_RANGE_SIZE;
} else {
data.size = (ids[0]+1) * sizeof( ID );
}
2000-09-20 15:21:09 +08:00
}
/* store the key */
rc = db->put( db, tid, key, &data, 0 );
2000-09-26 09:18:00 +08:00
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: get failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
}
2000-09-20 15:21:09 +08:00
return rc;
}
2000-09-21 07:29:41 +08:00
int
bdb_idl_delete_key(
BackendDB *be,
DB *db,
2000-09-21 07:29:41 +08:00
DB_TXN *tid,
DBT *key,
ID id )
2000-09-21 07:29:41 +08:00
{
int rc;
2000-09-26 02:59:15 +08:00
ID ids[BDB_IDL_DB_SIZE];
2000-09-21 07:29:41 +08:00
DBT data;
2000-09-26 12:28:17 +08:00
/* for printable keys only */
Debug( LDAP_DEBUG_ARGS,
"=> bdb_idl_delete_key: %s %ld\n",
key->data, (long) id, 0 );
2000-09-21 07:29:41 +08:00
assert( id != NOID );
data.data = ids;
data.ulen = sizeof( ids );
data.flags = DB_DBT_USERMEM;
/* fetch the key and grab a write lock */
rc = db->get( db, tid, key, &data, DB_RMW );
if ( rc != 0 ) {
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: get failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
2000-09-21 07:29:41 +08:00
return rc;
} else if ( data.size == 0 || data.size % sizeof( ID ) ) {
/* size not multiple of ID size */
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: odd size: expected %ld multiple, got %ld\n",
(long) sizeof( ID ), (long) data.size, 0 );
2000-09-21 07:29:41 +08:00
return -1;
2000-09-27 06:22:42 +08:00
} else if ( BDB_IDL_IS_RANGE(ids) ) {
2000-09-21 07:29:41 +08:00
return 0;
} else if ( data.size != (1 + ids[0]) * sizeof( ID ) ) {
/* size mismatch */
2000-09-26 09:18:00 +08:00
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: get size mismatch: expected %ld, got %ld\n",
(long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
2000-09-21 07:29:41 +08:00
return -1;
} else {
rc = idl_delete( ids, id );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_insert_key: idl_insert failed (%d)\n",
rc, 0, 0 );
return rc;
}
2000-09-21 07:29:41 +08:00
if( ids[0] == 0 ) {
2000-09-21 07:29:41 +08:00
/* delete the key */
rc = db->del( db, tid, key, 0 );
2000-09-26 09:18:00 +08:00
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: delete failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
}
2000-09-21 07:29:41 +08:00
return rc;
}
data.size = (ids[0]+1) * sizeof( ID );
}
/* store the key */
rc = db->put( db, tid, key, &data, 0 );
2000-09-26 09:18:00 +08:00
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_idl_delete_key: put failed: %s (%d)\n",
db_strerror(rc), rc, 0 );
}
2000-09-21 07:29:41 +08:00
return rc;
}