]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/id2entry.c
13f958dd467e89d2d3074c9ac5c5772f847d1301
[openldap] / servers / slapd / back-bdb / id2entry.c
1 /* id2entry.c - routines to deal with the id2entry database */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2004 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21
22 #include "back-bdb.h"
23 #include "external.h"
24
25 static int bdb_id2entry_put(
26         BackendDB *be,
27         DB_TXN *tid,
28         Entry *e,
29         int flag )
30 {
31         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
32         DB *db = bdb->bi_id2entry->bdi_db;
33         DBT key, data;
34         struct berval bv;
35         char buf[sizeof(ID)];
36         ID tmp;
37         int i, rc;
38 #ifdef BDB_HIER
39         struct berval odn, ondn;
40
41         /* We only store rdns, and they go in the dn2id database. */
42
43         odn = e->e_name; ondn = e->e_nname;
44
45         e->e_name = slap_empty_bv;
46         e->e_nname = slap_empty_bv;
47 #endif
48         DBTzero( &key );
49         key.data = buf;
50         key.size = sizeof(ID);
51
52         /* Set key in BigEndian order */
53         tmp = e->e_id;
54         for ( i=sizeof(ID)-1; i>=0; i-- ) {
55                 buf[i] = tmp & 0xff;
56                 tmp >>= 8;
57         }
58
59         rc = entry_encode( e, &bv );
60 #ifdef BDB_HIER
61         e->e_name = odn; e->e_nname = ondn;
62 #endif
63         if( rc != LDAP_SUCCESS ) {
64                 return -1;
65         }
66
67         DBTzero( &data );
68         bv2DBT( &bv, &data );
69
70         rc = db->put( db, tid, &key, &data, flag );
71
72         free( bv.bv_val );
73         return rc;
74 }
75
76 /*
77  * This routine adds (or updates) an entry on disk.
78  * The cache should be already be updated.
79  */
80
81
82 int bdb_id2entry_add(
83         BackendDB *be,
84         DB_TXN *tid,
85         Entry *e )
86 {
87         return bdb_id2entry_put(be, tid, e, DB_NOOVERWRITE);
88 }
89
90 int bdb_id2entry_update(
91         BackendDB *be,
92         DB_TXN *tid,
93         Entry *e )
94 {
95         return bdb_id2entry_put(be, tid, e, 0);
96 }
97
98 int bdb_id2entry(
99         BackendDB *be,
100         DB_TXN *tid,
101         ID id,
102         Entry **e )
103 {
104         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
105         DB *db = bdb->bi_id2entry->bdi_db;
106         DBT key, data;
107         struct berval bv;
108         char buf[sizeof(ID)];
109         ID tmp;
110         int i, rc = 0, ret = 0;
111
112         *e = NULL;
113
114         DBTzero( &key );
115         key.data = buf;
116         key.size = sizeof(ID);
117         tmp = id;
118         for ( i=sizeof(ID)-1; i>=0; i-- ) {
119                 buf[i] = tmp & 0xff;
120                 tmp >>= 8;
121         }
122
123         DBTzero( &data );
124         data.flags = DB_DBT_MALLOC;
125
126         /* fetch it */
127         rc = db->get( db, tid, &key, &data, bdb->bi_db_opflags );
128
129         if( rc != 0 ) {
130                 return rc;
131         }
132
133         DBT2bv( &data, &bv );
134
135         rc = entry_decode( &bv, e );
136
137         if( rc == 0 ) {
138                 (*e)->e_id = id;
139         } else {
140                 /* only free on error. On success, the entry was
141                  * decoded in place.
142                  */
143                 ch_free( data.data );
144         }
145
146         return rc;
147 }
148
149 int bdb_id2entry_delete(
150         BackendDB *be,
151         DB_TXN *tid,
152         Entry *e )
153 {
154         struct bdb_info *bdb = (struct bdb_info *) be->be_private;
155         DB *db = bdb->bi_id2entry->bdi_db;
156         DBT key;
157         char buf[sizeof(ID)];
158         ID tmp;
159         int i, rc;
160
161         DBTzero( &key );
162         key.data = buf;
163         key.size = sizeof(ID);
164         tmp = e->e_id;
165         for ( i=sizeof(ID)-1; i>=0; i-- ) {
166                 buf[i] = tmp & 0xff;
167                 tmp >>= 8;
168         }
169
170         /* delete from database */
171         rc = db->del( db, tid, &key, 0 );
172
173         return rc;
174 }
175
176 int bdb_entry_return(
177         Entry *e )
178 {
179         /* Our entries are allocated in two blocks; the data comes from
180          * the db itself and the Entry structure and associated pointers
181          * are allocated in entry_decode. The db data pointer is saved
182          * in e_bv. Since the Entry structure is allocated as a single
183          * block, e_attrs is always a fixed offset from e. The exception
184          * is when an entry has been modified, in which case we also need
185          * to free e_attrs.
186          */
187         if( !e->e_bv.bv_val ) { /* A regular entry, from do_add */
188                 entry_free( e );
189                 return 0;
190         }
191         if( (void *) e->e_attrs != (void *) (e+1)) {
192                 attrs_free( e->e_attrs );
193         }
194
195         /* See if the DNs were changed by modrdn */
196         if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val >
197                 e->e_bv.bv_val + e->e_bv.bv_len ) {
198                 ch_free(e->e_name.bv_val);
199                 ch_free(e->e_nname.bv_val);
200                 e->e_name.bv_val = NULL;
201                 e->e_nname.bv_val = NULL;
202         }
203 #ifndef BDB_HIER
204         /* In tool mode the e_bv buffer is realloc'd, leave it alone */
205         if( !(slapMode & SLAP_TOOL_MODE) ) {
206                 free( e->e_bv.bv_val );
207         }
208 #else
209         free( e->e_bv.bv_val );
210 #endif
211         free( e );
212
213         return 0;
214 }
215
216 int bdb_entry_release(
217         Operation *o,
218         Entry *e,
219         int rw )
220 {
221         struct bdb_info *bdb = (struct bdb_info *) o->o_bd->be_private;
222         struct bdb_op_info *boi = NULL;
223  
224         /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
225                         SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
226  
227         if ( slapMode == SLAP_SERVER_MODE ) {
228                 /* free entry and reader or writer lock */
229                 if ( o ) {
230                         boi = (struct bdb_op_info *)o->o_private;
231                 }
232                 /* lock is freed with txn */
233                 if ( !boi || boi->boi_txn ) {
234                         bdb_unlocked_cache_return_entry_rw( &bdb->bi_cache, e, rw );
235                 } else {
236                         bdb_cache_return_entry_rw( bdb->bi_dbenv, &bdb->bi_cache, e, rw, &boi->boi_lock );
237                         o->o_tmpfree( boi, o->o_tmpmemctx );
238                         o->o_private = NULL;
239                 }
240         } else {
241                 if (e->e_private != NULL)
242                         BEI(e)->bei_e = NULL;
243                 e->e_private = NULL;
244                 bdb_entry_return ( e );
245         }
246  
247         return 0;
248 }
249
250 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
251  */
252 int bdb_entry_get(
253         Operation *op,
254         struct berval *ndn,
255         ObjectClass *oc,
256         AttributeDescription *at,
257         int rw,
258         Entry **ent )
259 {
260         struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
261         struct bdb_op_info *boi = NULL;
262         DB_TXN *txn = NULL;
263         Entry *e = NULL;
264         EntryInfo *ei;
265         int     rc;
266         const char *at_name = at ? at->ad_cname.bv_val : "(null)";
267
268         u_int32_t       locker = 0;
269         DB_LOCK         lock;
270         int             free_lock_id = 0;
271
272 #ifdef NEW_LOGGING
273         LDAP_LOG( BACK_BDB, ARGS, 
274                 "bdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 );
275         LDAP_LOG( BACK_BDB, ARGS, 
276                 "bdb_entry_get: oc: \"%s\", at: \"%s\"\n",
277                 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
278 #else
279         Debug( LDAP_DEBUG_ARGS,
280                 "=> bdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); 
281         Debug( LDAP_DEBUG_ARGS,
282                 "=> bdb_entry_get: oc: \"%s\", at: \"%s\"\n",
283                 oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
284 #endif
285
286         if( op ) boi = (struct bdb_op_info *) op->o_private;
287         if( boi != NULL && op->o_bd == boi->boi_bdb ) {
288                 txn = boi->boi_txn;
289                 locker = boi->boi_locker;
290         }
291
292         if ( txn != NULL ) {
293                 locker = TXN_ID ( txn );
294         } else if ( !locker ) {
295                 rc = LOCK_ID ( bdb->bi_dbenv, &locker );
296                 free_lock_id = 1;
297                 switch(rc) {
298                 case 0:
299                         break;
300                 default:
301                         return LDAP_OTHER;
302                 }
303         }
304
305 dn2entry_retry:
306         /* can we find entry */
307         rc = bdb_dn2entry( op, txn, ndn, &ei, 0, locker, &lock );
308         switch( rc ) {
309         case DB_NOTFOUND:
310         case 0:
311                 break;
312         case DB_LOCK_DEADLOCK:
313         case DB_LOCK_NOTGRANTED:
314                 /* the txn must abort and retry */
315                 if ( txn ) {
316                         boi->boi_err = rc;
317                         return LDAP_BUSY;
318                 }
319                 ldap_pvt_thread_yield();
320                 goto dn2entry_retry;
321         default:
322                 if ( boi ) boi->boi_err = rc;
323                 if ( free_lock_id ) {
324                         LOCK_ID_FREE( bdb->bi_dbenv, locker );
325                 }
326                 return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY;
327         }
328         if (ei) e = ei->bei_e;
329         if (e == NULL) {
330 #ifdef NEW_LOGGING
331                 LDAP_LOG( BACK_BDB, INFO, 
332                         "bdb_entry_get: cannot find entry (%s)\n", 
333                         ndn->bv_val, 0, 0 );
334 #else
335                 Debug( LDAP_DEBUG_ACL,
336                         "=> bdb_entry_get: cannot find entry: \"%s\"\n",
337                                 ndn->bv_val, 0, 0 ); 
338 #endif
339                 if ( free_lock_id ) {
340                         LOCK_ID_FREE( bdb->bi_dbenv, locker );
341                 }
342                 return LDAP_NO_SUCH_OBJECT; 
343         }
344         
345 #ifdef NEW_LOGGING
346         LDAP_LOG( BACK_BDB, DETAIL1, "bdb_entry_get: found entry (%s)\n",
347                 ndn->bv_val, 0, 0 );
348 #else
349         Debug( LDAP_DEBUG_ACL,
350                 "=> bdb_entry_get: found entry: \"%s\"\n",
351                 ndn->bv_val, 0, 0 ); 
352 #endif
353
354 #ifdef BDB_ALIASES
355         /* find attribute values */
356         if( is_entry_alias( e ) ) {
357 #ifdef NEW_LOGGING
358                 LDAP_LOG( BACK_BDB, INFO, 
359                         "bdb_entry_get: entry (%s) is an alias\n", e->e_name.bv_val, 0, 0 );
360 #else
361                 Debug( LDAP_DEBUG_ACL,
362                         "<= bdb_entry_get: entry is an alias\n", 0, 0, 0 );
363 #endif
364                 rc = LDAP_ALIAS_PROBLEM;
365                 goto return_results;
366         }
367 #endif
368
369         if( is_entry_referral( e ) ) {
370 #ifdef NEW_LOGGING
371                 LDAP_LOG( BACK_BDB, INFO, 
372                         "bdb_entry_get: entry (%s) is a referral.\n", e->e_name.bv_val, 0, 0);
373 #else
374                 Debug( LDAP_DEBUG_ACL,
375                         "<= bdb_entry_get: entry is a referral\n", 0, 0, 0 );
376 #endif
377                 rc = LDAP_REFERRAL;
378                 goto return_results;
379         }
380
381         if ( oc && !is_entry_objectclass( e, oc, 0 )) {
382 #ifdef NEW_LOGGING
383                 LDAP_LOG( BACK_BDB, INFO, 
384                         "bdb_entry_get: failed to find objectClass.\n", 0, 0, 0 );
385 #else
386                 Debug( LDAP_DEBUG_ACL,
387                         "<= bdb_entry_get: failed to find objectClass\n",
388                         0, 0, 0 ); 
389 #endif
390                 rc = LDAP_NO_SUCH_ATTRIBUTE;
391                 goto return_results;
392         }
393
394 return_results:
395         if( rc != LDAP_SUCCESS ) {
396                 /* free entry */
397                 bdb_cache_return_entry_rw(bdb->bi_dbenv, &bdb->bi_cache, e, rw, &lock);
398         } else {
399                 *ent = e;
400                 /* big drag. we need a place to store a read lock so we can
401                  * release it later??
402                  */
403                 if ( op && !boi ) {
404                         boi = op->o_tmpcalloc(1,sizeof(struct bdb_op_info),op->o_tmpmemctx);
405                         boi->boi_lock = lock;
406                         op->o_private = boi;
407                 }
408         }
409
410         if ( free_lock_id ) {
411                 LOCK_ID_FREE( bdb->bi_dbenv, locker );
412         }
413
414 #ifdef NEW_LOGGING
415         LDAP_LOG( BACK_BDB, ENTRY, "bdb_entry_get: rc=%d\n", rc, 0, 0 );
416 #else
417         Debug( LDAP_DEBUG_TRACE,
418                 "bdb_entry_get: rc=%d\n",
419                 rc, 0, 0 ); 
420 #endif
421         return(rc);
422 }