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
mdb_monitor_update(Operation * op,SlapReply * rs,Entry * e,void * priv)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
mdb_monitor_free(Entry * e,void ** priv)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
mdb_monitor_initialize(void)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
mdb_monitor_db_init(BackendDB * be)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
mdb_monitor_db_open(BackendDB * be)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
mdb_monitor_db_close(BackendDB * be)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
mdb_monitor_db_destroy(BackendDB * be)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
mdb_monitor_bitmask2key(slap_mask_t bitmask)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
mdb_monitor_idx2len(monitor_idx_t * idx)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
monitor_idx_cmp(const void * p1,const void * p2)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
monitor_idx_dup(void * p1,void * p2)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
mdb_monitor_idx_add(struct mdb_info * mdb,AttributeDescription * desc,slap_mask_t type)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
mdb_monitor_idx_apply(void * v_idx,void * v_valp)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
mdb_monitor_idx_entry_add(struct mdb_info * mdb,Entry * e)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