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;
127 #ifdef MDB_MONITOR_IDX
128 mdb_monitor_idx_entry_add( mdb, e );
129 #endif /* MDB_MONITOR_IDX */
131 return SLAP_CB_CONTINUE;
134 #if 0 /* uncomment if required */
142 return SLAP_CB_CONTINUE;
151 struct berval values[ 2 ];
152 Modification mod = { 0 };
155 char textbuf[ SLAP_TEXT_BUFLEN ];
159 /* NOTE: if slap_shutdown != 0, priv might have already been freed */
162 /* Remove objectClass */
163 mod.sm_op = LDAP_MOD_DELETE;
164 mod.sm_desc = slap_schema.si_ad_objectClass;
165 mod.sm_values = values;
167 values[ 0 ] = oc_olmMDBDatabase->soc_cname;
168 BER_BVZERO( &values[ 1 ] );
170 rc = modify_delete_values( e, &mod, 1, &text,
171 textbuf, sizeof( textbuf ) );
172 /* don't care too much about return code... */
175 mod.sm_values = NULL;
177 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
178 mod.sm_desc = *s_at[ i ].ad;
179 rc = modify_delete_values( e, &mod, 1, &text,
180 textbuf, sizeof( textbuf ) );
181 /* don't care too much about return code... */
184 return SLAP_CB_CONTINUE;
188 * call from within mdb_initialize()
191 mdb_monitor_initialize( void )
197 static int mdb_monitor_initialized = 0;
199 /* set to 0 when successfully initialized; otherwise, remember failure */
200 static int mdb_monitor_initialized_failure = 1;
202 if ( mdb_monitor_initialized++ ) {
203 return mdb_monitor_initialized_failure;
206 if ( backend_info( "monitor" ) == NULL ) {
210 /* register schema here */
212 argv[ 0 ] = "back-mdb monitor";
217 for ( i = 0; s_oid[ i ].name; i++ ) {
219 argv[ 1 ] = s_oid[ i ].name;
220 argv[ 2 ] = s_oid[ i ].oid;
222 if ( parse_oidm( &c, 0, NULL ) != 0 ) {
223 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
225 "objectIdentifier \"%s=%s\"\n",
226 s_oid[ i ].name, s_oid[ i ].oid, 0 );
231 for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
232 code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
233 if ( code != LDAP_SUCCESS ) {
234 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
235 ": register_at failed for attributeType (%s)\n",
236 s_at[ i ].desc, 0, 0 );
240 (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
244 for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
245 code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
246 if ( code != LDAP_SUCCESS ) {
247 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_initialize)
248 ": register_oc failed for objectClass (%s)\n",
249 s_oc[ i ].desc, 0, 0 );
253 (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
257 return ( mdb_monitor_initialized_failure = LDAP_SUCCESS );
261 * call from within mdb_db_init()
264 mdb_monitor_db_init( BackendDB *be )
266 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
268 if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
269 /* monitoring in back-mdb is on by default */
270 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
273 #ifdef MDB_MONITOR_IDX
275 ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
276 #endif /* MDB_MONITOR_IDX */
282 * call from within mdb_db_open()
285 mdb_monitor_db_open( BackendDB *be )
287 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
289 monitor_callback_t *cb = NULL;
292 monitor_extra_t *mbe;
293 struct berval dummy = BER_BVC("");
295 if ( !SLAP_DBMONITORING( be ) ) {
299 mi = backend_info( "monitor" );
300 if ( !mi || !mi->bi_extra ) {
301 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
306 /* don't bother if monitor is not configured */
307 if ( !mbe->is_configured() ) {
308 static int warning = 0;
310 if ( warning++ == 0 ) {
311 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
312 ": monitoring disabled; "
313 "configure monitor database to enable\n",
320 /* alloc as many as required (plus 1 for objectClass) */
321 a = attrs_alloc( 1 + 1 );
327 a->a_desc = slap_schema.si_ad_objectClass;
328 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
332 struct berval bv, nbv;
333 ber_len_t pathlen = 0, len = 0;
334 char path[ MAXPATHLEN ] = { '\0' };
335 char *fname = mdb->mi_dbenv_home,
338 len = strlen( fname );
339 if ( fname[ 0 ] != '/' ) {
340 /* get full path name */
341 getcwd( path, sizeof( path ) );
342 pathlen = strlen( path );
344 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
350 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
351 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
353 ptr = lutil_strncopy( ptr, path, pathlen );
357 ptr = lutil_strncopy( ptr, fname, len );
358 if ( ptr[ -1 ] != '/' ) {
364 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
366 next->a_desc = ad_olmDbDirectory;
367 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
368 next->a_vals[ 0 ] = bv;
371 if ( BER_BVISNULL( &nbv ) ) {
372 next->a_nvals = next->a_vals;
375 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
376 next->a_nvals[ 0 ] = nbv;
382 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
383 cb->mc_update = mdb_monitor_update;
384 #if 0 /* uncomment if required */
385 cb->mc_modify = mdb_monitor_modify;
387 cb->mc_free = mdb_monitor_free;
388 cb->mc_private = (void *)mdb;
390 /* make sure the database is registered; then add monitor attributes */
391 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
393 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
410 /* store for cleanup */
411 mdb->mi_monitor.mdm_cb = (void *)cb;
413 /* we don't need to keep track of the attributes, because
414 * mdb_monitor_free() takes care of everything */
423 * call from within mdb_db_close()
426 mdb_monitor_db_close( BackendDB *be )
428 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
430 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
431 BackendInfo *mi = backend_info( "monitor" );
432 monitor_extra_t *mbe;
434 if ( mi && &mi->bi_extra ) {
436 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
437 (monitor_callback_t *)mdb->mi_monitor.mdm_cb,
441 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
448 * call from within mdb_db_destroy()
451 mdb_monitor_db_destroy( BackendDB *be )
453 #ifdef MDB_MONITOR_IDX
454 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
456 /* TODO: free tree */
457 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
458 avl_free( mdb->mi_idx, ch_free );
459 #endif /* MDB_MONITOR_IDX */
464 #ifdef MDB_MONITOR_IDX
466 #define MDB_MONITOR_IDX_TYPES (4)
468 typedef struct monitor_idx_t monitor_idx_t;
470 struct monitor_idx_t {
471 AttributeDescription *idx_ad;
472 unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
476 mdb_monitor_bitmask2key( slap_mask_t bitmask )
480 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
487 static struct berval idxbv[] = {
488 BER_BVC( "present=" ),
489 BER_BVC( "equality=" ),
490 BER_BVC( "approx=" ),
491 BER_BVC( "substr=" ),
496 mdb_monitor_idx2len( monitor_idx_t *idx )
501 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
502 if ( idx->idx_count[ i ] != 0 ) {
503 len += idxbv[i].bv_len;
511 monitor_idx_cmp( const void *p1, const void *p2 )
513 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
514 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
516 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
520 monitor_idx_dup( void *p1, void *p2 )
522 monitor_idx_t *idx1 = (monitor_idx_t *)p1;
523 monitor_idx_t *idx2 = (monitor_idx_t *)p2;
525 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
530 struct mdb_info *mdb,
531 AttributeDescription *desc,
534 monitor_idx_t idx_dummy = { 0 },
538 idx_dummy.idx_ad = desc;
539 key = mdb_monitor_bitmask2key( type ) - 1;
540 if ( key >= MDB_MONITOR_IDX_TYPES ) {
541 /* invalid index type */
545 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
547 idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
548 (caddr_t)&idx_dummy, monitor_idx_cmp );
550 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
552 idx->idx_count[ key ] = 1;
554 switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
555 monitor_idx_cmp, monitor_idx_dup ) )
566 idx->idx_count[ key ]++;
569 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
575 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
577 monitor_idx_t *idx = (monitor_idx_t *)v_idx;
578 BerVarray *valp = (BerVarray *)v_valp;
582 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
583 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
587 idx_len = mdb_monitor_idx2len( idx );
590 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
591 if ( idx->idx_count[ i ] == 0 ) {
595 count_len[ i ] = snprintf( count_buf[ i ],
596 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
597 bv.bv_len += count_len[ i ];
601 bv.bv_len += idx->idx_ad->ad_cname.bv_len
604 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
605 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
606 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
607 if ( idx->idx_count[ i ] == 0 ) {
613 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
614 ptr = lutil_strcopy( ptr, count_buf[ i ] );
617 ber_bvarray_add( valp, &bv );
623 mdb_monitor_idx_entry_add(
624 struct mdb_info *mdb,
627 BerVarray vals = NULL;
630 a = attr_find( e->e_attrs, ad_olmMDBNotIndexed );
632 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
634 avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
635 &vals, -1, AVL_INORDER );
637 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
639 if ( vals != NULL ) {
641 assert( a->a_nvals == a->a_vals );
643 ber_bvarray_free( a->a_vals );
648 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
650 *ap = attr_alloc( ad_olmMDBNotIndexed );
654 a->a_nvals = a->a_vals;
660 #endif /* MDB_MONITOR_IDX */