1 /* $NetBSD: monitor.c,v 1.3 2021/08/14 16:15:00 christos Exp $ */ 2 3 /* monitor.c - monitor mdb backend */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2000-2021 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 19 #include <sys/cdefs.h> 20 __RCSID("$NetBSD: monitor.c,v 1.3 2021/08/14 16:15:00 christos Exp $"); 21 22 #include "portable.h" 23 24 #include <stdio.h> 25 #include <ac/string.h> 26 #include <ac/unistd.h> 27 #include <ac/stdlib.h> 28 #include <ac/errno.h> 29 #include <sys/stat.h> 30 #include "lutil.h" 31 #include "back-mdb.h" 32 33 #include "../back-monitor/back-monitor.h" 34 35 #include "slap-config.h" 36 37 static ObjectClass *oc_olmMDBDatabase; 38 39 static AttributeDescription *ad_olmDbDirectory; 40 41 #ifdef MDB_MONITOR_IDX 42 static int 43 mdb_monitor_idx_entry_add( 44 struct mdb_info *mdb, 45 Entry *e ); 46 47 static AttributeDescription *ad_olmDbNotIndexed; 48 #endif /* MDB_MONITOR_IDX */ 49 50 static AttributeDescription *ad_olmMDBPagesMax, 51 *ad_olmMDBPagesUsed, *ad_olmMDBPagesFree; 52 53 static AttributeDescription *ad_olmMDBReadersMax, 54 *ad_olmMDBReadersUsed; 55 56 static AttributeDescription *ad_olmMDBEntries; 57 58 /* 59 * NOTE: there's some confusion in monitor OID arc; 60 * by now, let's consider: 61 * 62 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0 63 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1 64 * MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.3 65 * 66 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0 67 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1 68 * MDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.3 69 */ 70 71 static struct { 72 char *name; 73 char *oid; 74 } s_oid[] = { 75 { "olmMDBAttributes", "olmDatabaseAttributes:1" }, 76 { "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" }, 77 78 { NULL } 79 }; 80 81 static struct { 82 char *desc; 83 AttributeDescription **ad; 84 } s_at[] = { 85 { "( olmDatabaseAttributes:1 " 86 "NAME ( 'olmDbDirectory' ) " 87 "DESC 'Path name of the directory " 88 "where the database environment resides' " 89 "SUP monitoredInfo " 90 "NO-USER-MODIFICATION " 91 "USAGE dSAOperation )", 92 &ad_olmDbDirectory }, 93 94 #ifdef MDB_MONITOR_IDX 95 { "( olmDatabaseAttributes:2 " 96 "NAME ( 'olmDbNotIndexed' ) " 97 "DESC 'Missing indexes resulting from candidate selection' " 98 "SUP monitoredInfo " 99 "NO-USER-MODIFICATION " 100 "USAGE dSAOperation )", 101 &ad_olmDbNotIndexed }, 102 #endif /* MDB_MONITOR_IDX */ 103 104 { "( olmMDBAttributes:1 " 105 "NAME ( 'olmMDBPagesMax' ) " 106 "DESC 'Maximum number of pages' " 107 "SUP monitorCounter " 108 "NO-USER-MODIFICATION " 109 "USAGE dSAOperation )", 110 &ad_olmMDBPagesMax }, 111 112 { "( olmMDBAttributes:2 " 113 "NAME ( 'olmMDBPagesUsed' ) " 114 "DESC 'Number of pages in use' " 115 "SUP monitorCounter " 116 "NO-USER-MODIFICATION " 117 "USAGE dSAOperation )", 118 &ad_olmMDBPagesUsed }, 119 120 { "( olmMDBAttributes:3 " 121 "NAME ( 'olmMDBPagesFree' ) " 122 "DESC 'Number of free pages' " 123 "SUP monitorCounter " 124 "NO-USER-MODIFICATION " 125 "USAGE dSAOperation )", 126 &ad_olmMDBPagesFree }, 127 128 { "( olmMDBAttributes:4 " 129 "NAME ( 'olmMDBReadersMax' ) " 130 "DESC 'Maximum number of readers' " 131 "SUP monitorCounter " 132 "NO-USER-MODIFICATION " 133 "USAGE dSAOperation )", 134 &ad_olmMDBReadersMax }, 135 136 { "( olmMDBAttributes:5 " 137 "NAME ( 'olmMDBReadersUsed' ) " 138 "DESC 'Number of readers in use' " 139 "SUP monitorCounter " 140 "NO-USER-MODIFICATION " 141 "USAGE dSAOperation )", 142 &ad_olmMDBReadersUsed }, 143 144 { "( olmMDBAttributes:6 " 145 "NAME ( 'olmMDBEntries' ) " 146 "DESC 'Number of entries in DB' " 147 "SUP monitorCounter " 148 "NO-USER-MODIFICATION " 149 "USAGE dSAOperation )", 150 &ad_olmMDBEntries }, 151 { NULL } 152 }; 153 154 static struct { 155 char *desc; 156 ObjectClass **oc; 157 } s_oc[] = { 158 /* augments an existing object, so it must be AUXILIARY 159 * FIXME: derive from some ABSTRACT "monitoredEntity"? */ 160 { "( olmMDBObjectClasses:2 " 161 "NAME ( 'olmMDBDatabase' ) " 162 "SUP top AUXILIARY " 163 "MAY ( " 164 "olmDbDirectory " 165 #ifdef MDB_MONITOR_IDX 166 "$ olmDbNotIndexed " 167 #endif /* MDB_MONITOR_IDX */ 168 "$ olmMDBPagesMax $ olmMDBPagesUsed $ olmMDBPagesFree " 169 "$ olmMDBReadersMax $ olmMDBReadersUsed $ olmMDBEntries " 170 ") )", 171 &oc_olmMDBDatabase }, 172 173 { NULL } 174 }; 175 176 static int 177 mdb_monitor_update( 178 Operation *op, 179 SlapReply *rs, 180 Entry *e, 181 void *priv ) 182 { 183 struct mdb_info *mdb = (struct mdb_info *) priv; 184 Attribute *a; 185 char buf[ BUFSIZ ]; 186 struct berval bv; 187 MDB_stat mst; 188 MDB_envinfo mei; 189 MDB_txn *txn; 190 int rc; 191 192 #ifdef MDB_MONITOR_IDX 193 194 mdb_monitor_idx_entry_add( mdb, e ); 195 #endif /* MDB_MONITOR_IDX */ 196 197 mdb_env_stat( mdb->mi_dbenv, &mst ); 198 mdb_env_info( mdb->mi_dbenv, &mei ); 199 200 a = attr_find( e->e_attrs, ad_olmMDBPagesMax ); 201 assert( a != NULL ); 202 bv.bv_val = buf; 203 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", mei.me_mapsize / mst.ms_psize ); 204 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 205 206 a = attr_find( e->e_attrs, ad_olmMDBPagesUsed ); 207 assert( a != NULL ); 208 bv.bv_val = buf; 209 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", mei.me_last_pgno+1 ); 210 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 211 212 a = attr_find( e->e_attrs, ad_olmMDBReadersMax ); 213 assert( a != NULL ); 214 bv.bv_val = buf; 215 bv.bv_len = snprintf( buf, sizeof( buf ), "%u", mei.me_maxreaders ); 216 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 217 218 a = attr_find( e->e_attrs, ad_olmMDBReadersUsed ); 219 assert( a != NULL ); 220 bv.bv_val = buf; 221 bv.bv_len = snprintf( buf, sizeof( buf ), "%u", mei.me_numreaders ); 222 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 223 224 rc = mdb_txn_begin( mdb->mi_dbenv, NULL, MDB_RDONLY, &txn ); 225 if ( !rc ) { 226 MDB_cursor *cursor; 227 MDB_val key, data; 228 size_t pages = 0, *iptr; 229 230 rc = mdb_cursor_open( txn, 0, &cursor ); 231 if ( !rc ) { 232 while (( rc = mdb_cursor_get( cursor, &key, &data, MDB_NEXT )) == 0 ) { 233 iptr = data.mv_data; 234 pages += *iptr; 235 } 236 mdb_cursor_close( cursor ); 237 } 238 239 mdb_stat( txn, mdb->mi_id2entry, &mst ); 240 a = attr_find( e->e_attrs, ad_olmMDBEntries ); 241 assert( a != NULL ); 242 bv.bv_val = buf; 243 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", mst.ms_entries ); 244 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 245 246 mdb_txn_abort( txn ); 247 248 a = attr_find( e->e_attrs, ad_olmMDBPagesFree ); 249 assert( a != NULL ); 250 bv.bv_val = buf; 251 bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", pages ); 252 ber_bvreplace( &a->a_vals[ 0 ], &bv ); 253 } 254 return SLAP_CB_CONTINUE; 255 } 256 257 #if 0 /* uncomment if required */ 258 static int 259 mdb_monitor_modify( 260 Operation *op, 261 SlapReply *rs, 262 Entry *e, 263 void *priv ) 264 { 265 return SLAP_CB_CONTINUE; 266 } 267 #endif 268 269 static int 270 mdb_monitor_free( 271 Entry *e, 272 void **priv ) 273 { 274 struct berval values[ 2 ]; 275 Modification mod = { 0 }; 276 277 const char *text; 278 char textbuf[ SLAP_TEXT_BUFLEN ]; 279 280 int i, rc; 281 282 /* NOTE: if slap_shutdown != 0, priv might have already been freed */ 283 *priv = NULL; 284 285 /* Remove objectClass */ 286 mod.sm_op = LDAP_MOD_DELETE; 287 mod.sm_desc = slap_schema.si_ad_objectClass; 288 mod.sm_values = values; 289 mod.sm_numvals = 1; 290 values[ 0 ] = oc_olmMDBDatabase->soc_cname; 291 BER_BVZERO( &values[ 1 ] ); 292 293 rc = modify_delete_values( e, &mod, 1, &text, 294 textbuf, sizeof( textbuf ) ); 295 /* don't care too much about return code... */ 296 297 /* remove attrs */ 298 mod.sm_values = NULL; 299 mod.sm_numvals = 0; 300 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 301 mod.sm_desc = *s_at[ i ].ad; 302 rc = modify_delete_values( e, &mod, 1, &text, 303 textbuf, sizeof( textbuf ) ); 304 /* don't care too much about return code... */ 305 } 306 307 return SLAP_CB_CONTINUE; 308 } 309 310 /* 311 * call from within mdb_initialize() 312 */ 313 static int 314 mdb_monitor_initialize( void ) 315 { 316 int i, code; 317 ConfigArgs c; 318 char *argv[ 3 ]; 319 320 static int mdb_monitor_initialized = 0; 321 322 /* set to 0 when successfully initialized; otherwise, remember failure */ 323 static int mdb_monitor_initialized_failure = 1; 324 325 if ( mdb_monitor_initialized++ ) { 326 return mdb_monitor_initialized_failure; 327 } 328 329 if ( backend_info( "monitor" ) == NULL ) { 330 return -1; 331 } 332 333 /* register schema here */ 334 335 argv[ 0 ] = "back-mdb monitor"; 336 c.argv = argv; 337 c.argc = 3; 338 c.fname = argv[0]; 339 340 for ( i = 0; s_oid[ i ].name; i++ ) { 341 c.lineno = i; 342 argv[ 1 ] = s_oid[ i ].name; 343 argv[ 2 ] = s_oid[ i ].oid; 344 345 if ( parse_oidm( &c, 0, NULL ) != 0 ) { 346 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 347 ": unable to add " 348 "objectIdentifier \"%s=%s\"\n", 349 s_oid[ i ].name, s_oid[ i ].oid ); 350 return 2; 351 } 352 } 353 354 for ( i = 0; s_at[ i ].desc != NULL; i++ ) { 355 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 ); 356 if ( code != LDAP_SUCCESS ) { 357 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 358 ": register_at failed for attributeType (%s)\n", 359 s_at[ i ].desc ); 360 return 3; 361 362 } else { 363 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 364 } 365 } 366 367 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) { 368 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 ); 369 if ( code != LDAP_SUCCESS ) { 370 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize) 371 ": register_oc failed for objectClass (%s)\n", 372 s_oc[ i ].desc ); 373 return 4; 374 375 } else { 376 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 377 } 378 } 379 380 return ( mdb_monitor_initialized_failure = LDAP_SUCCESS ); 381 } 382 383 /* 384 * call from within mdb_db_init() 385 */ 386 int 387 mdb_monitor_db_init( BackendDB *be ) 388 { 389 #ifdef MDB_MONITOR_IDX 390 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 391 #endif /* MDB_MONITOR_IDX */ 392 393 if ( mdb_monitor_initialize() == LDAP_SUCCESS ) { 394 /* monitoring in back-mdb is on by default */ 395 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING; 396 } 397 398 #ifdef MDB_MONITOR_IDX 399 mdb->mi_idx = NULL; 400 ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex ); 401 #endif /* MDB_MONITOR_IDX */ 402 403 return 0; 404 } 405 406 /* 407 * call from within mdb_db_open() 408 */ 409 int 410 mdb_monitor_db_open( BackendDB *be ) 411 { 412 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 413 Attribute *a, *next; 414 monitor_callback_t *cb = NULL; 415 int rc = 0; 416 BackendInfo *mi; 417 monitor_extra_t *mbe; 418 419 if ( !SLAP_DBMONITORING( be ) ) { 420 return 0; 421 } 422 423 mi = backend_info( "monitor" ); 424 if ( !mi || !mi->bi_extra ) { 425 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING; 426 return 0; 427 } 428 mbe = mi->bi_extra; 429 430 /* don't bother if monitor is not configured */ 431 if ( !mbe->is_configured() ) { 432 static int warning = 0; 433 434 if ( warning++ == 0 ) { 435 Debug( LDAP_DEBUG_CONFIG, LDAP_XSTRING(mdb_monitor_db_open) 436 ": monitoring disabled; " 437 "configure monitor database to enable\n" ); 438 } 439 440 return 0; 441 } 442 443 /* alloc as many as required (plus 1 for objectClass) */ 444 a = attrs_alloc( 1 + 7 ); 445 if ( a == NULL ) { 446 rc = 1; 447 goto cleanup; 448 } 449 450 a->a_desc = slap_schema.si_ad_objectClass; 451 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 ); 452 next = a->a_next; 453 454 { 455 struct berval bv = BER_BVC( "0" ); 456 457 next->a_desc = ad_olmMDBPagesMax; 458 attr_valadd( next, &bv, NULL, 1 ); 459 next = next->a_next; 460 461 next->a_desc = ad_olmMDBPagesUsed; 462 attr_valadd( next, &bv, NULL, 1 ); 463 next = next->a_next; 464 465 next->a_desc = ad_olmMDBPagesFree; 466 attr_valadd( next, &bv, NULL, 1 ); 467 next = next->a_next; 468 469 next->a_desc = ad_olmMDBReadersMax; 470 attr_valadd( next, &bv, NULL, 1 ); 471 next = next->a_next; 472 473 next->a_desc = ad_olmMDBReadersUsed; 474 attr_valadd( next, &bv, NULL, 1 ); 475 next = next->a_next; 476 477 next->a_desc = ad_olmMDBEntries; 478 attr_valadd( next, &bv, NULL, 1 ); 479 next = next->a_next; 480 } 481 482 { 483 struct berval bv, nbv; 484 ber_len_t pathlen = 0, len = 0; 485 char path[ MAXPATHLEN ] = { '\0' }; 486 char *fname = mdb->mi_dbenv_home, 487 *ptr; 488 489 len = strlen( fname ); 490 if ( fname[ 0 ] != '/' ) { 491 /* get full path name */ 492 getcwd( path, sizeof( path ) ); 493 pathlen = strlen( path ); 494 495 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) { 496 fname += 2; 497 len -= 2; 498 } 499 } 500 501 bv.bv_len = pathlen + STRLENOF( "/" ) + len; 502 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 ); 503 if ( pathlen ) { 504 ptr = lutil_strncopy( ptr, path, pathlen ); 505 ptr[ 0 ] = '/'; 506 ptr++; 507 } 508 ptr = lutil_strncopy( ptr, fname, len ); 509 if ( ptr[ -1 ] != '/' ) { 510 ptr[ 0 ] = '/'; 511 ptr++; 512 } 513 ptr[ 0 ] = '\0'; 514 515 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL ); 516 517 next->a_desc = ad_olmDbDirectory; 518 next->a_vals = ch_calloc( sizeof( struct berval ), 2 ); 519 next->a_vals[ 0 ] = bv; 520 next->a_numvals = 1; 521 522 if ( BER_BVISNULL( &nbv ) ) { 523 next->a_nvals = next->a_vals; 524 525 } else { 526 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 ); 527 next->a_nvals[ 0 ] = nbv; 528 } 529 530 next = next->a_next; 531 } 532 533 cb = ch_calloc( sizeof( monitor_callback_t ), 1 ); 534 cb->mc_update = mdb_monitor_update; 535 #if 0 /* uncomment if required */ 536 cb->mc_modify = mdb_monitor_modify; 537 #endif 538 cb->mc_free = mdb_monitor_free; 539 cb->mc_private = (void *)mdb; 540 541 /* make sure the database is registered; then add monitor attributes */ 542 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn ); 543 if ( rc == 0 ) { 544 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb, 545 NULL, -1, NULL ); 546 } 547 548 cleanup:; 549 if ( rc != 0 ) { 550 if ( cb != NULL ) { 551 ch_free( cb ); 552 cb = NULL; 553 } 554 555 if ( a != NULL ) { 556 attrs_free( a ); 557 a = NULL; 558 } 559 } 560 561 /* store for cleanup */ 562 mdb->mi_monitor.mdm_cb = (void *)cb; 563 564 /* we don't need to keep track of the attributes, because 565 * mdb_monitor_free() takes care of everything */ 566 if ( a != NULL ) { 567 attrs_free( a ); 568 } 569 570 return rc; 571 } 572 573 /* 574 * call from within mdb_db_close() 575 */ 576 int 577 mdb_monitor_db_close( BackendDB *be ) 578 { 579 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 580 581 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) { 582 BackendInfo *mi = backend_info( "monitor" ); 583 monitor_extra_t *mbe; 584 585 if ( mi && mi->bi_extra ) { 586 mbe = mi->bi_extra; 587 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn, 588 (monitor_callback_t *)mdb->mi_monitor.mdm_cb, 589 NULL, 0, NULL ); 590 } 591 592 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) ); 593 } 594 595 return 0; 596 } 597 598 /* 599 * call from within mdb_db_destroy() 600 */ 601 int 602 mdb_monitor_db_destroy( BackendDB *be ) 603 { 604 #ifdef MDB_MONITOR_IDX 605 struct mdb_info *mdb = (struct mdb_info *) be->be_private; 606 607 /* TODO: free tree */ 608 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex ); 609 ldap_avl_free( mdb->mi_idx, ch_free ); 610 #endif /* MDB_MONITOR_IDX */ 611 612 return 0; 613 } 614 615 #ifdef MDB_MONITOR_IDX 616 617 #define MDB_MONITOR_IDX_TYPES (4) 618 619 typedef struct monitor_idx_t monitor_idx_t; 620 621 struct monitor_idx_t { 622 AttributeDescription *idx_ad; 623 unsigned long idx_count[MDB_MONITOR_IDX_TYPES]; 624 }; 625 626 static int 627 mdb_monitor_bitmask2key( slap_mask_t bitmask ) 628 { 629 int key; 630 631 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U ); 632 key++ ) 633 bitmask >>= 1; 634 635 return key; 636 } 637 638 static struct berval idxbv[] = { 639 BER_BVC( "present=" ), 640 BER_BVC( "equality=" ), 641 BER_BVC( "approx=" ), 642 BER_BVC( "substr=" ), 643 BER_BVNULL 644 }; 645 646 static ber_len_t 647 mdb_monitor_idx2len( monitor_idx_t *idx ) 648 { 649 int i; 650 ber_len_t len = 0; 651 652 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 653 if ( idx->idx_count[ i ] != 0 ) { 654 len += idxbv[i].bv_len; 655 } 656 } 657 658 return len; 659 } 660 661 static int 662 monitor_idx_cmp( const void *p1, const void *p2 ) 663 { 664 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1; 665 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2; 666 667 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ); 668 } 669 670 static int 671 monitor_idx_dup( void *p1, void *p2 ) 672 { 673 monitor_idx_t *idx1 = (monitor_idx_t *)p1; 674 monitor_idx_t *idx2 = (monitor_idx_t *)p2; 675 676 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0; 677 } 678 679 int 680 mdb_monitor_idx_add( 681 struct mdb_info *mdb, 682 AttributeDescription *desc, 683 slap_mask_t type ) 684 { 685 monitor_idx_t idx_dummy = { 0 }, 686 *idx; 687 int rc = 0, key; 688 689 idx_dummy.idx_ad = desc; 690 key = mdb_monitor_bitmask2key( type ) - 1; 691 if ( key >= MDB_MONITOR_IDX_TYPES ) { 692 /* invalid index type */ 693 return -1; 694 } 695 696 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex ); 697 698 idx = (monitor_idx_t *)ldap_avl_find( mdb->mi_idx, 699 (caddr_t)&idx_dummy, monitor_idx_cmp ); 700 if ( idx == NULL ) { 701 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 ); 702 idx->idx_ad = desc; 703 idx->idx_count[ key ] = 1; 704 705 switch ( ldap_avl_insert( &mdb->mi_idx, (caddr_t)idx, 706 monitor_idx_cmp, monitor_idx_dup ) ) 707 { 708 case 0: 709 break; 710 711 default: 712 ch_free( idx ); 713 rc = -1; 714 } 715 716 } else { 717 idx->idx_count[ key ]++; 718 } 719 720 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex ); 721 722 return rc; 723 } 724 725 static int 726 mdb_monitor_idx_apply( void *v_idx, void *v_valp ) 727 { 728 monitor_idx_t *idx = (monitor_idx_t *)v_idx; 729 BerVarray *valp = (BerVarray *)v_valp; 730 731 struct berval bv; 732 char *ptr; 733 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ]; 734 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ], 735 idx_len; 736 int i, num = 0; 737 738 idx_len = mdb_monitor_idx2len( idx ); 739 740 bv.bv_len = 0; 741 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 742 if ( idx->idx_count[ i ] == 0 ) { 743 continue; 744 } 745 746 count_len[ i ] = snprintf( count_buf[ i ], 747 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] ); 748 bv.bv_len += count_len[ i ]; 749 num++; 750 } 751 752 bv.bv_len += idx->idx_ad->ad_cname.bv_len 753 + num 754 + idx_len; 755 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); 756 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val ); 757 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) { 758 if ( idx->idx_count[ i ] == 0 ) { 759 continue; 760 } 761 762 ptr[ 0 ] = '#'; 763 ++ptr; 764 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val ); 765 ptr = lutil_strcopy( ptr, count_buf[ i ] ); 766 } 767 768 ber_bvarray_add( valp, &bv ); 769 770 return 0; 771 } 772 773 static int 774 mdb_monitor_idx_entry_add( 775 struct mdb_info *mdb, 776 Entry *e ) 777 { 778 BerVarray vals = NULL; 779 Attribute *a; 780 781 a = attr_find( e->e_attrs, ad_olmDbNotIndexed ); 782 783 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex ); 784 785 ldap_avl_apply( mdb->mi_idx, mdb_monitor_idx_apply, 786 &vals, -1, AVL_INORDER ); 787 788 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex ); 789 790 if ( vals != NULL ) { 791 if ( a != NULL ) { 792 assert( a->a_nvals == a->a_vals ); 793 794 ber_bvarray_free( a->a_vals ); 795 796 } else { 797 Attribute **ap; 798 799 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next ) 800 ; 801 *ap = attr_alloc( ad_olmDbNotIndexed ); 802 a = *ap; 803 } 804 a->a_vals = vals; 805 a->a_nvals = a->a_vals; 806 } 807 808 return 0; 809 } 810 811 #endif /* MDB_MONITOR_IDX */ 812