1 /* monitor.c - monitor mdb backend */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2000-2018 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 #ifdef MDB_MONITOR_IDX
122 struct mdb_info *mdb = (struct mdb_info *) priv;
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 #ifdef MDB_MONITOR_IDX
263 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
264 #endif /* MDB_MONITOR_IDX */
266 if ( mdb_monitor_initialize() == LDAP_SUCCESS ) {
267 /* monitoring in back-mdb is on by default */
268 SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
271 #ifdef MDB_MONITOR_IDX
273 ldap_pvt_thread_mutex_init( &mdb->mi_idx_mutex );
274 #endif /* MDB_MONITOR_IDX */
280 * call from within mdb_db_open()
283 mdb_monitor_db_open( BackendDB *be )
285 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
287 monitor_callback_t *cb = NULL;
290 monitor_extra_t *mbe;
292 if ( !SLAP_DBMONITORING( be ) ) {
296 mi = backend_info( "monitor" );
297 if ( !mi || !mi->bi_extra ) {
298 SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
303 /* don't bother if monitor is not configured */
304 if ( !mbe->is_configured() ) {
305 static int warning = 0;
307 if ( warning++ == 0 ) {
308 Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(mdb_monitor_db_open)
309 ": monitoring disabled; "
310 "configure monitor database to enable\n",
317 /* alloc as many as required (plus 1 for objectClass) */
318 a = attrs_alloc( 1 + 1 );
324 a->a_desc = slap_schema.si_ad_objectClass;
325 attr_valadd( a, &oc_olmMDBDatabase->soc_cname, NULL, 1 );
329 struct berval bv, nbv;
330 ber_len_t pathlen = 0, len = 0;
331 char path[ MAXPATHLEN ] = { '\0' };
332 char *fname = mdb->mi_dbenv_home,
335 len = strlen( fname );
336 if ( fname[ 0 ] != '/' ) {
337 /* get full path name */
338 getcwd( path, sizeof( path ) );
339 pathlen = strlen( path );
341 if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
347 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
348 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
350 ptr = lutil_strncopy( ptr, path, pathlen );
354 ptr = lutil_strncopy( ptr, fname, len );
355 if ( ptr[ -1 ] != '/' ) {
361 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
363 next->a_desc = ad_olmDbDirectory;
364 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
365 next->a_vals[ 0 ] = bv;
368 if ( BER_BVISNULL( &nbv ) ) {
369 next->a_nvals = next->a_vals;
372 next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
373 next->a_nvals[ 0 ] = nbv;
379 cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
380 cb->mc_update = mdb_monitor_update;
381 #if 0 /* uncomment if required */
382 cb->mc_modify = mdb_monitor_modify;
384 cb->mc_free = mdb_monitor_free;
385 cb->mc_private = (void *)mdb;
387 /* make sure the database is registered; then add monitor attributes */
388 rc = mbe->register_database( be, &mdb->mi_monitor.mdm_ndn );
390 rc = mbe->register_entry_attrs( &mdb->mi_monitor.mdm_ndn, a, cb,
407 /* store for cleanup */
408 mdb->mi_monitor.mdm_cb = (void *)cb;
410 /* we don't need to keep track of the attributes, because
411 * mdb_monitor_free() takes care of everything */
420 * call from within mdb_db_close()
423 mdb_monitor_db_close( BackendDB *be )
425 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
427 if ( !BER_BVISNULL( &mdb->mi_monitor.mdm_ndn ) ) {
428 BackendInfo *mi = backend_info( "monitor" );
429 monitor_extra_t *mbe;
431 if ( mi && &mi->bi_extra ) {
433 mbe->unregister_entry_callback( &mdb->mi_monitor.mdm_ndn,
434 (monitor_callback_t *)mdb->mi_monitor.mdm_cb,
438 memset( &mdb->mi_monitor, 0, sizeof( mdb->mi_monitor ) );
445 * call from within mdb_db_destroy()
448 mdb_monitor_db_destroy( BackendDB *be )
450 #ifdef MDB_MONITOR_IDX
451 struct mdb_info *mdb = (struct mdb_info *) be->be_private;
453 /* TODO: free tree */
454 ldap_pvt_thread_mutex_destroy( &mdb->mi_idx_mutex );
455 avl_free( mdb->mi_idx, ch_free );
456 #endif /* MDB_MONITOR_IDX */
461 #ifdef MDB_MONITOR_IDX
463 #define MDB_MONITOR_IDX_TYPES (4)
465 typedef struct monitor_idx_t monitor_idx_t;
467 struct monitor_idx_t {
468 AttributeDescription *idx_ad;
469 unsigned long idx_count[MDB_MONITOR_IDX_TYPES];
473 mdb_monitor_bitmask2key( slap_mask_t bitmask )
477 for ( key = 0; key < 8 * (int)sizeof(slap_mask_t) && !( bitmask & 0x1U );
484 static struct berval idxbv[] = {
485 BER_BVC( "present=" ),
486 BER_BVC( "equality=" ),
487 BER_BVC( "approx=" ),
488 BER_BVC( "substr=" ),
493 mdb_monitor_idx2len( monitor_idx_t *idx )
498 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
499 if ( idx->idx_count[ i ] != 0 ) {
500 len += idxbv[i].bv_len;
508 monitor_idx_cmp( const void *p1, const void *p2 )
510 const monitor_idx_t *idx1 = (const monitor_idx_t *)p1;
511 const monitor_idx_t *idx2 = (const monitor_idx_t *)p2;
513 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad );
517 monitor_idx_dup( void *p1, void *p2 )
519 monitor_idx_t *idx1 = (monitor_idx_t *)p1;
520 monitor_idx_t *idx2 = (monitor_idx_t *)p2;
522 return SLAP_PTRCMP( idx1->idx_ad, idx2->idx_ad ) == 0 ? -1 : 0;
527 struct mdb_info *mdb,
528 AttributeDescription *desc,
531 monitor_idx_t idx_dummy = { 0 },
535 idx_dummy.idx_ad = desc;
536 key = mdb_monitor_bitmask2key( type ) - 1;
537 if ( key >= MDB_MONITOR_IDX_TYPES ) {
538 /* invalid index type */
542 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
544 idx = (monitor_idx_t *)avl_find( mdb->mi_idx,
545 (caddr_t)&idx_dummy, monitor_idx_cmp );
547 idx = (monitor_idx_t *)ch_calloc( sizeof( monitor_idx_t ), 1 );
549 idx->idx_count[ key ] = 1;
551 switch ( avl_insert( &mdb->mi_idx, (caddr_t)idx,
552 monitor_idx_cmp, monitor_idx_dup ) )
563 idx->idx_count[ key ]++;
566 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
572 mdb_monitor_idx_apply( void *v_idx, void *v_valp )
574 monitor_idx_t *idx = (monitor_idx_t *)v_idx;
575 BerVarray *valp = (BerVarray *)v_valp;
579 char count_buf[ MDB_MONITOR_IDX_TYPES ][ SLAP_TEXT_BUFLEN ];
580 ber_len_t count_len[ MDB_MONITOR_IDX_TYPES ],
584 idx_len = mdb_monitor_idx2len( idx );
587 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
588 if ( idx->idx_count[ i ] == 0 ) {
592 count_len[ i ] = snprintf( count_buf[ i ],
593 sizeof( count_buf[ i ] ), "%lu", idx->idx_count[ i ] );
594 bv.bv_len += count_len[ i ];
598 bv.bv_len += idx->idx_ad->ad_cname.bv_len
601 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
602 ptr = lutil_strcopy( ptr, idx->idx_ad->ad_cname.bv_val );
603 for ( i = 0; i < MDB_MONITOR_IDX_TYPES; i++ ) {
604 if ( idx->idx_count[ i ] == 0 ) {
610 ptr = lutil_strcopy( ptr, idxbv[ i ].bv_val );
611 ptr = lutil_strcopy( ptr, count_buf[ i ] );
614 ber_bvarray_add( valp, &bv );
620 mdb_monitor_idx_entry_add(
621 struct mdb_info *mdb,
624 BerVarray vals = NULL;
627 a = attr_find( e->e_attrs, ad_olmDbNotIndexed );
629 ldap_pvt_thread_mutex_lock( &mdb->mi_idx_mutex );
631 avl_apply( mdb->mi_idx, mdb_monitor_idx_apply,
632 &vals, -1, AVL_INORDER );
634 ldap_pvt_thread_mutex_unlock( &mdb->mi_idx_mutex );
636 if ( vals != NULL ) {
638 assert( a->a_nvals == a->a_vals );
640 ber_bvarray_free( a->a_vals );
645 for ( ap = &e->e_attrs; *ap != NULL; ap = &(*ap)->a_next )
647 *ap = attr_alloc( ad_olmDbNotIndexed );
651 a->a_nvals = a->a_vals;
657 #endif /* MDB_MONITOR_IDX */