1 /* id2entry.c - routines to deal with the id2entry database */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/id2entry.c,v 1.72.2.6 2008/05/01 21:39:35 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
20 #include <ac/string.h>
25 static int bdb_id2entry_put(
31 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
32 DB
*db
= bdb
->bi_id2entry
->bdi_db
;
38 struct berval odn
, ondn
;
40 /* We only store rdns, and they go in the dn2id database. */
42 odn
= e
->e_name
; ondn
= e
->e_nname
;
44 e
->e_name
= slap_empty_bv
;
45 e
->e_nname
= slap_empty_bv
;
49 /* Store ID in BigEndian format */
51 key
.size
= sizeof(ID
);
52 BDB_ID2DISK( e
->e_id
, &nid
);
54 rc
= entry_encode( e
, &bv
);
56 e
->e_name
= odn
; e
->e_nname
= ondn
;
58 if( rc
!= LDAP_SUCCESS
) {
65 rc
= db
->put( db
, tid
, &key
, &data
, flag
);
72 * This routine adds (or updates) an entry on disk.
73 * The cache should be already be updated.
82 return bdb_id2entry_put(be
, tid
, e
, DB_NOOVERWRITE
);
85 int bdb_id2entry_update(
90 return bdb_id2entry_put(be
, tid
, e
, 0);
100 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
101 DB
*db
= bdb
->bi_id2entry
->bdi_db
;
113 key
.size
= sizeof(ID
);
114 BDB_ID2DISK( id
, &nid
);
117 data
.flags
= DB_DBT_USERMEM
| DB_DBT_PARTIAL
;
120 rc
= db
->cursor( db
, tid
, &cursor
, bdb
->bi_db_opflags
);
123 /* Use our own locker if needed */
124 if ( !tid
&& locker
) {
125 CURSOR_SETLOCKER( cursor
, locker
);
128 /* Get the nattrs / nvals counts first */
129 data
.ulen
= data
.dlen
= sizeof(buf
);
131 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_SET
);
132 if ( rc
) goto finish
;
136 eh
.bv
.bv_len
= data
.size
;
137 rc
= entry_header( &eh
);
138 if ( rc
) goto finish
;
141 data
.flags
^= DB_DBT_PARTIAL
;
143 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_CURRENT
);
144 if ( rc
!= DB_BUFFER_SMALL
) goto finish
;
146 /* Allocate a block and retrieve the data */
147 off
= eh
.data
- eh
.bv
.bv_val
;
148 eh
.bv
.bv_len
= eh
.nvals
* sizeof( struct berval
) + data
.size
;
149 eh
.bv
.bv_val
= ch_malloc( eh
.bv
.bv_len
);
150 eh
.data
= eh
.bv
.bv_val
+ eh
.nvals
* sizeof( struct berval
);
152 data
.ulen
= data
.size
;
154 /* skip past already parsed nattr/nvals */
157 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_CURRENT
);
160 cursor
->c_close( cursor
);
166 #ifdef SLAP_ZONE_ALLOC
167 rc
= entry_decode(&eh
, e
, bdb
->bi_cache
.c_zctx
);
169 rc
= entry_decode(&eh
, e
);
175 /* only free on error. On success, the entry was
178 #ifndef SLAP_ZONE_ALLOC
179 ch_free(eh
.bv
.bv_val
);
182 #ifdef SLAP_ZONE_ALLOC
183 ch_free(eh
.bv
.bv_val
);
189 int bdb_id2entry_delete(
194 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
195 DB
*db
= bdb
->bi_id2entry
->bdi_db
;
202 key
.size
= sizeof(ID
);
203 BDB_ID2DISK( e
->e_id
, &nid
);
205 /* delete from database */
206 rc
= db
->del( db
, tid
, &key
, 0 );
211 int bdb_entry_return(
215 /* Our entries are allocated in two blocks; the data comes from
216 * the db itself and the Entry structure and associated pointers
217 * are allocated in entry_decode. The db data pointer is saved
220 if ( e
->e_bv
.bv_val
) {
221 /* See if the DNs were changed by modrdn */
222 if( e
->e_nname
.bv_val
< e
->e_bv
.bv_val
|| e
->e_nname
.bv_val
>
223 e
->e_bv
.bv_val
+ e
->e_bv
.bv_len
) {
224 ch_free(e
->e_name
.bv_val
);
225 ch_free(e
->e_nname
.bv_val
);
227 e
->e_name
.bv_val
= NULL
;
228 e
->e_nname
.bv_val
= NULL
;
229 /* In tool mode the e_bv buffer is realloc'd, leave it alone */
230 if( !(slapMode
& SLAP_TOOL_MODE
) ) {
231 free( e
->e_bv
.bv_val
);
233 BER_BVZERO( &e
->e_bv
);
239 int bdb_entry_release(
244 struct bdb_info
*bdb
= (struct bdb_info
*) op
->o_bd
->be_private
;
245 struct bdb_op_info
*boi
;
248 /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
249 SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
251 if ( slapMode
== SLAP_SERVER_MODE
) {
252 /* If not in our cache, just free it */
253 if ( !e
->e_private
) {
254 #ifdef SLAP_ZONE_ALLOC
255 return bdb_entry_return( bdb
, e
, -1 );
257 return bdb_entry_return( e
);
260 /* free entry and reader or writer lock */
261 LDAP_SLIST_FOREACH( oex
, &op
->o_extra
, oe_next
) {
262 if ( oex
->oe_key
== bdb
) break;
264 boi
= (struct bdb_op_info
*)oex
;
266 /* lock is freed with txn */
267 if ( !boi
|| boi
->boi_txn
) {
268 bdb_unlocked_cache_return_entry_rw( bdb
, e
, rw
);
270 struct bdb_lock_info
*bli
, *prev
;
271 for ( prev
=(struct bdb_lock_info
*)&boi
->boi_locks
,
272 bli
= boi
->boi_locks
; bli
; prev
=bli
, bli
=bli
->bli_next
) {
273 if ( bli
->bli_id
== e
->e_id
) {
274 bdb_cache_return_entry_rw( bdb
, e
, rw
, &bli
->bli_lock
);
275 prev
->bli_next
= bli
->bli_next
;
276 op
->o_tmpfree( bli
, op
->o_tmpmemctx
);
280 if ( !boi
->boi_locks
) {
281 LDAP_SLIST_REMOVE( &op
->o_extra
, &boi
->boi_oe
, OpExtra
, oe_next
);
282 op
->o_tmpfree( boi
, op
->o_tmpmemctx
);
286 #ifdef SLAP_ZONE_ALLOC
288 if (e
->e_private
!= NULL
) {
289 BEI(e
)->bei_e
= NULL
;
290 zseq
= BEI(e
)->bei_zseq
;
293 if (e
->e_private
!= NULL
)
294 BEI(e
)->bei_e
= NULL
;
297 #ifdef SLAP_ZONE_ALLOC
298 bdb_entry_return ( bdb
, e
, zseq
);
300 bdb_entry_return ( e
);
307 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
313 AttributeDescription
*at
,
317 struct bdb_info
*bdb
= (struct bdb_info
*) op
->o_bd
->be_private
;
318 struct bdb_op_info
*boi
= NULL
;
323 const char *at_name
= at
? at
->ad_cname
.bv_val
: "(null)";
325 BDB_LOCKER locker
= 0;
327 int free_lock_id
= 0;
329 Debug( LDAP_DEBUG_ARGS
,
330 "=> bdb_entry_get: ndn: \"%s\"\n", ndn
->bv_val
, 0, 0 );
331 Debug( LDAP_DEBUG_ARGS
,
332 "=> bdb_entry_get: oc: \"%s\", at: \"%s\"\n",
333 oc
? oc
->soc_cname
.bv_val
: "(null)", at_name
, 0);
337 LDAP_SLIST_FOREACH( oex
, &op
->o_extra
, oe_next
) {
338 if ( oex
->oe_key
== bdb
) break;
340 boi
= (struct bdb_op_info
*)oex
;
346 locker
= TXN_ID ( txn
);
348 rc
= LOCK_ID ( bdb
->bi_dbenv
, &locker
);
359 /* can we find entry */
360 rc
= bdb_dn2entry( op
, txn
, ndn
, &ei
, 0, locker
, &lock
);
365 case DB_LOCK_DEADLOCK
:
366 case DB_LOCK_NOTGRANTED
:
367 /* the txn must abort and retry */
372 ldap_pvt_thread_yield();
375 if ( boi
) boi
->boi_err
= rc
;
376 if ( free_lock_id
) {
377 LOCK_ID_FREE( bdb
->bi_dbenv
, locker
);
379 return (rc
!= LDAP_BUSY
) ? LDAP_OTHER
: LDAP_BUSY
;
381 if (ei
) e
= ei
->bei_e
;
383 Debug( LDAP_DEBUG_ACL
,
384 "=> bdb_entry_get: cannot find entry: \"%s\"\n",
386 if ( free_lock_id
) {
387 LOCK_ID_FREE( bdb
->bi_dbenv
, locker
);
389 return LDAP_NO_SUCH_OBJECT
;
392 Debug( LDAP_DEBUG_ACL
,
393 "=> bdb_entry_get: found entry: \"%s\"\n",
396 if ( oc
&& !is_entry_objectclass( e
, oc
, 0 )) {
397 Debug( LDAP_DEBUG_ACL
,
398 "<= bdb_entry_get: failed to find objectClass %s\n",
399 oc
->soc_cname
.bv_val
, 0, 0 );
400 rc
= LDAP_NO_SUCH_ATTRIBUTE
;
405 if( rc
!= LDAP_SUCCESS
) {
407 bdb_cache_return_entry_rw(bdb
, e
, rw
, &lock
);
410 if ( slapMode
== SLAP_SERVER_MODE
) {
412 /* big drag. we need a place to store a read lock so we can
413 * release it later?? If we're in a txn, nothing is needed
414 * here because the locks will go away with the txn.
418 boi
= op
->o_tmpcalloc(1,sizeof(struct bdb_op_info
),op
->o_tmpmemctx
);
419 boi
->boi_oe
.oe_key
= bdb
;
420 LDAP_SLIST_INSERT_HEAD( &op
->o_extra
, &boi
->boi_oe
, oe_next
);
422 if ( !boi
->boi_txn
) {
423 struct bdb_lock_info
*bli
;
424 bli
= op
->o_tmpalloc( sizeof(struct bdb_lock_info
),
426 bli
->bli_next
= boi
->boi_locks
;
427 bli
->bli_id
= e
->e_id
;
428 bli
->bli_lock
= lock
;
429 boi
->boi_locks
= bli
;
433 *ent
= entry_dup( e
);
434 bdb_cache_return_entry_rw(bdb
, e
, rw
, &lock
);
438 if ( free_lock_id
) {
439 LOCK_ID_FREE( bdb
->bi_dbenv
, locker
);
442 Debug( LDAP_DEBUG_TRACE
,
443 "bdb_entry_get: rc=%d\n",