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