]> git.sur5r.net Git - openldap/blob - servers/slapd/back-monitor/thread.c
don't leak callbacks if stuff cannot be registered; provide a means to dispose of...
[openldap] / servers / slapd / back-monitor / thread.c
1 /* thread.c - deal with thread subsystem */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2001-2006 The OpenLDAP Foundation.
6  * Portions Copyright 2001-2003 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Pierangelo Masarati for inclusion
19  * in OpenLDAP Software.
20  */
21
22 #include "portable.h"
23
24 #include <stdio.h>
25 #include <ac/string.h>
26
27 #include "slap.h"
28 #include "back-monitor.h"
29
30 #include <ldap_rq.h>
31
32 #ifndef NO_THREADS
33 typedef enum {
34         MT_UNKNOWN,
35         MT_RUNQUEUE,
36         MT_TASKLIST,
37
38         MT_LAST
39 } monitor_thread_t;
40
41 static struct {
42         struct berval                   rdn;
43         struct berval                   nrdn;
44         ldap_pvt_thread_pool_param_t    param;
45         monitor_thread_t                mt;
46 }               mt[] = {
47         { BER_BVC( "cn=Max" ),          BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_MAX,         MT_UNKNOWN },
48         { BER_BVC( "cn=Max Pending" ),  BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_MAX_PENDING, MT_UNKNOWN },
49         { BER_BVC( "cn=Open" ),         BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_OPEN,        MT_UNKNOWN },
50         { BER_BVC( "cn=Starting" ),     BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_STARTING,    MT_UNKNOWN },
51         { BER_BVC( "cn=Active" ),       BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_ACTIVE,      MT_UNKNOWN },
52         { BER_BVC( "cn=Pending" ),      BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_PENDING,     MT_UNKNOWN },
53         { BER_BVC( "cn=Backload" ),     BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD,    MT_UNKNOWN },
54 #if 0   /* not meaningful right now */
55         { BER_BVC( "cn=Active Max" ),   BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_ACTIVE_MAX,  MT_UNKNOWN },
56         { BER_BVC( "cn=Pending Max" ),  BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_PENDING_MAX, MT_UNKNOWN },
57         { BER_BVC( "cn=Backload Max" ), BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD_MAX,MT_UNKNOWN },
58 #endif
59         { BER_BVC( "cn=State" ),        BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_STATE,       MT_UNKNOWN },
60
61         { BER_BVC( "cn=Runqueue" ),     BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN,     MT_RUNQUEUE },
62         { BER_BVC( "cn=Tasklist" ),     BER_BVNULL,     LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN,     MT_TASKLIST },
63
64         { BER_BVNULL }
65 };
66
67 static int 
68 monitor_subsys_thread_update( 
69         Operation               *op,
70         SlapReply               *rs,
71         Entry                   *e );
72 #endif /* ! NO_THREADS */
73
74 /*
75  * initializes log subentry
76  */
77 int
78 monitor_subsys_thread_init(
79         BackendDB               *be,
80         monitor_subsys_t        *ms )
81 {
82 #ifndef NO_THREADS
83         monitor_info_t  *mi;
84         monitor_entry_t *mp;
85         Entry           *e, **ep, *e_thread;
86         int             i;
87
88         ms->mss_update = monitor_subsys_thread_update;
89
90         mi = ( monitor_info_t * )be->be_private;
91
92         if ( monitor_cache_get( mi, &ms->mss_ndn, &e_thread ) ) {
93                 Debug( LDAP_DEBUG_ANY,
94                         "monitor_subsys_thread_init: unable to get entry \"%s\"\n",
95                         ms->mss_ndn.bv_val, 
96                         0, 0 );
97                 return( -1 );
98         }
99
100         mp = ( monitor_entry_t * )e_thread->e_private;
101         mp->mp_children = NULL;
102         ep = &mp->mp_children;
103
104         for ( i = 0; !BER_BVISNULL( &mt[ i ].rdn ); i++ ) {
105                 static char     buf[ BACKMONITOR_BUFSIZE ];
106                 int             count = -1;
107                 char            *state = NULL;
108                 struct berval   bv = BER_BVNULL;
109
110                 /*
111                  * Max
112                  */
113                 e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
114                         &mt[ i ].rdn,
115                         mi->mi_oc_monitoredObject, mi, NULL, NULL );
116                 if ( e == NULL ) {
117                         Debug( LDAP_DEBUG_ANY,
118                                 "monitor_subsys_thread_init: "
119                                 "unable to create entry \"%s,%s\"\n",
120                                 mt[ i ].rdn.bv_val,
121                                 ms->mss_ndn.bv_val, 0 );
122                         return( -1 );
123                 }
124
125                 /* NOTE: reference to the normalized DN of the entry,
126                  * under the assumption it's not modified */
127                 dnRdn( &e->e_nname, &mt[ i ].nrdn );
128
129                 switch ( mt[ i ].param ) {
130                 case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
131                         break;
132
133                 case LDAP_PVT_THREAD_POOL_PARAM_STATE:
134                         if ( ldap_pvt_thread_pool_query( &connection_pool,
135                                 mt[ i ].param, (void *)&state ) == 0 )
136                         {
137                                 ber_str2bv( state, 0, 0, &bv );
138
139                         } else {
140                                 BER_BVSTR( &bv, "unknown" );
141                         }
142                         break;
143
144                 default:
145                         /* NOTE: in case of error, it'll be set to -1 */
146                         (void)ldap_pvt_thread_pool_query( &connection_pool,
147                                 mt[ i ].param, (void *)&count );
148                         bv.bv_val = buf;
149                         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
150                         break;
151                 }
152
153                 if ( !BER_BVISNULL( &bv ) ) {
154                         attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
155                 }
156         
157                 mp = monitor_entrypriv_create();
158                 if ( mp == NULL ) {
159                         return -1;
160                 }
161                 e->e_private = ( void * )mp;
162                 mp->mp_info = ms;
163                 mp->mp_flags = ms->mss_flags \
164                         | MONITOR_F_SUB | MONITOR_F_PERSISTENT;
165
166                 if ( monitor_cache_add( mi, e ) ) {
167                         Debug( LDAP_DEBUG_ANY,
168                                 "monitor_subsys_thread_init: "
169                                 "unable to add entry \"%s,%s\"\n",
170                                 mt[ i ].rdn.bv_val,
171                                 ms->mss_ndn.bv_val, 0 );
172                         return( -1 );
173                 }
174         
175                 *ep = e;
176                 ep = &mp->mp_next;
177         }
178
179         monitor_cache_release( mi, e_thread );
180
181 #endif /* ! NO_THREADS */
182         return( 0 );
183 }
184
185 #ifndef NO_THREADS
186 static int 
187 monitor_subsys_thread_update( 
188         Operation               *op,
189         SlapReply               *rs,
190         Entry                   *e )
191 {
192         monitor_info_t  *mi = ( monitor_info_t * )op->o_bd->be_private;
193         Attribute               *a;
194         BerVarray               vals = NULL;
195         char                    buf[ BACKMONITOR_BUFSIZE ];
196         struct berval           rdn, bv;
197         int                     which, i;
198         struct re_s             *re;
199         int                     count = -1;
200         char                    *state = NULL;
201
202         assert( mi != NULL );
203
204         dnRdn( &e->e_nname, &rdn );
205
206         for ( i = 0; !BER_BVISNULL( &mt[ i ].nrdn ); i++ ) {
207                 if ( dn_match( &mt[ i ].nrdn, &rdn ) ) {
208                         break;
209                 }
210         }
211
212         which = i;
213         if ( BER_BVISNULL( &mt[ which ].nrdn ) ) {
214                 return SLAP_CB_CONTINUE;
215         }
216
217         a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo );
218
219         switch ( mt[ which ].param ) {
220         case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
221                 switch ( mt[ which ].mt ) {
222                 case MT_RUNQUEUE:
223                         if ( a != NULL ) {
224                                 if ( a->a_nvals != a->a_vals ) {
225                                         ber_bvarray_free( a->a_nvals );
226                                 }
227                                 ber_bvarray_free( a->a_vals );
228                                 a->a_vals = NULL;
229                                 a->a_nvals = NULL;
230                         }
231
232                         i = 0;
233                         bv.bv_val = buf;
234                         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
235                         LDAP_STAILQ_FOREACH( re, &slapd_rq.run_list, rnext ) {
236                                 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
237                                         i, re->tname, re->tspec );
238                                 if ( bv.bv_len < sizeof( buf ) ) {
239                                         value_add_one( &vals, &bv );
240                                 }
241                                 i++;
242                         }
243                         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
244         
245                         if ( vals ) {
246                                 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
247                                 ber_bvarray_free( vals );
248                         }
249                         break;
250
251                 case MT_TASKLIST:
252                         if ( a != NULL ) {
253                                 if ( a->a_nvals != a->a_vals ) {
254                                         ber_bvarray_free( a->a_nvals );
255                                 }
256                                 ber_bvarray_free( a->a_vals );
257                                 a->a_vals = NULL;
258                                 a->a_nvals = NULL;
259                         }
260         
261                         i = 0;
262                         bv.bv_val = buf;
263                         ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
264                         LDAP_STAILQ_FOREACH( re, &slapd_rq.task_list, tnext ) {
265                                 bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
266                                         i, re->tname, re->tspec );
267                                 if ( bv.bv_len < sizeof( buf ) ) {
268                                         value_add_one( &vals, &bv );
269                                 }
270                                 i++;
271                         }
272                         ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
273         
274                         if ( vals ) {
275                                 attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
276                                 ber_bvarray_free( vals );
277                         }
278                         break;
279
280                 default:
281                         assert( 0 );
282                 }
283                 break;
284
285         case LDAP_PVT_THREAD_POOL_PARAM_STATE:
286                 if ( a == NULL ) {
287                         return rs->sr_err = LDAP_OTHER;
288                 }
289                 if ( ldap_pvt_thread_pool_query( &connection_pool,
290                         mt[ i ].param, (void *)&state ) == 0 )
291                 {
292                         ber_str2bv( state, 0, 0, &bv );
293                         ber_bvreplace( &a->a_vals[ 0 ], &bv );
294                 }
295                 break;
296
297         default:
298                 if ( a == NULL ) {
299                         return rs->sr_err = LDAP_OTHER;
300                 }
301                 if ( ldap_pvt_thread_pool_query( &connection_pool,
302                         mt[ i ].param, (void *)&count ) == 0 )
303                 {
304                         bv.bv_val = buf;
305                         bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
306                         if ( bv.bv_len < sizeof( buf ) ) {
307                                 ber_bvreplace( &a->a_vals[ 0 ], &bv );
308                         }
309                 }
310                 break;
311         }
312
313         /* FIXME: touch modifyTimestamp? */
314
315         return SLAP_CB_CONTINUE;
316 }
317 #endif /* ! NO_THREADS */