1 /* tools.c - tools for slap tools */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/back-bdb/tools.c,v 1.105.2.10 2008/02/12 00:34:58 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>
27 static DBC
*cursor
= NULL
;
29 static EntryHeader eh
;
30 static ID nid
, previd
= NOID
;
31 static char ehbuf
[16];
33 typedef struct dn_id
{
38 #define HOLE_SIZE 4096
39 static dn_id hbuf
[HOLE_SIZE
], *holes
= hbuf
;
40 static unsigned nhmax
= HOLE_SIZE
;
41 static unsigned nholes
;
43 static int index_nattrs
;
45 #ifdef BDB_TOOL_IDL_CACHING
46 #define bdb_tool_idl_cmp BDB_SYMBOL(tool_idl_cmp)
47 #define bdb_tool_idl_flush_one BDB_SYMBOL(tool_idl_flush_one)
48 #define bdb_tool_idl_flush BDB_SYMBOL(tool_idl_flush)
50 static int bdb_tool_idl_flush( BackendDB
*be
);
54 typedef struct bdb_tool_idl_cache_entry
{
55 struct bdb_tool_idl_cache_entry
*next
;
57 } bdb_tool_idl_cache_entry
;
59 typedef struct bdb_tool_idl_cache
{
61 bdb_tool_idl_cache_entry
*head
, *tail
;
66 static bdb_tool_idl_cache_entry
*bdb_tool_idl_free_list
;
67 #endif /* BDB_TOOL_IDL_CACHING */
69 static ID bdb_tool_ix_id
;
70 static Operation
*bdb_tool_ix_op
;
71 static int *bdb_tool_index_threads
, bdb_tool_index_tcount
;
72 static void *bdb_tool_index_rec
;
73 static struct bdb_info
*bdb_tool_info
;
74 static ldap_pvt_thread_mutex_t bdb_tool_index_mutex
;
75 static ldap_pvt_thread_cond_t bdb_tool_index_cond_main
;
76 static ldap_pvt_thread_cond_t bdb_tool_index_cond_work
;
78 static ldap_pvt_thread_mutex_t bdb_tool_trickle_mutex
;
79 static ldap_pvt_thread_cond_t bdb_tool_trickle_cond
;
81 static void * bdb_tool_index_task( void *ctx
, void *ptr
);
82 static void * bdb_tool_trickle_task( void *ctx
, void *ptr
);
84 int bdb_tool_entry_open(
85 BackendDB
*be
, int mode
)
87 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
89 /* initialize key and data thangs */
92 key
.flags
= DB_DBT_USERMEM
;
94 key
.size
= key
.ulen
= sizeof( nid
);
95 data
.flags
= DB_DBT_USERMEM
;
98 int rc
= bdb
->bi_id2entry
->bdi_db
->cursor(
99 bdb
->bi_id2entry
->bdi_db
, NULL
, &cursor
,
100 bdb
->bi_db_opflags
);
106 /* Set up for threaded slapindex */
107 if (( slapMode
& (SLAP_TOOL_QUICK
|SLAP_TOOL_READONLY
)) == SLAP_TOOL_QUICK
) {
108 if ( !bdb_tool_info
) {
109 ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex
);
110 ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond
);
111 ldap_pvt_thread_pool_submit( &connection_pool
, bdb_tool_trickle_task
, bdb
->bi_dbenv
);
113 ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex
);
114 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main
);
115 ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work
);
116 if ( bdb
->bi_nattrs
) {
118 bdb_tool_index_threads
= ch_malloc( slap_tool_thread_max
* sizeof( int ));
119 bdb_tool_index_rec
= ch_malloc( bdb
->bi_nattrs
* sizeof( IndexRec
));
120 bdb_tool_index_tcount
= slap_tool_thread_max
- 1;
121 for (i
=1; i
<slap_tool_thread_max
; i
++) {
122 int *ptr
= ch_malloc( sizeof( int ));
124 ldap_pvt_thread_pool_submit( &connection_pool
,
125 bdb_tool_index_task
, ptr
);
135 int bdb_tool_entry_close(
138 if ( bdb_tool_info
) {
140 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex
);
141 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond
);
142 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex
);
143 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex
);
144 bdb_tool_index_tcount
= slap_tool_thread_max
- 1;
145 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work
);
146 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex
);
150 ch_free( eh
.bv
.bv_val
);
155 cursor
->c_close( cursor
);
159 #ifdef BDB_TOOL_IDL_CACHING
160 bdb_tool_idl_flush( be
);
165 fprintf( stderr
, "Error, entries missing!\n");
166 for (i
=0; i
<nholes
; i
++) {
167 fprintf(stderr
, " entry %ld: %s\n",
168 holes
[i
].id
, holes
[i
].dn
.bv_val
);
176 ID
bdb_tool_entry_next(
181 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
183 assert( be
!= NULL
);
184 assert( slapMode
& SLAP_TOOL_MODE
);
185 assert( bdb
!= NULL
);
188 data
.ulen
= data
.dlen
= sizeof( ehbuf
);
190 data
.flags
|= DB_DBT_PARTIAL
;
191 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_NEXT
);
194 /* If we're doing linear indexing and there are more attrs to
195 * index, and we're at the end of the database, start over.
197 if ( index_nattrs
&& rc
== DB_NOTFOUND
) {
198 /* optional - do a checkpoint here? */
199 bdb_attr_info_free( bdb
->bi_attrs
[0] );
200 bdb
->bi_attrs
[0] = bdb
->bi_attrs
[index_nattrs
];
202 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_FIRST
);
211 BDB_DISK2ID( key
.data
, &id
);
216 ID
bdb_tool_dn2id_get(
223 EntryInfo
*ei
= NULL
;
226 if ( BER_BVISEMPTY(dn
) )
231 op
.o_tmpmemctx
= NULL
;
232 op
.o_tmpmfuncs
= &ch_mfuncs
;
234 rc
= bdb_cache_find_ndn( &op
, 0, dn
, &ei
);
235 if ( ei
) bdb_cache_entryinfo_unlock( ei
);
236 if ( rc
== DB_NOTFOUND
)
242 Entry
* bdb_tool_entry_get( BackendDB
*be
, ID id
)
248 assert( be
!= NULL
);
249 assert( slapMode
& SLAP_TOOL_MODE
);
251 if ( id
!= previd
) {
252 data
.ulen
= data
.dlen
= sizeof( ehbuf
);
254 data
.flags
|= DB_DBT_PARTIAL
;
256 BDB_ID2DISK( id
, &nid
);
257 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_SET
);
263 eh
.bv
.bv_val
= ehbuf
;
264 eh
.bv
.bv_len
= data
.size
;
265 rc
= entry_header( &eh
);
266 eoff
= eh
.data
- eh
.bv
.bv_val
;
271 data
.flags
&= ~DB_DBT_PARTIAL
;
273 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_CURRENT
);
274 if ( rc
!= DB_BUFFER_SMALL
) goto done
;
276 /* Allocate a block and retrieve the data */
277 eh
.bv
.bv_len
= eh
.nvals
* sizeof( struct berval
) + data
.size
;
278 eh
.bv
.bv_val
= ch_realloc( eh
.bv
.bv_val
, eh
.bv
.bv_len
);
279 eh
.data
= eh
.bv
.bv_val
+ eh
.nvals
* sizeof( struct berval
);
281 data
.ulen
= data
.size
;
283 /* Skip past already parsed nattr/nvals */
286 rc
= cursor
->c_get( cursor
, &key
, &data
, DB_CURRENT
);
289 #ifdef SLAP_ZONE_ALLOC
290 /* FIXME: will add ctx later */
291 rc
= entry_decode( &eh
, &e
, NULL
);
293 rc
= entry_decode( &eh
, &e
);
296 if( rc
== LDAP_SUCCESS
) {
299 if ( slapMode
& SLAP_TOOL_READONLY
) {
300 EntryInfo
*ei
= NULL
;
306 op
.o_tmpmemctx
= NULL
;
307 op
.o_tmpmfuncs
= &ch_mfuncs
;
309 rc
= bdb_cache_find_parent( &op
, CURSOR_GETLOCKER(cursor
), id
, &ei
);
310 if ( rc
== LDAP_SUCCESS
) {
311 bdb_cache_entryinfo_unlock( ei
);
325 static int bdb_tool_next_id(
332 struct berval dn
= e
->e_name
;
333 struct berval ndn
= e
->e_nname
;
334 struct berval pdn
, npdn
;
335 EntryInfo
*ei
= NULL
, eidummy
;
338 if (ndn
.bv_len
== 0) {
343 rc
= bdb_cache_find_ndn( op
, tid
? TXN_ID( tid
) : 0, &ndn
, &ei
);
344 if ( ei
) bdb_cache_entryinfo_unlock( ei
);
345 if ( rc
== DB_NOTFOUND
) {
346 if ( !be_issuffix( op
->o_bd
, &ndn
) ) {
348 dnParent( &dn
, &pdn
);
349 dnParent( &ndn
, &npdn
);
352 rc
= bdb_tool_next_id( op
, tid
, e
, text
, 1 );
358 /* If parent didn't exist, it was created just now
359 * and its ID is now in e->e_id. Make sure the current
360 * entry gets added under the new parent ID.
362 if ( eid
!= e
->e_id
) {
363 eidummy
.bei_id
= e
->e_id
;
367 rc
= bdb_next_id( op
->o_bd
, &e
->e_id
);
369 snprintf( text
->bv_val
, text
->bv_len
,
370 "next_id failed: %s (%d)",
371 db_strerror(rc
), rc
);
372 Debug( LDAP_DEBUG_ANY
,
373 "=> bdb_tool_next_id: %s\n", text
->bv_val
, 0, 0 );
376 rc
= bdb_dn2id_add( op
, tid
, ei
, e
);
378 snprintf( text
->bv_val
, text
->bv_len
,
379 "dn2id_add failed: %s (%d)",
380 db_strerror(rc
), rc
);
381 Debug( LDAP_DEBUG_ANY
,
382 "=> bdb_tool_next_id: %s\n", text
->bv_val
, 0, 0 );
384 if ( nholes
== nhmax
- 1 ) {
385 if ( holes
== hbuf
) {
386 holes
= ch_malloc( nhmax
* sizeof(dn_id
) * 2 );
387 AC_MEMCPY( holes
, hbuf
, sizeof(hbuf
) );
389 holes
= ch_realloc( holes
, nhmax
* sizeof(dn_id
) * 2 );
393 ber_dupbv( &holes
[nholes
].dn
, &ndn
);
394 holes
[nholes
++].id
= e
->e_id
;
396 } else if ( !hole
) {
399 e
->e_id
= ei
->bei_id
;
401 for ( i
=0; i
<nholes
; i
++) {
402 if ( holes
[i
].id
== e
->e_id
) {
404 free(holes
[i
].dn
.bv_val
);
405 for (j
=i
;j
<nholes
;j
++) holes
[j
] = holes
[j
+1];
409 } else if ( holes
[i
].id
> e
->e_id
) {
423 struct bdb_info
*bdb
= (struct bdb_info
*) op
->o_bd
->be_private
;
425 if ( !bdb
->bi_nattrs
)
428 if ( slapMode
& SLAP_TOOL_QUICK
) {
433 ir
= bdb_tool_index_rec
;
434 memset(ir
, 0, bdb
->bi_nattrs
* sizeof( IndexRec
));
436 for ( a
= e
->e_attrs
; a
!= NULL
; a
= a
->a_next
) {
437 rc
= bdb_index_recset( bdb
, a
, a
->a_desc
->ad_type
,
438 &a
->a_desc
->ad_tags
, ir
);
442 bdb_tool_ix_id
= e
->e_id
;
444 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex
);
445 /* Wait for all threads to be ready */
446 while ( bdb_tool_index_tcount
) {
447 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main
,
448 &bdb_tool_index_mutex
);
450 for ( i
=1; i
<slap_tool_thread_max
; i
++ )
451 bdb_tool_index_threads
[i
] = LDAP_BUSY
;
452 bdb_tool_index_tcount
= slap_tool_thread_max
- 1;
453 ldap_pvt_thread_cond_broadcast( &bdb_tool_index_cond_work
);
454 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex
);
455 rc
= bdb_index_recrun( op
, bdb
, ir
, e
->e_id
, 0 );
458 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex
);
459 for ( i
=1; i
<slap_tool_thread_max
; i
++ ) {
460 if ( bdb_tool_index_threads
[i
] == LDAP_BUSY
) {
461 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_main
,
462 &bdb_tool_index_mutex
);
466 if ( bdb_tool_index_threads
[i
] ) {
467 rc
= bdb_tool_index_threads
[i
];
471 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex
);
474 return bdb_index_entry_add( op
, txn
, e
);
478 ID
bdb_tool_entry_put(
481 struct berval
*text
)
484 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
489 assert( be
!= NULL
);
490 assert( slapMode
& SLAP_TOOL_MODE
);
492 assert( text
!= NULL
);
493 assert( text
->bv_val
!= NULL
);
494 assert( text
->bv_val
[0] == '\0' ); /* overconservative? */
496 Debug( LDAP_DEBUG_TRACE
, "=> " LDAP_XSTRING(bdb_tool_entry_put
)
497 "( %ld, \"%s\" )\n", (long) e
->e_id
, e
->e_dn
, 0 );
499 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
500 rc
= TXN_BEGIN( bdb
->bi_dbenv
, NULL
, &tid
,
501 bdb
->bi_db_opflags
);
503 snprintf( text
->bv_val
, text
->bv_len
,
504 "txn_begin failed: %s (%d)",
505 db_strerror(rc
), rc
);
506 Debug( LDAP_DEBUG_ANY
,
507 "=> " LDAP_XSTRING(bdb_tool_entry_put
) ": %s\n",
508 text
->bv_val
, 0, 0 );
515 op
.o_tmpmemctx
= NULL
;
516 op
.o_tmpmfuncs
= &ch_mfuncs
;
518 /* add dn2id indices */
519 rc
= bdb_tool_next_id( &op
, tid
, e
, text
, 0 );
524 if (( slapMode
& SLAP_TOOL_QUICK
) && (( e
->e_id
& 0xfff ) == 0xfff )) {
525 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex
);
526 ldap_pvt_thread_cond_signal( &bdb_tool_trickle_cond
);
527 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex
);
530 if ( !bdb
->bi_linear_index
)
531 rc
= bdb_tool_index_add( &op
, tid
, e
);
533 snprintf( text
->bv_val
, text
->bv_len
,
534 "index_entry_add failed: %s (%d)",
535 rc
== LDAP_OTHER
? "Internal error" :
536 db_strerror(rc
), rc
);
537 Debug( LDAP_DEBUG_ANY
,
538 "=> " LDAP_XSTRING(bdb_tool_entry_put
) ": %s\n",
539 text
->bv_val
, 0, 0 );
544 rc
= bdb_id2entry_add( be
, tid
, e
);
546 snprintf( text
->bv_val
, text
->bv_len
,
547 "id2entry_add failed: %s (%d)",
548 db_strerror(rc
), rc
);
549 Debug( LDAP_DEBUG_ANY
,
550 "=> " LDAP_XSTRING(bdb_tool_entry_put
) ": %s\n",
551 text
->bv_val
, 0, 0 );
557 if ( !( slapMode
& SLAP_TOOL_QUICK
)) {
558 rc
= TXN_COMMIT( tid
, 0 );
560 snprintf( text
->bv_val
, text
->bv_len
,
561 "txn_commit failed: %s (%d)",
562 db_strerror(rc
), rc
);
563 Debug( LDAP_DEBUG_ANY
,
564 "=> " LDAP_XSTRING(bdb_tool_entry_put
) ": %s\n",
565 text
->bv_val
, 0, 0 );
571 if ( !( slapMode
& SLAP_TOOL_QUICK
)) {
573 snprintf( text
->bv_val
, text
->bv_len
,
574 "txn_aborted! %s (%d)",
575 rc
== LDAP_OTHER
? "Internal error" :
576 db_strerror(rc
), rc
);
577 Debug( LDAP_DEBUG_ANY
,
578 "=> " LDAP_XSTRING(bdb_tool_entry_put
) ": %s\n",
579 text
->bv_val
, 0, 0 );
587 int bdb_tool_entry_reindex(
590 AttributeDescription
**adv
)
592 struct bdb_info
*bi
= (struct bdb_info
*) be
->be_private
;
599 Debug( LDAP_DEBUG_ARGS
,
600 "=> " LDAP_XSTRING(bdb_tool_entry_reindex
) "( %ld )\n",
603 /* No indexes configured, nothing to do. Could return an
604 * error here to shortcut things.
610 /* Check for explicit list of attrs to index */
614 if ( bi
->bi_attrs
[0]->ai_desc
!= adv
[0] ) {
616 for ( n
= 0; adv
[n
]; n
++ ) ;
619 for ( i
= 0; i
< n
; i
++ ) {
620 AttributeDescription
*ad
= adv
[i
];
621 for ( j
= i
-1; j
>=0; j
--) {
622 if ( SLAP_PTRCMP( adv
[j
], ad
) <= 0 ) break;
629 for ( i
= 0; adv
[i
]; i
++ ) {
630 if ( bi
->bi_attrs
[i
]->ai_desc
!= adv
[i
] ) {
631 for ( j
= i
+1; j
< bi
->bi_nattrs
; j
++ ) {
632 if ( bi
->bi_attrs
[j
]->ai_desc
== adv
[i
] ) {
633 AttrInfo
*ai
= bi
->bi_attrs
[i
];
634 bi
->bi_attrs
[i
] = bi
->bi_attrs
[j
];
635 bi
->bi_attrs
[j
] = ai
;
639 if ( j
== bi
->bi_nattrs
) {
640 Debug( LDAP_DEBUG_ANY
,
641 LDAP_XSTRING(bdb_tool_entry_reindex
)
642 ": no index configured for %s\n",
643 adv
[i
]->ad_cname
.bv_val
, 0, 0 );
651 /* Get the first attribute to index */
652 if (bi
->bi_linear_index
&& !index_nattrs
) {
653 index_nattrs
= bi
->bi_nattrs
- 1;
657 e
= bdb_tool_entry_get( be
, id
);
660 Debug( LDAP_DEBUG_ANY
,
661 LDAP_XSTRING(bdb_tool_entry_reindex
)
662 ": could not locate id=%ld\n",
667 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
668 rc
= TXN_BEGIN( bi
->bi_dbenv
, NULL
, &tid
, bi
->bi_db_opflags
);
670 Debug( LDAP_DEBUG_ANY
,
671 "=> " LDAP_XSTRING(bdb_tool_entry_reindex
) ": "
672 "txn_begin failed: %s (%d)\n",
673 db_strerror(rc
), rc
, 0 );
679 * just (re)add them for now
680 * assume that some other routine (not yet implemented)
681 * will zap index databases
685 Debug( LDAP_DEBUG_TRACE
,
686 "=> " LDAP_XSTRING(bdb_tool_entry_reindex
) "( %ld, \"%s\" )\n",
687 (long) id
, e
->e_dn
, 0 );
691 op
.o_tmpmemctx
= NULL
;
692 op
.o_tmpmfuncs
= &ch_mfuncs
;
694 rc
= bdb_tool_index_add( &op
, tid
, e
);
698 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
699 rc
= TXN_COMMIT( tid
, 0 );
701 Debug( LDAP_DEBUG_ANY
,
702 "=> " LDAP_XSTRING(bdb_tool_entry_reindex
)
703 ": txn_commit failed: %s (%d)\n",
704 db_strerror(rc
), rc
, 0 );
710 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
712 Debug( LDAP_DEBUG_ANY
,
713 "=> " LDAP_XSTRING(bdb_tool_entry_reindex
)
714 ": txn_aborted! %s (%d)\n",
715 db_strerror(rc
), rc
, 0 );
719 bdb_entry_release( &op
, e
, 0 );
724 ID
bdb_tool_entry_modify(
727 struct berval
*text
)
730 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
735 assert( be
!= NULL
);
736 assert( slapMode
& SLAP_TOOL_MODE
);
738 assert( text
!= NULL
);
739 assert( text
->bv_val
!= NULL
);
740 assert( text
->bv_val
[0] == '\0' ); /* overconservative? */
742 assert ( e
->e_id
!= NOID
);
744 Debug( LDAP_DEBUG_TRACE
,
745 "=> " LDAP_XSTRING(bdb_tool_entry_modify
) "( %ld, \"%s\" )\n",
746 (long) e
->e_id
, e
->e_dn
, 0 );
748 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
750 cursor
->c_close( cursor
);
753 rc
= TXN_BEGIN( bdb
->bi_dbenv
, NULL
, &tid
,
754 bdb
->bi_db_opflags
);
756 snprintf( text
->bv_val
, text
->bv_len
,
757 "txn_begin failed: %s (%d)",
758 db_strerror(rc
), rc
);
759 Debug( LDAP_DEBUG_ANY
,
760 "=> " LDAP_XSTRING(bdb_tool_entry_modify
) ": %s\n",
761 text
->bv_val
, 0, 0 );
768 op
.o_tmpmemctx
= NULL
;
769 op
.o_tmpmfuncs
= &ch_mfuncs
;
772 rc
= bdb_id2entry_update( be
, tid
, e
);
774 snprintf( text
->bv_val
, text
->bv_len
,
775 "id2entry_add failed: %s (%d)",
776 db_strerror(rc
), rc
);
777 Debug( LDAP_DEBUG_ANY
,
778 "=> " LDAP_XSTRING(bdb_tool_entry_modify
) ": %s\n",
779 text
->bv_val
, 0, 0 );
785 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
786 rc
= TXN_COMMIT( tid
, 0 );
788 snprintf( text
->bv_val
, text
->bv_len
,
789 "txn_commit failed: %s (%d)",
790 db_strerror(rc
), rc
);
791 Debug( LDAP_DEBUG_ANY
,
792 "=> " LDAP_XSTRING(bdb_tool_entry_modify
) ": "
793 "%s\n", text
->bv_val
, 0, 0 );
799 if (! (slapMode
& SLAP_TOOL_QUICK
)) {
801 snprintf( text
->bv_val
, text
->bv_len
,
802 "txn_aborted! %s (%d)",
803 db_strerror(rc
), rc
);
804 Debug( LDAP_DEBUG_ANY
,
805 "=> " LDAP_XSTRING(bdb_tool_entry_modify
) ": %s\n",
806 text
->bv_val
, 0, 0 );
814 #ifdef BDB_TOOL_IDL_CACHING
816 bdb_tool_idl_cmp( const void *v1
, const void *v2
)
818 const bdb_tool_idl_cache
*c1
= v1
, *c2
= v2
;
821 if (( rc
= c1
->kstr
.bv_len
- c2
->kstr
.bv_len
)) return rc
;
822 return memcmp( c1
->kstr
.bv_val
, c2
->kstr
.bv_val
, c1
->kstr
.bv_len
);
826 bdb_tool_idl_flush_one( void *v1
, void *arg
)
828 bdb_tool_idl_cache
*ic
= v1
;
830 struct bdb_info
*bdb
= bdb_tool_info
;
831 bdb_tool_idl_cache_entry
*ice
;
837 /* Freshly allocated, ignore it */
838 if ( !ic
->head
&& ic
->count
<= BDB_IDL_DB_SIZE
) {
842 rc
= db
->cursor( db
, NULL
, &curs
, 0 );
849 bv2DBT( &ic
->kstr
, &key
);
851 data
.size
= data
.ulen
= sizeof( ID
);
852 data
.flags
= DB_DBT_USERMEM
;
855 rc
= curs
->c_get( curs
, &key
, &data
, DB_SET
);
856 /* If key already exists and we're writing a range... */
857 if ( rc
== 0 && ic
->count
> BDB_IDL_DB_SIZE
) {
858 /* If it's not currently a range, must delete old info */
861 while ( curs
->c_get( curs
, &key
, &data
, DB_NEXT_DUP
) == 0 )
862 curs
->c_del( curs
, 0 );
865 /* Store range marker */
866 curs
->c_put( curs
, &key
, &data
, DB_KEYFIRST
);
870 rc
= curs
->c_get( curs
, &key
, &data
, DB_NEXT_DUP
);
873 rc
= curs
->c_get( curs
, &key
, &data
, DB_NEXT_DUP
);
876 curs
->c_del( curs
, 0 );
878 BDB_ID2DISK( ic
->last
, &nid
);
879 curs
->c_put( curs
, &key
, &data
, DB_KEYLAST
);
881 } else if ( rc
&& rc
!= DB_NOTFOUND
) {
883 } else if ( ic
->count
> BDB_IDL_DB_SIZE
) {
884 /* range, didn't exist before */
886 rc
= curs
->c_put( curs
, &key
, &data
, DB_KEYLAST
);
888 BDB_ID2DISK( ic
->first
, &nid
);
889 rc
= curs
->c_put( curs
, &key
, &data
, DB_KEYLAST
);
891 BDB_ID2DISK( ic
->last
, &nid
);
892 rc
= curs
->c_put( curs
, &key
, &data
, DB_KEYLAST
);
901 /* Just a normal write */
903 for ( ice
= ic
->head
, n
=0; ice
; ice
= ice
->next
, n
++ ) {
908 end
= ic
->count
& (IDBLOCK
-1);
912 for ( i
=0; i
<end
; i
++ ) {
913 if ( !ice
->ids
[i
] ) continue;
914 BDB_ID2DISK( ice
->ids
[i
], &nid
);
915 rc
= curs
->c_put( curs
, &key
, &data
, DB_NODUPDATA
);
917 if ( rc
== DB_KEYEXIST
) {
931 ldap_pvt_thread_mutex_lock( &bdb
->bi_idl_tree_lrulock
);
932 ic
->tail
->next
= bdb_tool_idl_free_list
;
933 bdb_tool_idl_free_list
= ic
->head
;
934 bdb
->bi_idl_cache_size
-= n
;
935 ldap_pvt_thread_mutex_unlock( &bdb
->bi_idl_tree_lrulock
);
938 if ( ic
!= db
->app_private
) {
941 ic
->head
= ic
->tail
= NULL
;
943 curs
->c_close( curs
);
948 bdb_tool_idl_flush_db( DB
*db
, bdb_tool_idl_cache
*ic
)
950 Avlnode
*root
= db
->app_private
;
953 db
->app_private
= ic
;
954 rc
= avl_apply( root
, bdb_tool_idl_flush_one
, db
, -1, AVL_INORDER
);
955 avl_free( root
, NULL
);
956 db
->app_private
= NULL
;
963 bdb_tool_idl_flush( BackendDB
*be
)
965 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
970 for ( i
=BDB_NDB
; i
< bdb
->bi_ndatabases
; i
++ ) {
971 db
= bdb
->bi_databases
[i
]->bdi_db
;
972 if ( !db
->app_private
) continue;
973 rc
= bdb_tool_idl_flush_db( db
, NULL
);
978 bdb
->bi_idl_cache_size
= 0;
983 int bdb_tool_idl_add(
990 struct bdb_info
*bdb
= (struct bdb_info
*) be
->be_private
;
991 bdb_tool_idl_cache
*ic
, itmp
;
992 bdb_tool_idl_cache_entry
*ice
;
995 if ( !bdb
->bi_idl_cache_max_size
)
996 return bdb_idl_insert_key( be
, db
, txn
, key
, id
);
998 DBT2bv( key
, &itmp
.kstr
);
1000 ic
= avl_find( (Avlnode
*)db
->app_private
, &itmp
, bdb_tool_idl_cmp
);
1002 /* No entry yet, create one */
1009 ic
= ch_malloc( sizeof( bdb_tool_idl_cache
) + itmp
.kstr
.bv_len
);
1010 ic
->kstr
.bv_len
= itmp
.kstr
.bv_len
;
1011 ic
->kstr
.bv_val
= (char *)(ic
+1);
1012 AC_MEMCPY( ic
->kstr
.bv_val
, itmp
.kstr
.bv_val
, ic
->kstr
.bv_len
);
1013 ic
->head
= ic
->tail
= NULL
;
1016 avl_insert( (Avlnode
**)&db
->app_private
, ic
, bdb_tool_idl_cmp
,
1019 /* load existing key count here */
1020 rc
= db
->cursor( db
, NULL
, &curs
, 0 );
1021 if ( rc
) return rc
;
1023 data
.ulen
= sizeof( ID
);
1024 data
.flags
= DB_DBT_USERMEM
;
1026 rc
= curs
->c_get( curs
, key
, &data
, DB_SET
);
1029 ic
->count
= BDB_IDL_DB_SIZE
+1;
1033 curs
->c_count( curs
, &count
, 0 );
1035 BDB_DISK2ID( &nid
, &ic
->first
);
1038 curs
->c_close( curs
);
1040 /* are we a range already? */
1041 if ( ic
->count
> BDB_IDL_DB_SIZE
) {
1044 /* Are we at the limit, and converting to a range? */
1045 } else if ( ic
->count
== BDB_IDL_DB_SIZE
) {
1047 for ( ice
= ic
->head
, n
=0; ice
; ice
= ice
->next
, n
++ )
1050 ldap_pvt_thread_mutex_lock( &bdb
->bi_idl_tree_lrulock
);
1051 ic
->tail
->next
= bdb_tool_idl_free_list
;
1052 bdb_tool_idl_free_list
= ic
->head
;
1053 bdb
->bi_idl_cache_size
-= n
;
1054 ldap_pvt_thread_mutex_unlock( &bdb
->bi_idl_tree_lrulock
);
1056 ic
->head
= ic
->tail
= NULL
;
1061 /* No free block, create that too */
1062 if ( !ic
->tail
|| ( ic
->count
& (IDBLOCK
-1)) == 0) {
1064 ldap_pvt_thread_mutex_lock( &bdb
->bi_idl_tree_lrulock
);
1065 if ( bdb
->bi_idl_cache_size
>= bdb
->bi_idl_cache_max_size
) {
1066 ldap_pvt_thread_mutex_unlock( &bdb
->bi_idl_tree_lrulock
);
1067 rc
= bdb_tool_idl_flush_db( db
, ic
);
1070 avl_insert( (Avlnode
**)&db
->app_private
, ic
, bdb_tool_idl_cmp
,
1072 ldap_pvt_thread_mutex_lock( &bdb
->bi_idl_tree_lrulock
);
1074 bdb
->bi_idl_cache_size
++;
1075 if ( bdb_tool_idl_free_list
) {
1076 ice
= bdb_tool_idl_free_list
;
1077 bdb_tool_idl_free_list
= ice
->next
;
1079 ldap_pvt_thread_mutex_unlock( &bdb
->bi_idl_tree_lrulock
);
1081 ice
= ch_malloc( sizeof( bdb_tool_idl_cache_entry
));
1083 memset( ice
, 0, sizeof( *ice
));
1087 ic
->tail
->next
= ice
;
1094 ice
->ids
[ ic
->count
& (IDBLOCK
-1) ] = id
;
1102 bdb_tool_trickle_task( void *ctx
, void *ptr
)
1107 ldap_pvt_thread_mutex_lock( &bdb_tool_trickle_mutex
);
1109 ldap_pvt_thread_cond_wait( &bdb_tool_trickle_cond
,
1110 &bdb_tool_trickle_mutex
);
1111 if ( slapd_shutdown
)
1113 env
->memp_trickle( env
, 30, &wrote
);
1115 ldap_pvt_thread_mutex_unlock( &bdb_tool_trickle_mutex
);
1121 bdb_tool_index_task( void *ctx
, void *ptr
)
1123 int base
= *(int *)ptr
;
1127 ldap_pvt_thread_mutex_lock( &bdb_tool_index_mutex
);
1128 bdb_tool_index_tcount
--;
1129 if ( !bdb_tool_index_tcount
)
1130 ldap_pvt_thread_cond_signal( &bdb_tool_index_cond_main
);
1131 ldap_pvt_thread_cond_wait( &bdb_tool_index_cond_work
,
1132 &bdb_tool_index_mutex
);
1133 ldap_pvt_thread_mutex_unlock( &bdb_tool_index_mutex
);
1134 if ( slapd_shutdown
)
1137 bdb_tool_index_threads
[base
] = bdb_index_recrun( bdb_tool_ix_op
,
1138 bdb_tool_info
, bdb_tool_index_rec
, bdb_tool_ix_id
, base
);