1 /* monitor.c - monitor mdb backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2013 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>
21 #include <ac/unistd.h>
22 #include <ac/stdlib.h>
28 #include "../back-monitor/back-monitor.h"
32 static ObjectClass *oc_olmMDBDatabase;
34 static AttributeDescription *ad_olmDbDirectory;
36 #ifdef MDB_MONITOR_IDX
38 mdb_monitor_idx_entry_add(
42 static AttributeDescription *ad_olmDbNotIndexed;
43 #endif /* MDB_MONITOR_IDX */
46 * NOTE: there's some confusion in monitor OID arc;
47 * by now, let's consider:
49 * Subsystems monitor attributes 1.3.6.1.4.1.4203.666.1.55.0
50 * Databases monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1
51 * MDB database monitor attributes 1.3.6.1.4.1.4203.666.1.55.0.1.3
53 * Subsystems monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0
54 * Databases monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1
55 * MDB database monitor objectclasses 1.3.6.1.4.1.4203.666.3.16.0.1.3
62 { "olmMDBAttributes", "olmDatabaseAttributes:1" },
63 { "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" },
70 AttributeDescription **ad;
72 { "( olmDatabaseAttributes:1 "
73 "NAME ( 'olmDbDirectory' ) "
74 "DESC 'Path name of the directory "
75 "where the database environment resides' "
77 "NO-USER-MODIFICATION "
78 "USAGE dSAOperation )",
81 #ifdef MDB_MONITOR_IDX
82 { "( olmDatabaseAttributes:2 "
83 "NAME ( 'olmDbNotIndexed' ) "
84 "DESC 'Missing indexes resulting from candidate selection' "
86 "NO-USER-MODIFICATION "
87 "USAGE dSAOperation )",
88 &ad_olmDbNotIndexed },
89 #endif /* MDB_MONITOR_IDX */
98 /* augments an existing object, so it must be AUXILIARY
99 * FIXME: derive from some ABSTRACT "monitoredEntity"? */
100 { "( olmMDBObjectClasses:2 "
101 "NAME ( 'olmMDBDatabase' ) "
105 #ifdef MDB_MONITOR_IDX
107 #endif /* MDB_MONITOR_IDX */
109 &oc_olmMDBDatabase },
121 struct mdb_info *mdb = (struct mdb_info *) priv;
123 #ifdef MDB_MONITOR_IDX
124 mdb_monitor_idx_entry_add( mdb, e );
125 #endif /* MDB_MONITOR_IDX */
127 return SLAP_CB_CONTINUE;
130 #if 0 /* uncomment if required */
138 return SLAP_CB_CONTINUE;
147 struct berval values[ 2 ];
148 Modification mod = { 0 };
151 char textbuf[ SLAP_TEXT_BUFLEN ];
155 /* NOTE: if slap_shutdown != 0, priv might have already been freed */
158 /* Remove objectClass */
159 mod.sm_op = LDAP_MOD_DELETE;
160 mod.sm_desc = slap_schema.si_ad_objectClass;
161 mod.sm_values = values;
163 values[ 0 ] = oc_olmMDBDatabase->soc_cname;
164 BER_BVZERO( &values[ 1 ] );
166 rc = modify_delete_values( e, &mod, 1, &text,
167 textbuf, sizeof( textbuf ) );
168 /* don't care too much about return code... */
171 mod.sm_values = NULL;
173 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
174 mod.sm_desc = *s_at[ i ].ad;
175 rc = modify_delete_values( e, &mod, 1, &text,
176 textbuf, sizeof( textbuf ) );
177 /* don't care too much about return code... */
180 return SLAP_CB_CONTINUE;
184 * call from within mdb_initialize()
187 mdb_monitor_initialize( void )
193 static int mdb_monitor_initialized = 0;
195 /* set to 0 when successfully initialized; otherwise, remember failure */
196 static int mdb_monitor_initialized_failure = 1;
198 if ( mdb_monitor_initialized++ ) {
199 return mdb_monitor_initialized_failure;
202 if ( backend_info( "monitor" ) == NULL ) {
206 /* register schema here */
208 argv[ 0 ] = "back-mdb monitor";
213 for ( i = 0; s_oid[ i ].name; i++ ) {
215 argv[ 1 ] = s_oid[ i ].name;
216 argv[ 2 ] = s_oid[ i ].oid;
218 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
219 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
221 "objectIdentifier \"%s=%s\"\n",
222 s_oid[ i ].name, s_oid[ i ].oid, 0 );
227 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
228 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
229 if ( code != LDAP_SUCCESS ) {
230 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
231 ": register_at failed for attributeType (%s)\n",
232 s_at[ i ].desc, 0, 0 );
236 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
240 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
241 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
242 if ( code != LDAP_SUCCESS ) {
243 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
244 ": register_oc failed for objectClass (%s)\n",
245 s_oc[ i ].desc, 0, 0 );
249 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
253 return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
257 * call from within mdb_db_init()
260 mdb_monitor_db_init( BackendDB *be )
262 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
264 if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
265 /* monitoring in back-mdb is on by default */
266 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
269 #ifdef MDB_MONITOR_IDX
271 ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
272 #endif /* MDB_MONITOR_IDX */
278 * call from within mdb_db_open()
281 mdb_monitor_db_open( BackendDB *be )
283 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
285 monitor_callback_t *cb = NULL;
288 monitor_extra_t *mbe;
290 if ( !SLAP_DBMONITORING( be ) ) {
294 mi = backend_info( "monitor" );
295 if ( !mi || !mi->bi_extra ) {
296 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
301 /* don't bother if monitor is not configured */
302 if ( !mbe->is_configured() ) {
303 static int warning = 0;
305 if ( warning++ == 0 ) {
306 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
307 ": monitoring disabled; "
308 "configure monitor database to enable\n",
315 /* alloc as many as required (plus 1 for objectClass) */
316 a = attrs_alloc( 1 + 1 );
322 a->a_desc = slap_schema.si_ad_objectClass;
323 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
327 struct berval bv, nbv;
328 ber_len_t pathlen = 0, len = 0;
329 char path[ MAXPATHLEN ] = { '\0' };
330 char *fname = mdb->mi_dbenv_home,
333 len = strlen( fname );
334 if ( fname[ 0 ] != '/' ) {
335 /* get full path name */
336 getcwd( path, sizeof( path ) );
337 pathlen = strlen( path );
339 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
345 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
346 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
348 ptr = lutil_strncopy( ptr, path, pathlen );
352 ptr = lutil_strncopy( ptr, fname, len );
353 if ( ptr[ -1 ] != '/' ) {
359 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
361 next->a_desc = ad_olmDbDirectory;
362 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
363 next->a_vals[ 0 ] = bv;
366 if ( BER_BVISNULL( &nbv ) ) {
367 next->a_nvals = next->a_vals;
370 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
371 next->a_nvals[ 0 ] = nbv;
377 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
378 cb->mc_update = mdb_monitor_update;
379 #if 0 /* uncomment if required */
380 cb->mc_modify = mdb_monitor_modify;
382 cb->mc_free = mdb_monitor_free;
383 cb->mc_private = (void *)mdb;
385 /* make sure the database is registered; then add monitor attributes */
386 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
388 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
405 /* store for cleanup */
406 mdb->mi_monitor.mdm_cb = (void *)cb;
408 /* we don't need to keep track of the attributes, because
409 * mdb_monitor_free() takes care of everything */
418 * call from within mdb_db_close()
421 mdb_monitor_db_close( BackendDB *be )
423 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
425 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
426 BackendInfo *mi = backend_info( "monitor" );
427 monitor_extra_t *mbe;
429 if ( mi && &mi->bi_extra ) {
431 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
432 (monitor_callback_t *)mdb->mi_monitor.mdm_cb,
436 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
443 * call from within mdb_db_destroy()
446 mdb_monitor_db_destroy( BackendDB *be )
448 #ifdef MDB_MONITOR_IDX
449 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
451 /* TODO: free tree */
452 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
453 avl_free( mdb->mi_idx, ch_free );
454 #endif /* MDB_MONITOR_IDX */
459 #ifdef MDB_MONITOR_IDX
461 #define MDB_MONITOR_IDX_TYPES (4)
463 typedef struct monitor_idx_t monitor_idx_t;
465 struct monitor_idx_t {
466 AttributeDescription *idx_ad;
467 unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
471 mdb_monitor_bitmask2key( slap_mask_t bitmask )
475 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
482 static struct berval idxbv[] = {
483 BER_BVC( "present=" ),
484 BER_BVC( "equality=" ),
485 BER_BVC( "approx=" ),
486 BER_BVC( "substr=" ),
491 mdb_monitor_idx2len( monitor_idx_t *idx )
496 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
497 if ( idx->idx_count[ i ] != 0 ) {
498 len += idxbv[i].bv_len;
506 monitor_idx_cmp( const void *p1, const void *p2 )
508 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
509 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
511 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
515 monitor_idx_dup( void *p1, void *p2 )
517 monitor_idx_t *idx1 = (monitor_idx_t *)p1;
518 monitor_idx_t *idx2 = (monitor_idx_t *)p2;
520 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
525 struct mdb_info *mdb,
526 AttributeDescription *desc,
529 monitor_idx_t idx_dummy = { 0 },
533 idx_dummy.idx_ad = desc;
534 key = mdb_monitor_bitmask2key( type ) - 1;
535 if ( key >= MDB_MONITOR_IDX_TYPES ) {
536 /* invalid index type */
540 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
542 idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
543 (caddr_t)&idx_dummy, monitor_idx_cmp );
545 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
547 idx->idx_count[ key ] = 1;
549 switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
550 monitor_idx_cmp, monitor_idx_dup ) )
561 idx->idx_count[ key ]++;
564 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
570 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
572 monitor_idx_t *idx = (monitor_idx_t *)v_idx;
573 BerVarray *valp = (BerVarray *)v_valp;
577 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
578 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
582 idx_len = mdb_monitor_idx2len( idx );
585 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
586 if ( idx->idx_count[ i ] == 0 ) {
590 count_len[ i ] = snprintf( count_buf[ i ],
591 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
592 bv.bv_len += count_len[ i ];
596 bv.bv_len += idx->idx_ad->ad_cname.bv_len
599 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
600 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
601 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
602 if ( idx->idx_count[ i ] == 0 ) {
608 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
609 ptr = lutil_strcopy( ptr, count_buf[ i ] );
612 ber_bvarray_add( valp, &bv );
618 mdb_monitor_idx_entry_add(
619 struct mdb_info *mdb,
622 BerVarray vals = NULL;
625 a = attr_find( e->e_attrs, ad_olmDbNotIndexed );
627 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
629 avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
630 &vals, -1, AVL_INORDER );
632 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
634 if ( vals != NULL ) {
636 assert( a->a_nvals == a->a_vals );
638 ber_bvarray_free( a->a_vals );
643 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
645 *ap = attr_alloc( ad_olmDbNotIndexed );
649 a->a_nvals = a->a_vals;
655 #endif /* MDB_MONITOR_IDX */