]> git.sur5r.net Git - openldap/blob - servers/slapd/back-bdb/monitor.c
further improve monitoring setup and cleanup
[openldap] / servers / slapd / back-bdb / monitor.c
1 /* monitor.c - monitor bdb backend */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2000-2006 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
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>.
15  */
16
17 #include "portable.h"
18
19 #include <stdio.h>
20 #include <ac/string.h>
21 #include <ac/unistd.h>
22 #include <ac/stdlib.h>
23 #include <ac/errno.h>
24 #include <sys/stat.h>
25 #include "lutil.h"
26 #include "back-bdb.h"
27 #include "../back-monitor/back-monitor.h"
28
29 static ObjectClass              *oc_olmBDBDatabase;
30
31 static AttributeDescription     *ad_olmBDBEntryCache,
32         *ad_olmBDBEntryInfo, *ad_olmBDBIDLCache,
33         *ad_olmDbDirectory;
34
35 /*
36  * NOTE: there's some confusion in monitor OID arc;
37  * by now, let's consider:
38  * 
39  * Subsystems monitor attributes        1.3.6.1.4.1.4203.666.1.55.0
40  * Databases monitor attributes         1.3.6.1.4.1.4203.666.1.55.0.1
41  * BDB database monitor attributes      1.3.6.1.4.1.4203.666.1.55.0.1.1
42  *
43  * Subsystems monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0
44  * Databases monitor objectclasses      1.3.6.1.4.1.4203.666.3.16.0.1
45  * BDB database monitor objectclasses   1.3.6.1.4.1.4203.666.3.16.0.1.1
46  */
47
48 static struct {
49         char                    *name;
50         char                    *oid;
51 }               s_oid[] = {
52         { "olmBDBAttributes",                   "olmDatabaseAttributes:1" },
53         { "olmBDBObjectClasses",                "olmDatabaseObjectClasses:1" },
54
55         { NULL }
56 };
57
58 static struct {
59         char                    *name;
60         char                    *desc;
61         AttributeDescription    **ad;
62 }               s_at[] = {
63         { "olmBDBEntryCache", "( olmBDBAttributes:1 "
64                 "NAME ( 'olmBDBEntryCache' ) "
65                 "DESC 'Number of items in Entry Cache' "
66                 "SUP monitorCounter "
67                 "NO-USER-MODIFICATION "
68                 "USAGE directoryOperation )",
69                 &ad_olmBDBEntryCache },
70
71         { "olmBDBEntryInfo", "( olmBDBAttributes:2 "
72                 "NAME ( 'olmBDBEntryInfo' ) "
73                 "DESC 'Number of items in EntryInfo Cache' "
74                 "SUP monitorCounter "
75                 "NO-USER-MODIFICATION "
76                 "USAGE directoryOperation )",
77                 &ad_olmBDBEntryInfo },
78
79         { "olmBDBIDLCache", "( olmBDBAttributes:3 "
80                 "NAME ( 'olmBDBIDLCache' ) "
81                 "DESC 'Number of items in IDL Cache' "
82                 "SUP monitorCounter "
83                 "NO-USER-MODIFICATION "
84                 "USAGE directoryOperation )",
85                 &ad_olmBDBIDLCache },
86
87         { "olmDbDirectory", "( olmBDBAttributes:4 "
88                 "NAME ( 'olmDbDirectory' ) "
89                 "DESC 'Path name of the directory "
90                         "where the database environment resides' "
91                 "SUP monitoredInfo "
92                 "NO-USER-MODIFICATION "
93                 "USAGE directoryOperation )",
94                 &ad_olmDbDirectory },
95
96         { NULL }
97 };
98
99 static struct {
100         char            *name;
101         char            *desc;
102         ObjectClass     **oc;
103 }               s_oc[] = {
104         /* augments an existing object, so it must be AUXILIARY
105          * FIXME: derive from some ABSTRACT "monitoredEntity"? */
106         { "olmBDBDatabase", "( olmBDBObjectClasses:1 "
107                 "NAME ( 'olmBDBDatabase' ) "
108                 "SUP top AUXILIARY "
109                 "MAY ( "
110                         "olmBDBEntryCache "
111                         "$ olmBDBEntryInfo "
112                         "$ olmBDBIDLCache "
113                         "$ olmDbDirectory "
114                         ") )",
115                 &oc_olmBDBDatabase },
116
117         { NULL }
118 };
119
120 static int
121 bdb_monitor_update(
122         Operation       *op,
123         SlapReply       *rs,
124         Entry           *e,
125         void            *priv )
126 {
127         struct bdb_info         *bdb = (struct bdb_info *) priv;
128         Attribute               *a;
129
130         char                    buf[ BUFSIZ ];
131         struct berval           bv;
132
133         assert( ad_olmBDBEntryCache != NULL );
134
135         a = attr_find( e->e_attrs, ad_olmBDBEntryCache );
136         assert( a != NULL );
137         bv.bv_val = buf;
138         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_cursize );
139         ber_bvreplace( &a->a_vals[ 0 ], &bv );
140
141         a = attr_find( e->e_attrs, ad_olmBDBEntryInfo );
142         assert( a != NULL );
143         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_cache.c_eiused );
144         ber_bvreplace( &a->a_vals[ 0 ], &bv );
145
146         a = attr_find( e->e_attrs, ad_olmBDBIDLCache );
147         assert( a != NULL );
148         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", bdb->bi_idl_cache_size );
149         ber_bvreplace( &a->a_vals[ 0 ], &bv );
150         
151         return SLAP_CB_CONTINUE;
152 }
153
154 static int
155 bdb_monitor_modify(
156         Operation       *op,
157         SlapReply       *rs,
158         Entry           *e,
159         void            *priv )
160 {
161         struct bdb_info         *bdb = (struct bdb_info *) priv;
162         
163         return SLAP_CB_CONTINUE;
164 }
165
166 static int
167 bdb_monitor_free(
168         Entry           *e,
169         void            *priv )
170 {
171         struct bdb_info         *bdb = (struct bdb_info *) priv;
172
173         struct berval   values[ 2 ];
174         Modification    mod = { 0 };
175
176         const char      *text;
177         char            textbuf[ SLAP_TEXT_BUFLEN ];
178
179         int             i, rc;
180
181         /* Remove objectClass */
182         mod.sm_op = LDAP_MOD_DELETE;
183         mod.sm_desc = slap_schema.si_ad_objectClass;
184         mod.sm_values = values;
185         values[ 0 ] = oc_olmBDBDatabase->soc_cname;
186         BER_BVZERO( &values[ 1 ] );
187
188         rc = modify_delete_values( e, &mod, 1, &text,
189                 textbuf, sizeof( textbuf ) );
190         /* don't care too much about return code... */
191
192         /* remove attrs */
193         for ( i = 0; s_at[ i ].name != NULL; i++ ) {
194                 mod.sm_desc = *s_at[ i ].ad;
195                 mod.sm_values = NULL;
196                 rc = modify_delete_values( e, &mod, 1, &text,
197                         textbuf, sizeof( textbuf ) );
198                 /* don't care too much about return code... */
199         }
200         
201         return SLAP_CB_CONTINUE;
202 }
203
204 /*
205  * call from within bdb_initialize()
206  */
207 int
208 bdb_monitor_initialize( void )
209 {
210         int             i, code;
211         const char      *err;
212
213         static int      bdb_monitor_initialized = 0;
214
215         /* register schema here; if compiled as dynamic object,
216          * must be loaded __after__ back_monitor.la */
217
218         if ( bdb_monitor_initialized++ ) {
219                 return 0;
220         }
221
222         for ( i = 0; s_oid[ i ].name; i++ ) {
223                 char    *argv[ 3 ];
224         
225                 argv[ 0 ] = "back-bdb/back-hdb monitor";
226                 argv[ 1 ] = s_oid[ i ].name;
227                 argv[ 2 ] = s_oid[ i ].oid;
228
229                 if ( parse_oidm( argv[ 0 ], i, 3, argv, 0, NULL ) != 0 ) {
230                         Debug( LDAP_DEBUG_ANY,
231                                 "bdb_monitor_initialize: unable to add "
232                                 "objectIdentifier \"%s=%s\"\n",
233                                 s_oid[ i ].name, s_oid[ i ].oid, 0 );
234                         return 1;
235                 }
236         }
237
238         for ( i = 0; s_at[ i ].name != NULL; i++ ) {
239                 LDAPAttributeType       *at;
240
241                 at = ldap_str2attributetype( s_at[ i ].desc,
242                         &code, &err, LDAP_SCHEMA_ALLOW_ALL );
243                 if ( !at ) {
244                         Debug( LDAP_DEBUG_ANY,
245                                 "bdb_monitor_initialize: "
246                                 "AttributeType load failed: %s %s\n",
247                                 ldap_scherr2str( code ), err, 0 );
248                         return LDAP_INVALID_SYNTAX;
249                 }
250
251                 code = at_add( at, 0, NULL, &err );
252                 if ( code != LDAP_SUCCESS ) {
253                         Debug( LDAP_DEBUG_ANY,
254                                 "bdb_monitor_initialize: "
255                                 "AttributeType load failed: %s %s\n",
256                                 scherr2str( code ), err, 0 );
257                         code = LDAP_INVALID_SYNTAX;
258                         goto done_at;
259                 }
260
261                 code = slap_str2ad( s_at[ i ].name,
262                                 s_at[ i ].ad, &err );
263                 if ( code != LDAP_SUCCESS ) {
264                         Debug( LDAP_DEBUG_ANY,
265                                 "bdb_monitor_initialize: "
266                                 "unable to find AttributeDescription "
267                                 "\"%s\": %d (%s)\n",
268                                 s_at[ i ].name, code, err );
269                         code = LDAP_UNDEFINED_TYPE;
270                         goto done_at;
271                 }
272
273 done_at:;
274                 if ( code ) {
275                         ldap_attributetype_free( at );
276                         return code;
277                 }
278
279                 ldap_memfree( at );
280         }
281
282         for ( i = 0; s_oc[ i ].name != NULL; i++ ) {
283                 LDAPObjectClass *oc;
284
285                 oc = ldap_str2objectclass( s_oc[ i ].desc,
286                                 &code, &err, LDAP_SCHEMA_ALLOW_ALL );
287                 if ( !oc ) {
288                         Debug( LDAP_DEBUG_ANY,
289                                 "bdb_monitor_initialize: "
290                                 "ObjectClass load failed: %s %s\n",
291                                 ldap_scherr2str( code ), err, 0 );
292                         return LDAP_INVALID_SYNTAX;
293                 }
294
295                 code = oc_add( oc, 0, NULL, &err );
296                 if ( code != LDAP_SUCCESS ) {
297                         Debug( LDAP_DEBUG_ANY,
298                                 "bdb_monitor_initialize: "
299                                 "ObjectClass load failed: %s %s\n",
300                                 scherr2str( code ), err, 0 );
301                         code = LDAP_INVALID_SYNTAX;
302                         goto done_oc;
303                 }
304
305                 *s_oc[ i ].oc = oc_find( s_oc[ i ].name );
306                 if ( *s_oc[ i ].oc == NULL ) {
307                         code = LDAP_UNDEFINED_TYPE;
308                         Debug( LDAP_DEBUG_ANY,
309                                 "bdb_monitor_initialize: "
310                                 "unable to find objectClass \"%s\"\n",
311                                 s_oc[ i ].name, 0, 0 );
312                         goto done_oc;
313                 }
314
315 done_oc:;
316                 if ( code != LDAP_SUCCESS ) {
317                         ldap_objectclass_free( oc );
318                         return code;
319                 }
320
321                 ldap_memfree( oc );
322         }
323
324         return 0;
325 }
326
327 /*
328  * call from within bdb_db_init()
329  */
330 int
331 bdb_monitor_init( BackendDB *be )
332 {
333         SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
334
335         return 0;
336 }
337
338 /*
339  * call from within bdb_db_open()
340  */
341 int
342 bdb_monitor_open( BackendDB *be )
343 {
344         struct bdb_info         *bdb = (struct bdb_info *) be->be_private;
345         Attribute               *a, *next;
346         monitor_callback_t      *cb;
347         struct berval           suffix, *filter, *base;
348         char                    *ptr;
349         int                     rc = 0;
350
351         if ( !SLAP_DBMONITORING( be ) ) {
352                 return 0;
353         }
354
355         /* don't bother if monitor is not configured */
356         if ( !monitor_back_is_configured() ) {
357                 static int warning = 0;
358
359                 if ( warning++ == 0 ) {
360                         Debug( LDAP_DEBUG_ANY, "bdb_monitor_open: "
361                                 "monitoring disabled; "
362                                 "configure monitor database to enable\n",
363                                 0, 0, 0 );
364                 }
365
366                 return 0;
367         }
368
369         bdb->bi_monitor.bdm_scope = LDAP_SCOPE_SUBORDINATE;
370         base = &bdb->bi_monitor.bdm_nbase;
371         BER_BVSTR( base, "cn=databases,cn=monitor" );
372         filter = &bdb->bi_monitor.bdm_filter;
373         BER_BVZERO( filter );
374
375         suffix.bv_len = ldap_bv2escaped_filter_value_len( &be->be_nsuffix[ 0 ] );
376         if ( suffix.bv_len == be->be_nsuffix[ 0 ].bv_len ) {
377                 suffix = be->be_nsuffix[ 0 ];
378
379         } else {
380                 ldap_bv2escaped_filter_value( &be->be_nsuffix[ 0 ], &suffix );
381         }
382         
383         filter->bv_len = STRLENOF( "(&(monitoredInfo=" )
384                 + strlen( be->bd_info->bi_type )
385                 + STRLENOF( ")(namingContexts:distinguishedNameMatch:=" )
386                 + suffix.bv_len + STRLENOF( "))" );
387         ptr = filter->bv_val = ch_malloc( filter->bv_len + 1 );
388         ptr = lutil_strcopy( ptr, "(&(monitoredInfo=" );
389         ptr = lutil_strcopy( ptr, be->bd_info->bi_type );
390         ptr = lutil_strcopy( ptr, ")(namingContexts:distinguishedNameMatch:=" );
391         ptr = lutil_strncopy( ptr, suffix.bv_val, suffix.bv_len );
392         ptr = lutil_strcopy( ptr, "))" );
393         ptr[ 0 ] = '\0';
394         assert( filter->bv_len == ptr - filter->bv_val );
395         
396         if ( suffix.bv_val != be->be_nsuffix[ 0 ].bv_val ) {
397                 ch_free( suffix.bv_val );
398         }
399
400         /* alloc as many as required (plus 1 for objectClass) */
401         a = attrs_alloc( 1 + 4 );
402         if ( a == NULL ) {
403                 rc = 1;
404                 goto cleanup;
405         }
406
407         a->a_desc = slap_schema.si_ad_objectClass;
408         value_add_one( &a->a_vals, &oc_olmBDBDatabase->soc_cname );
409         a->a_nvals = a->a_vals;
410         next = a->a_next;
411
412         {
413                 struct berval   bv = BER_BVC( "0" );
414
415                 next->a_desc = ad_olmBDBEntryCache;
416                 value_add_one( &next->a_vals, &bv );
417                 next->a_nvals = next->a_vals;
418                 next = next->a_next;
419
420                 next->a_desc = ad_olmBDBEntryInfo;
421                 value_add_one( &next->a_vals, &bv );
422                 next->a_nvals = next->a_vals;
423                 next = next->a_next;
424
425                 next->a_desc = ad_olmBDBIDLCache;
426                 value_add_one( &next->a_vals, &bv );
427                 next->a_nvals = next->a_vals;
428                 next = next->a_next;
429         }
430
431         {
432                 struct berval   bv, nbv;
433                 ber_len_t       pathlen = 0, len = 0;
434                 char            path[ PATH_MAX ] = { '\0' };
435                 char            *fname = bdb->bi_dbenv_home,
436                                 *ptr;
437
438                 len = strlen( fname );
439                 if ( fname[ 0 ] != '/' ) {
440                         /* get full path name */
441                         getcwd( path, sizeof( path ) );
442                         pathlen = strlen( path );
443
444                         if ( fname[ 0 ] == '.' && fname[ 1 ] == '/' ) {
445                                 fname += 2;
446                                 len -= 2;
447                         }
448                 }
449
450                 bv.bv_len = pathlen + STRLENOF( "/" ) + len;
451                 ptr = bv.bv_val = ch_malloc( bv.bv_len + STRLENOF( "/" ) + 1 );
452                 if ( pathlen ) {
453                         ptr = lutil_strncopy( ptr, path, pathlen );
454                         ptr[ 0 ] = '/';
455                         ptr++;
456                 }
457                 ptr = lutil_strncopy( ptr, fname, len );
458                 if ( ptr[ -1 ] != '/' ) {
459                         ptr[ 0 ] = '/';
460                         ptr++;
461                 }
462                 ptr[ 0 ] = '\0';
463                 
464                 attr_normalize_one( ad_olmDbDirectory, &bv, &nbv, NULL );
465
466                 next->a_desc = ad_olmDbDirectory;
467                 next->a_vals = ch_calloc( sizeof( struct berval ), 2 );
468                 next->a_vals[ 0 ] = bv;
469
470                 if ( BER_BVISNULL( &nbv ) ) {
471                         next->a_nvals = next->a_vals;
472
473                 } else {
474                         next->a_nvals = ch_calloc( sizeof( struct berval ), 2 );
475                         next->a_nvals[ 0 ] = nbv;
476                 }
477
478                 next = next->a_next;
479         }
480
481         cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
482         cb->mc_update = bdb_monitor_update;
483         cb->mc_modify = bdb_monitor_modify;
484         cb->mc_free = bdb_monitor_free;
485         cb->mc_private = (void *)bdb;
486
487         rc = monitor_back_register_entry_attrs( NULL, a, cb,
488                 base, LDAP_SCOPE_SUBORDINATE, filter );
489
490 cleanup:;
491         if ( rc != 0 ) {
492                 if ( cb != NULL ) {
493                         ch_free( cb );
494                         cb = NULL;
495                 }
496
497                 if ( a != NULL ) {
498                         attrs_free( a );
499                         a = NULL;
500                 }
501
502                 if ( !BER_BVISNULL( filter ) ) {
503                         ch_free( filter->bv_val );
504                         BER_BVZERO( filter );
505                 }
506         }
507
508         /* store for cleanup */
509         bdb->bi_monitor.bdm_cb = (void *)cb;
510
511         /* we don't need to keep track of the attributes, because
512          * bdb_monitor_free() takes care of everything */
513         if ( a != NULL ) {
514                 attrs_free( a );
515         }
516
517         return rc;
518 }
519
520 /*
521  * call from within bdb_db_close()
522  */
523 int
524 bdb_monitor_close( BackendDB *be )
525 {
526         struct bdb_info         *bdb = (struct bdb_info *) be->be_private;
527
528         if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_filter ) ) {
529                 monitor_back_unregister_entry_callback( NULL,
530                         (monitor_callback_t *)bdb->bi_monitor.bdm_cb,
531                         &bdb->bi_monitor.bdm_nbase,
532                         bdb->bi_monitor.bdm_scope,
533                         &bdb->bi_monitor.bdm_filter );
534
535                 if ( !BER_BVISNULL( &bdb->bi_monitor.bdm_filter ) ) {
536                         ch_free( bdb->bi_monitor.bdm_filter.bv_val );
537                 }
538
539                 memset( &bdb->bi_monitor, 0, sizeof( bdb->bi_monitor ) );
540         }
541
542         return 0;
543 }
544
545 /*
546  * call from within bdb_db_destroy()
547  */
548 int
549 bdb_monitor_destroy( BackendDB *be )
550 {
551         return 0;
552 }
553