1 /* monitor.c - monitor mdb backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2011 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_olmMDBNotIndexed;
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.1
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.1
62 { "olmMDBAttributes", "olmDatabaseAttributes:1" },
63 { "olmMDBObjectClasses", "olmDatabaseObjectClasses:1" },
70 AttributeDescription **ad;
72 { "( olmMDBAttributes:4 "
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 { "( olmMDBAttributes:5 "
83 "NAME ( 'olmMDBNotIndexed' ) "
84 "DESC 'Missing indexes resulting from candidate selection' "
86 "NO-USER-MODIFICATION "
87 "USAGE dSAOperation )",
88 &ad_olmMDBNotIndexed },
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
106 "$ olmMDBNotIndexed "
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;
289 struct berval dummy = BER_BVC("");
291 if ( !SLAP_DBMONITORING( be ) ) {
295 mi = backend_info( "monitor" );
296 if ( !mi || !mi->bi_extra ) {
297 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
302 /* don't bother if monitor is not configured */
303 if ( !mbe->is_configured() ) {
304 static int warning = 0;
306 if ( warning++ == 0 ) {
307 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
308 ": monitoring disabled; "
309 "configure monitor database to enable\n",
316 /* alloc as many as required (plus 1 for objectClass) */
317 a = attrs_alloc( 1 + 1 );
323 a->a_desc = slap_schema.si_ad_objectClass;
324 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
328 struct berval bv, nbv;
329 ber_len_t pathlen = 0, len = 0;
330 char path[ MAXPATHLEN ] = { '\0' };
331 char *fname = mdb->mi_dbenv_home,
334 len = strlen( fname );
335 if ( fname[ 0 ] != '/' ) {
336 /* get full path name */
337 getcwd( path, sizeof( path ) );
338 pathlen = strlen( path );
340 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
346 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
347 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
349 ptr = lutil_strncopy( ptr, path, pathlen );
353 ptr = lutil_strncopy( ptr, fname, len );
354 if ( ptr[ -1 ] != '/' ) {
360 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
362 next->a_desc = ad_olmDbDirectory;
363 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
364 next->a_vals[ 0 ] = bv;
367 if ( BER_BVISNULL( &nbv ) ) {
368 next->a_nvals = next->a_vals;
371 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
372 next->a_nvals[ 0 ] = nbv;
378 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
379 cb->mc_update = mdb_monitor_update;
380 #if 0 /* uncomment if required */
381 cb->mc_modify = mdb_monitor_modify;
383 cb->mc_free = mdb_monitor_free;
384 cb->mc_private = (void *)mdb;
386 /* make sure the database is registered; then add monitor attributes */
387 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
389 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
406 /* store for cleanup */
407 mdb->mi_monitor.mdm_cb = (void *)cb;
409 /* we don't need to keep track of the attributes, because
410 * mdb_monitor_free() takes care of everything */
419 * call from within mdb_db_close()
422 mdb_monitor_db_close( BackendDB *be )
424 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
426 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
427 BackendInfo *mi = backend_info( "monitor" );
428 monitor_extra_t *mbe;
430 if ( mi && &mi->bi_extra ) {
432 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
433 (monitor_callback_t *)mdb->mi_monitor.mdm_cb,
437 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
444 * call from within mdb_db_destroy()
447 mdb_monitor_db_destroy( BackendDB *be )
449 #ifdef MDB_MONITOR_IDX
450 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
452 /* TODO: free tree */
453 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
454 avl_free( mdb->mi_idx, ch_free );
455 #endif /* MDB_MONITOR_IDX */
460 #ifdef MDB_MONITOR_IDX
462 #define MDB_MONITOR_IDX_TYPES (4)
464 typedef struct monitor_idx_t monitor_idx_t;
466 struct monitor_idx_t {
467 AttributeDescription *idx_ad;
468 unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
472 mdb_monitor_bitmask2key( slap_mask_t bitmask )
476 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
483 static struct berval idxbv[] = {
484 BER_BVC( "present=" ),
485 BER_BVC( "equality=" ),
486 BER_BVC( "approx=" ),
487 BER_BVC( "substr=" ),
492 mdb_monitor_idx2len( monitor_idx_t *idx )
497 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
498 if ( idx->idx_count[ i ] != 0 ) {
499 len += idxbv[i].bv_len;
507 monitor_idx_cmp( const void *p1, const void *p2 )
509 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
510 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
512 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
516 monitor_idx_dup( void *p1, void *p2 )
518 monitor_idx_t *idx1 = (monitor_idx_t *)p1;
519 monitor_idx_t *idx2 = (monitor_idx_t *)p2;
521 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
526 struct mdb_info *mdb,
527 AttributeDescription *desc,
530 monitor_idx_t idx_dummy = { 0 },
534 idx_dummy.idx_ad = desc;
535 key = mdb_monitor_bitmask2key( type ) - 1;
536 if ( key >= MDB_MONITOR_IDX_TYPES ) {
537 /* invalid index type */
541 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
543 idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
544 (caddr_t)&idx_dummy, monitor_idx_cmp );
546 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
548 idx->idx_count[ key ] = 1;
550 switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
551 monitor_idx_cmp, monitor_idx_dup ) )
562 idx->idx_count[ key ]++;
565 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
571 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
573 monitor_idx_t *idx = (monitor_idx_t *)v_idx;
574 BerVarray *valp = (BerVarray *)v_valp;
578 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
579 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
583 idx_len = mdb_monitor_idx2len( idx );
586 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
587 if ( idx->idx_count[ i ] == 0 ) {
591 count_len[ i ] = snprintf( count_buf[ i ],
592 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
593 bv.bv_len += count_len[ i ];
597 bv.bv_len += idx->idx_ad->ad_cname.bv_len
600 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
601 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
602 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
603 if ( idx->idx_count[ i ] == 0 ) {
609 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
610 ptr = lutil_strcopy( ptr, count_buf[ i ] );
613 ber_bvarray_add( valp, &bv );
619 mdb_monitor_idx_entry_add(
620 struct mdb_info *mdb,
623 BerVarray vals = NULL;
626 a = attr_find( e->e_attrs, ad_olmMDBNotIndexed );
628 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
630 avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
631 &vals, -1, AVL_INORDER );
633 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
635 if ( vals != NULL ) {
637 assert( a->a_nvals == a->a_vals );
639 ber_bvarray_free( a->a_vals );
644 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
646 *ap = attr_alloc( ad_olmMDBNotIndexed );
650 a->a_nvals = a->a_vals;
656 #endif /* MDB_MONITOR_IDX */