1/* monitor.c - monitor bdb backend */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2000-2011 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#include <ac/unistd.h> 22#include <ac/stdlib.h> 23#include <ac/errno.h> 24#include <sys/stat.h> 25#include "lutil.h" 26#include "back-bdb.h" 27 28#include "../back-monitor/back-monitor.h" 29 30#include "config.h" 31 32static ObjectClass *oc_olmBDBDatabase; 33 34static AttributeDescription *ad_olmBDBEntryCache, 35 *ad_olmBDBDNCache, *ad_olmBDBIDLCache, 36 *ad_olmDbDirectory; 37 38#ifdef BDB_MONITOR_IDX 39static int 40bdb_monitor_idx_entry_add( 41 struct bdb_info *bdb, 42 Entry *e ); 43 44static AttributeDescription *ad_olmDbNotIndexed; 45#endif /* BDB_MONITOR_IDX */ 46 47/* 48 * NOTE: there's some confusion in monitor OID arc; 49 * by now, let's consider: 50 * 51 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0 52 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1 53 * BDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.1 54 * 55 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0 56 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1 57 * BDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.1 58 */ 59 60static struct { 61 char *name; 62 char *oid; 63} s_oid[] = { 64 { "olmBDBAttributes", "olmDatabaseAttributes:1" }, 65 { "olmBDBObjectClasses", "olmDatabaseObjectClasses:1" }, 66 67 { NULL } 68}; 69 70static struct { 71 char *desc; 72 AttributeDescription **ad; 73} s_at[] = { 74 { "( olmBDBAttributes:1 " 75 "NAME ( 'olmBDBEntryCache' ) " 76 "DESC 'Number of items in Entry Cache' " 77 "SUP monitorCounter " 78 "NO-USER-MODIFICATION " 79 "USAGE dSAOperation )", 80 &ad_olmBDBEntryCache }, 81 82 { "( olmBDBAttributes:2 " 83 "NAME ( 'olmBDBDNCache' ) " 84 "DESC 'Number of items in DN Cache' " 85 "SUP monitorCounter " 86 "NO-USER-MODIFICATION " 87 "USAGE dSAOperation )", 88 &ad_olmBDBDNCache }, 89 90 { "( olmBDBAttributes:3 " 91 "NAME ( 'olmBDBIDLCache' ) " 92 "DESC 'Number of items in IDL Cache' " 93 "SUP monitorCounter " 94 "NO-USER-MODIFICATION " 95 "USAGE dSAOperation )", 96 &ad_olmBDBIDLCache }, 97 98 { "( olmDatabaseAttributes:1 " 99 "NAME ( 'olmDbDirectory' ) " 100 "DESC 'Path name of the directory " 101 "where the database environment resides' " 102 "SUP monitoredInfo " 103 "NO-USER-MODIFICATION " 104 "USAGE dSAOperation )", 105 &ad_olmDbDirectory }, 106 107#ifdef BDB_MONITOR_IDX 108 { "( olmDatabaseAttributes:2 " 109 "NAME ( 'olmDbNotIndexed' ) " 110 "DESC 'Missing indexes resulting from candidate selection' " 111 "SUP monitoredInfo " 112 "NO-USER-MODIFICATION " 113 "USAGE dSAOperation )", 114 &ad_olmDbNotIndexed }, 115#endif /* BDB_MONITOR_IDX */ 116 117 { NULL } 118}; 119 120static struct { 121 char *desc; 122 ObjectClass **oc; 123} s_oc[] = { 124 /* augments an existing object, so it must be AUXILIARY 125 * FIXME: derive from some ABSTRACT "monitoredEntity"? */ 126 { "( olmBDBObjectClasses:1 " 127 "NAME ( 'olmBDBDatabase' ) " 128 "SUP top AUXILIARY " 129 "MAY ( " 130 "olmBDBEntryCache " 131 "$ olmBDBDNCache " 132 "$ olmBDBIDLCache " 133 "$ olmDbDirectory " 134#ifdef BDB_MONITOR_IDX 135 "$ olmDbNotIndexed " 136#endif /* BDB_MONITOR_IDX */ 137 ") )", 138 &oc_olmBDBDatabase }, 139 140 { NULL } 141}; 142 143static int 144bdb_monitor_update( 145 Operation *op, 146 SlapReply *rs, 147 Entry *e, 148 void *priv ) 149{ 150 struct bdb_info *bdb = (struct bdb_info *) priv; 151 Attribute *a; 152 153 char buf[ BUFSIZ ]; 154 struct berval bv; 155 156 assert( ad_olmBDBEntryCache != NULL ); 157 158 a = attr_find( e->e_attrs, ad_olmBDBEntryCache ); 159 assert( a != NULL ); 160 bv.bv_val = buf; 161 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_cursize ); 162 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 163 164 a = attr_find( e->e_attrs, ad_olmBDBDNCache ); 165 assert( a != NULL ); 166 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_cache.c_eiused ); 167 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 168 169 a = attr_find( e->e_attrs, ad_olmBDBIDLCache ); 170 assert( a != NULL ); 171 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", bdb->bi_idl_cache_size ); 172 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 173 174#ifdef BDB_MONITOR_IDX 175 bdb_monitor_idx_entry_add( bdb, e ); 176#endif /* BDB_MONITOR_IDX */ 177 178 return SLAP_CB_CONTINUE; 179} 180 181#if 0 /* uncomment if required */ 182static int 183bdb_monitor_modify( 184 Operation *op, 185 SlapReply *rs, 186 Entry *e, 187 void *priv ) 188{ 189 return SLAP_CB_CONTINUE; 190} 191#endif 192 193static int 194bdb_monitor_free( 195 Entry *e, 196 void **priv ) 197{ 198 struct berval values[ 2 ]; 199 Modification mod = { 0 }; 200 201 const char *text; 202 char textbuf[ SLAP_TEXT_BUFLEN ]; 203 204 int i, rc; 205 206 /* NOTE: if slap_shutdown != 0, priv might have already been freed */ 207 *priv = NULL; 208 209 /* Remove objectClass */ 210 mod.sm_op = LDAP_MOD_DELETE; 211 mod.sm_desc = slap_schema.si_ad_objectClass; 212 mod.sm_values = values; 213 mod.sm_numvals = 1; 214 values[ 0 ] = oc_olmBDBDatabase->soc_cname; 215 BER_BVZERO( &values[ 1 ] ); 216 217 rc = modify_delete_values( e, &mod, 1, &text, 218 textbuf, sizeof( textbuf ) ); 219 /* don't care too much about return code... */ 220 221 /* remove attrs */ 222 mod.sm_values = NULL; 223 mod.sm_numvals = 0; 224 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 225 mod.sm_desc = *s_at[ i ].ad; 226 rc = modify_delete_values( e, &mod, 1, &text, 227 textbuf, sizeof( textbuf ) ); 228 /* don't care too much about return code... */ 229 } 230 231 return SLAP_CB_CONTINUE; 232} 233 234#define bdb_monitor_initialize BDB_SYMBOL(monitor_initialize) 235 236/* 237 * call from within bdb_initialize() 238 */ 239static int 240bdb_monitor_initialize( void ) 241{ 242 int i, code; 243 ConfigArgs c; 244 char *argv[ 3 ]; 245 246 static int bdb_monitor_initialized = 0; 247 248 /* set to 0 when successfully initialized; otherwise, remember failure */ 249 static int bdb_monitor_initialized_failure = 1; 250 251 if ( bdb_monitor_initialized++ ) { 252 return bdb_monitor_initialized_failure; 253 } 254 255 if ( backend_info( "monitor" ) == NULL ) { 256 return -1; 257 } 258 259 /* register schema here */ 260 261 argv[ 0 ] = "back-bdb/back-hdb monitor"; 262 c.argv = argv; 263 c.argc = 3; 264 c.fname = argv[0]; 265 266 for ( i = 0; s_oid[ i ].name; i++ ) { 267 c.lineno = i; 268 argv[ 1 ] = s_oid[ i ].name; 269 argv[ 2 ] = s_oid[ i ].oid; 270 271 if ( parse_oidm( &c, 0, NULL ) != 0 ) { 272 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize) 273 ": unable to add " 274 "objectIdentifier \"%s=%s\"\n", 275 s_oid[ i ].name, s_oid[ i ].oid, 0 ); 276 return 2; 277 } 278 } 279 280 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 281 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 ); 282 if ( code != LDAP_SUCCESS ) { 283 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize) 284 ": register_at failed for attributeType (%s)\n", 285 s_at[ i ].desc, 0, 0 ); 286 return 3; 287 288 } else { 289 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 290 } 291 } 292 293 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) { 294 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 ); 295 if ( code != LDAP_SUCCESS ) { 296 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_initialize) 297 ": register_oc failed for objectClass (%s)\n", 298 s_oc[ i ].desc, 0, 0 ); 299 return 4; 300 301 } else { 302 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 303 } 304 } 305 306 return ( bdb_monitor_initialized_failure = LDAP_SUCCESS ); 307} 308 309/* 310 * call from within bdb_db_init() 311 */ 312int 313bdb_monitor_db_init( BackendDB *be ) 314{ 315 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 316 317 if ( bdb_monitor_initialize() == LDAP_SUCCESS ) { 318 /* monitoring in back-bdb is on by default */ 319 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; 320 } 321 322#ifdef BDB_MONITOR_IDX 323 bdb->bi_idx = NULL; 324 ldap_pvt_thread_mutex_init( &bdb->bi_idx_mutex ); 325#endif /* BDB_MONITOR_IDX */ 326 327 return 0; 328} 329 330/* 331 * call from within bdb_db_open() 332 */ 333int 334bdb_monitor_db_open( BackendDB *be ) 335{ 336 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 337 Attribute *a, *next; 338 monitor_callback_t *cb = NULL; 339 int rc = 0; 340 BackendInfo *mi; 341 monitor_extra_t *mbe; 342 struct berval dummy = BER_BVC(""); 343 344 if ( !SLAP_DBMONITORING( be ) ) { 345 return 0; 346 } 347 348 mi = backend_info( "monitor" ); 349 if ( !mi || !mi->bi_extra ) { 350 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; 351 return 0; 352 } 353 mbe = mi->bi_extra; 354 355 /* don't bother if monitor is not configured */ 356 if ( !mbe->is_configured() ) { 357 static int warning = 0; 358 359 if ( warning++ == 0 ) { 360 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(bdb_monitor_db_open) 361 ": monitoring disabled; " 362 "configure monitor database to enable\n", 363 0, 0, 0 ); 364 } 365 366 return 0; 367 } 368 369 /* alloc as many as required (plus 1 for objectClass) */ 370 a = attrs_alloc( 1 + 4 ); 371 if ( a == NULL ) { 372 rc = 1; 373 goto cleanup; 374 } 375 376 a->a_desc = slap_schema.si_ad_objectClass; 377 attr_valadd( a, &oc_olmBDBDatabase->soc_cname, NULL, 1 ); 378 next = a->a_next; 379 380 { 381 struct berval bv = BER_BVC( "0" ); 382 383 next->a_desc = ad_olmBDBEntryCache; 384 attr_valadd( next, &bv, NULL, 1 ); 385 next = next->a_next; 386 387 next->a_desc = ad_olmBDBDNCache; 388 attr_valadd( next, &bv, NULL, 1 ); 389 next = next->a_next; 390 391 next->a_desc = ad_olmBDBIDLCache; 392 attr_valadd( next, &bv, NULL, 1 ); 393 next = next->a_next; 394 } 395 396 { 397 struct berval bv, nbv; 398 ber_len_t pathlen = 0, len = 0; 399 char path[ MAXPATHLEN ] = { '\0' }; 400 char *fname = bdb->bi_dbenv_home, 401 *ptr; 402 403 len = strlen( fname ); 404 if ( fname[ 0 ] != '/' ) { 405 /* get full path name */ 406 getcwd( path, sizeof( path ) ); 407 pathlen = strlen( path ); 408 409 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) { 410 fname += 2; 411 len -= 2; 412 } 413 } 414 415 bv.bv_len = pathlen + STRLENOF( "/" ) + len; 416 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 ); 417 if ( pathlen ) { 418 ptr = lutil_strncopy( ptr, path, pathlen ); 419 ptr[ 0 ] = '/'; 420 ptr++; 421 } 422 ptr = lutil_strncopy( ptr, fname, len ); 423 if ( ptr[ -1 ] != '/' ) { 424 ptr[ 0 ] = '/'; 425 ptr++; 426 } 427 ptr[ 0 ] = '\0'; 428 429 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL ); 430 431 next->a_desc = ad_olmDbDirectory; 432 next->a_vals = ch_calloc( sizeof( struct berval ), 2 ); 433 next->a_vals[ 0 ] = bv; 434 next->a_numvals = 1; 435 436 if ( BER_BVISNULL( &nbv ) ) { 437 next->a_nvals = next->a_vals; 438 439 } else { 440 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 ); 441 next->a_nvals[ 0 ] = nbv; 442 } 443 444 next = next->a_next; 445 } 446 447 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 448 cb->mc_update = bdb_monitor_update; 449#if 0 /* uncomment if required */ 450 cb->mc_modify = bdb_monitor_modify; 451#endif 452 cb->mc_free = bdb_monitor_free; 453 cb->mc_private = (void *)bdb; 454 455 /* make sure the database is registered; then add monitor attributes */ 456 rc = mbe->register_database( be, &bdb->bi_monitor.bdm_ndn ); 457 if ( rc == 0 ) { 458 rc = mbe->register_entry_attrs( &bdb->bi_monitor.bdm_ndn, a, cb, 459 &dummy, 0, &dummy ); 460 } 461 462cleanup:; 463 if ( rc != 0 ) { 464 if ( cb != NULL ) { 465 ch_free( cb ); 466 cb = NULL; 467 } 468 469 if ( a != NULL ) { 470 attrs_free( a ); 471 a = NULL; 472 } 473 } 474 475 /* store for cleanup */ 476 bdb->bi_monitor.bdm_cb = (void *)cb; 477 478 /* we don't need to keep track of the attributes, because 479 * bdb_monitor_free() takes care of everything */ 480 if ( a != NULL ) { 481 attrs_free( a ); 482 } 483 484 return rc; 485} 486 487/* 488 * call from within bdb_db_close() 489 */ 490int 491bdb_monitor_db_close( BackendDB *be ) 492{ 493 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 494 495 if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_ndn ) ) { 496 BackendInfo *mi = backend_info( "monitor" ); 497 monitor_extra_t *mbe; 498 499 if ( mi && &mi->bi_extra ) { 500 mbe = mi->bi_extra; 501 mbe->unregister_entry_callback( &bdb->bi_monitor.bdm_ndn, 502 (monitor_callback_t *)bdb->bi_monitor.bdm_cb, 503 NULL, 0, NULL ); 504 } 505 506 memset( &bdb->bi_monitor, 0, sizeof( bdb->bi_monitor ) ); 507 } 508 509 return 0; 510} 511 512/* 513 * call from within bdb_db_destroy() 514 */ 515int 516bdb_monitor_db_destroy( BackendDB *be ) 517{ 518#ifdef BDB_MONITOR_IDX 519 struct bdb_info *bdb = (struct bdb_info *) be->be_private; 520 521 /* TODO: free tree */ 522 ldap_pvt_thread_mutex_destroy( &bdb->bi_idx_mutex ); 523 avl_free( bdb->bi_idx, ch_free ); 524#endif /* BDB_MONITOR_IDX */ 525 526 return 0; 527} 528 529#ifdef BDB_MONITOR_IDX 530 531#define BDB_MONITOR_IDX_TYPES (4) 532 533typedef struct monitor_idx_t monitor_idx_t; 534 535struct monitor_idx_t { 536 AttributeDescription *idx_ad; 537 unsigned long idx_count[BDB_MONITOR_IDX_TYPES]; 538}; 539 540static int 541bdb_monitor_bitmask2key( slap_mask_t bitmask ) 542{ 543 int key; 544 545 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U ); 546 key++ ) 547 bitmask >>= 1; 548 549 return key; 550} 551 552static struct berval idxbv[] = { 553 BER_BVC( "present=" ), 554 BER_BVC( "equality=" ), 555 BER_BVC( "approx=" ), 556 BER_BVC( "substr=" ), 557 BER_BVNULL 558}; 559 560static ber_len_t 561bdb_monitor_idx2len( monitor_idx_t *idx ) 562{ 563 int i; 564 ber_len_t len = 0; 565 566 for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { 567 if ( idx->idx_count[ i ] != 0 ) { 568 len += idxbv[i].bv_len; 569 } 570 } 571 572 return len; 573} 574 575static int 576monitor_idx_cmp( const void *p1, const void *p2 ) 577{ 578 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1; 579 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2; 580 581 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ); 582} 583 584static int 585monitor_idx_dup( void *p1, void *p2 ) 586{ 587 monitor_idx_t *idx1 = (monitor_idx_t *)p1; 588 monitor_idx_t *idx2 = (monitor_idx_t *)p2; 589 590 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0; 591} 592 593int 594bdb_monitor_idx_add( 595 struct bdb_info *bdb, 596 AttributeDescription *desc, 597 slap_mask_t type ) 598{ 599 monitor_idx_t idx_dummy = { 0 }, 600 *idx; 601 int rc = 0, key; 602 603 idx_dummy.idx_ad = desc; 604 key = bdb_monitor_bitmask2key( type ) - 1; 605 if ( key >= BDB_MONITOR_IDX_TYPES ) { 606 /* invalid index type */ 607 return -1; 608 } 609 610 ldap_pvt_thread_mutex_lock( &bdb->bi_idx_mutex ); 611 612 idx = (monitor_idx_t *)avl_find( bdb->bi_idx, 613 (caddr_t)&idx_dummy, monitor_idx_cmp ); 614 if ( idx == NULL ) { 615 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 ); 616 idx->idx_ad = desc; 617 idx->idx_count[ key ] = 1; 618 619 switch ( avl_insert( &bdb->bi_idx, (caddr_t)idx, 620 monitor_idx_cmp, monitor_idx_dup ) ) 621 { 622 case 0: 623 break; 624 625 default: 626 ch_free( idx ); 627 rc = -1; 628 } 629 630 } else { 631 idx->idx_count[ key ]++; 632 } 633 634 ldap_pvt_thread_mutex_unlock( &bdb->bi_idx_mutex ); 635 636 return rc; 637} 638 639static int 640bdb_monitor_idx_apply( void *v_idx, void *v_valp ) 641{ 642 monitor_idx_t *idx = (monitor_idx_t *)v_idx; 643 BerVarray *valp = (BerVarray *)v_valp; 644 645 struct berval bv; 646 char *ptr; 647 char count_buf[ BDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ]; 648 ber_len_t count_len[ BDB_MONITOR_IDX_TYPES ], 649 idx_len; 650 int i, num = 0; 651 652 idx_len = bdb_monitor_idx2len( idx ); 653 654 bv.bv_len = 0; 655 for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { 656 if ( idx->idx_count[ i ] == 0 ) { 657 continue; 658 } 659 660 count_len[ i ] = snprintf( count_buf[ i ], 661 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] ); 662 bv.bv_len += count_len[ i ]; 663 num++; 664 } 665 666 bv.bv_len += idx->idx_ad->ad_cname.bv_len 667 + num 668 + idx_len; 669 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); 670 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val ); 671 for ( i = 0; i < BDB_MONITOR_IDX_TYPES; i++ ) { 672 if ( idx->idx_count[ i ] == 0 ) { 673 continue; 674 } 675 676 ptr[ 0 ] = '#'; 677 ++ptr; 678 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val ); 679 ptr = lutil_strcopy( ptr, count_buf[ i ] ); 680 } 681 682 ber_bvarray_add( valp, &bv ); 683 684 return 0; 685} 686 687static int 688bdb_monitor_idx_entry_add( 689 struct bdb_info *bdb, 690 Entry *e ) 691{ 692 BerVarray vals = NULL; 693 Attribute *a; 694 695 a = attr_find( e->e_attrs, ad_olmDbNotIndexed ); 696 697 ldap_pvt_thread_mutex_lock( &bdb->bi_idx_mutex ); 698 699 avl_apply( bdb->bi_idx, bdb_monitor_idx_apply, 700 &vals, -1, AVL_INORDER ); 701 702 ldap_pvt_thread_mutex_unlock( &bdb->bi_idx_mutex ); 703 704 if ( vals != NULL ) { 705 if ( a != NULL ) { 706 assert( a->a_nvals == a->a_vals ); 707 708 ber_bvarray_free( a->a_vals ); 709 710 } else { 711 Attribute **ap; 712 713 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) 714 ; 715 *ap = attr_alloc( ad_olmDbNotIndexed ); 716 a = *ap; 717 } 718 a->a_vals = vals; 719 a->a_nvals = a->a_vals; 720 } 721 722 return 0; 723} 724 725#endif /* BDB_MONITOR_IDX */ 726