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-2021 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			desc;
44 	struct berval			nrdn;
45 	ldap_pvt_thread_pool_param_t	param;
46 	monitor_thread_t		mt;
47 }		mt[] = {
48 	{ BER_BVC( "cn=Max" ),
49 		BER_BVC("Maximum number of threads as configured"),
50 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_MAX,		MT_UNKNOWN },
51 	{ BER_BVC( "cn=Max Pending" ),
52 		BER_BVC("Maximum number of pending threads"),
53 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_MAX_PENDING,	MT_UNKNOWN },
54 	{ BER_BVC( "cn=Open" ),
55 		BER_BVC("Number of open threads"),
56 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_OPEN,	MT_UNKNOWN },
57 	{ BER_BVC( "cn=Starting" ),
58 		BER_BVC("Number of threads being started"),
59 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_STARTING,	MT_UNKNOWN },
60 	{ BER_BVC( "cn=Active" ),
61 		BER_BVC("Number of active threads"),
62 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_ACTIVE,	MT_UNKNOWN },
63 	{ BER_BVC( "cn=Pending" ),
64 		BER_BVC("Number of pending threads"),
65 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_PENDING,	MT_UNKNOWN },
66 	{ BER_BVC( "cn=Backload" ),
67 		BER_BVC("Number of active plus pending threads"),
68 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD,	MT_UNKNOWN },
69 #if 0	/* not meaningful right now */
70 	{ BER_BVC( "cn=Active Max" ),
71 		BER_BVNULL,
72 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_ACTIVE_MAX,	MT_UNKNOWN },
73 	{ BER_BVC( "cn=Pending Max" ),
74 		BER_BVNULL,
75 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_PENDING_MAX,	MT_UNKNOWN },
76 	{ BER_BVC( "cn=Backload Max" ),
77 		BER_BVNULL,
78 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_BACKLOAD_MAX,MT_UNKNOWN },
79 #endif
80 	{ BER_BVC( "cn=State" ),
81 		BER_BVC("Thread pool state"),
82 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_STATE,	MT_UNKNOWN },
83 
84 	{ BER_BVC( "cn=Runqueue" ),
85 		BER_BVC("Queue of running threads - besides those handling operations"),
86 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN,	MT_RUNQUEUE },
87 	{ BER_BVC( "cn=Tasklist" ),
88 		BER_BVC("List of running plus standby threads - besides those handling operations"),
89 		BER_BVNULL,	LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN,	MT_TASKLIST },
90 
91 	{ BER_BVNULL }
92 };
93 
94 static int
95 monitor_subsys_thread_update(
96 	Operation		*op,
97 	SlapReply		*rs,
98 	Entry 			*e );
99 #endif /* ! NO_THREADS */
100 
101 /*
102  * initializes log subentry
103  */
104 int
monitor_subsys_thread_init(BackendDB * be,monitor_subsys_t * ms)105 monitor_subsys_thread_init(
106 	BackendDB       	*be,
107 	monitor_subsys_t	*ms )
108 {
109 #ifndef NO_THREADS
110 	monitor_info_t	*mi;
111 	monitor_entry_t	*mp;
112 	Entry		*e, **ep, *e_thread;
113 	int		i;
114 
115 	ms->mss_update = monitor_subsys_thread_update;
116 
117 	mi = ( monitor_info_t * )be->be_private;
118 
119 	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_thread ) ) {
120 		Debug( LDAP_DEBUG_ANY,
121 			"monitor_subsys_thread_init: unable to get entry \"%s\"\n",
122 			ms->mss_dn.bv_val,
123 			0, 0 );
124 		return( -1 );
125 	}
126 
127 	mp = ( monitor_entry_t * )e_thread->e_private;
128 	mp->mp_children = NULL;
129 	ep = &mp->mp_children;
130 
131 	for ( i = 0; !BER_BVISNULL( &mt[ i ].rdn ); i++ ) {
132 		static char	buf[ BACKMONITOR_BUFSIZE ];
133 		int		count = -1;
134 		char		*state = NULL;
135 		struct berval	bv = BER_BVNULL;
136 
137 		/*
138 		 * Max
139 		 */
140 		e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn,
141 			&mt[ i ].rdn,
142 			mi->mi_oc_monitoredObject, NULL, NULL );
143 		if ( e == NULL ) {
144 			Debug( LDAP_DEBUG_ANY,
145 				"monitor_subsys_thread_init: "
146 				"unable to create entry \"%s,%s\"\n",
147 				mt[ i ].rdn.bv_val,
148 				ms->mss_ndn.bv_val, 0 );
149 			return( -1 );
150 		}
151 
152 		/* NOTE: reference to the normalized DN of the entry,
153 		 * under the assumption it's not modified */
154 		dnRdn( &e->e_nname, &mt[ i ].nrdn );
155 
156 		switch ( mt[ i ].param ) {
157 		case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
158 			break;
159 
160 		case LDAP_PVT_THREAD_POOL_PARAM_STATE:
161 			if ( ldap_pvt_thread_pool_query( &connection_pool,
162 				mt[ i ].param, (void *)&state ) == 0 )
163 			{
164 				ber_str2bv( state, 0, 0, &bv );
165 
166 			} else {
167 				BER_BVSTR( &bv, "unknown" );
168 			}
169 			break;
170 
171 		default:
172 			/* NOTE: in case of error, it'll be set to -1 */
173 			(void)ldap_pvt_thread_pool_query( &connection_pool,
174 				mt[ i ].param, (void *)&count );
175 			bv.bv_val = buf;
176 			bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
177 			break;
178 		}
179 
180 		if ( !BER_BVISNULL( &bv ) ) {
181 			attr_merge_normalize_one( e, mi->mi_ad_monitoredInfo, &bv, NULL );
182 		}
183 
184 		if ( !BER_BVISNULL( &mt[ i ].desc ) ) {
185 			attr_merge_normalize_one( e,
186 				slap_schema.si_ad_description,
187 				&mt[ i ].desc, NULL );
188 		}
189 
190 		mp = monitor_entrypriv_create();
191 		if ( mp == NULL ) {
192 			return -1;
193 		}
194 		e->e_private = ( void * )mp;
195 		mp->mp_info = ms;
196 		mp->mp_flags = ms->mss_flags \
197 			| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
198 
199 		if ( monitor_cache_add( mi, e ) ) {
200 			Debug( LDAP_DEBUG_ANY,
201 				"monitor_subsys_thread_init: "
202 				"unable to add entry \"%s,%s\"\n",
203 				mt[ i ].rdn.bv_val,
204 				ms->mss_dn.bv_val, 0 );
205 			return( -1 );
206 		}
207 
208 		*ep = e;
209 		ep = &mp->mp_next;
210 	}
211 
212 	monitor_cache_release( mi, e_thread );
213 
214 #endif /* ! NO_THREADS */
215 	return( 0 );
216 }
217 
218 #ifndef NO_THREADS
219 static int
monitor_subsys_thread_update(Operation * op,SlapReply * rs,Entry * e)220 monitor_subsys_thread_update(
221 	Operation		*op,
222 	SlapReply		*rs,
223 	Entry 			*e )
224 {
225 	monitor_info_t	*mi = ( monitor_info_t * )op->o_bd->be_private;
226 	Attribute		*a;
227 	BerVarray		vals = NULL;
228 	char 			buf[ BACKMONITOR_BUFSIZE ];
229 	struct berval		rdn, bv;
230 	int			which, i;
231 	struct re_s		*re;
232 	int			count = -1;
233 	char			*state = NULL;
234 
235 	assert( mi != NULL );
236 
237 	dnRdn( &e->e_nname, &rdn );
238 
239 	for ( i = 0; !BER_BVISNULL( &mt[ i ].nrdn ); i++ ) {
240 		if ( dn_match( &mt[ i ].nrdn, &rdn ) ) {
241 			break;
242 		}
243 	}
244 
245 	which = i;
246 	if ( BER_BVISNULL( &mt[ which ].nrdn ) ) {
247 		return SLAP_CB_CONTINUE;
248 	}
249 
250 	a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo );
251 
252 	switch ( mt[ which ].param ) {
253 	case LDAP_PVT_THREAD_POOL_PARAM_UNKNOWN:
254 		switch ( mt[ which ].mt ) {
255 		case MT_RUNQUEUE:
256 			if ( a != NULL ) {
257 				if ( a->a_nvals != a->a_vals ) {
258 					ber_bvarray_free( a->a_nvals );
259 				}
260 				ber_bvarray_free( a->a_vals );
261 				a->a_vals = NULL;
262 				a->a_nvals = NULL;
263 				a->a_numvals = 0;
264 			}
265 
266 			i = 0;
267 			bv.bv_val = buf;
268 			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
269 			LDAP_STAILQ_FOREACH( re, &slapd_rq.run_list, rnext ) {
270 				bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
271 					i, re->tname, re->tspec );
272 				if ( bv.bv_len < sizeof( buf ) ) {
273 					value_add_one( &vals, &bv );
274 				}
275 				i++;
276 			}
277 			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
278 
279 			if ( vals ) {
280 				attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
281 				ber_bvarray_free( vals );
282 
283 			} else {
284 				attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo );
285 			}
286 			break;
287 
288 		case MT_TASKLIST:
289 			if ( a != NULL ) {
290 				if ( a->a_nvals != a->a_vals ) {
291 					ber_bvarray_free( a->a_nvals );
292 				}
293 				ber_bvarray_free( a->a_vals );
294 				a->a_vals = NULL;
295 				a->a_nvals = NULL;
296 				a->a_numvals = 0;
297 			}
298 
299 			i = 0;
300 			bv.bv_val = buf;
301 			ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
302 			LDAP_STAILQ_FOREACH( re, &slapd_rq.task_list, tnext ) {
303 				bv.bv_len = snprintf( buf, sizeof( buf ), "{%d}%s(%s)",
304 					i, re->tname, re->tspec );
305 				if ( bv.bv_len < sizeof( buf ) ) {
306 					value_add_one( &vals, &bv );
307 				}
308 				i++;
309 			}
310 			ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
311 
312 			if ( vals ) {
313 				attr_merge_normalize( e, mi->mi_ad_monitoredInfo, vals, NULL );
314 				ber_bvarray_free( vals );
315 
316 			} else {
317 				attr_delete( &e->e_attrs, mi->mi_ad_monitoredInfo );
318 			}
319 			break;
320 
321 		default:
322 			assert( 0 );
323 		}
324 		break;
325 
326 	case LDAP_PVT_THREAD_POOL_PARAM_STATE:
327 		if ( a == NULL ) {
328 			return rs->sr_err = LDAP_OTHER;
329 		}
330 		if ( ldap_pvt_thread_pool_query( &connection_pool,
331 			mt[ i ].param, (void *)&state ) == 0 )
332 		{
333 			ber_str2bv( state, 0, 0, &bv );
334 			ber_bvreplace( &a->a_vals[ 0 ], &bv );
335 		}
336 		break;
337 
338 	default:
339 		if ( a == NULL ) {
340 			return rs->sr_err = LDAP_OTHER;
341 		}
342 		if ( ldap_pvt_thread_pool_query( &connection_pool,
343 			mt[ i ].param, (void *)&count ) == 0 )
344 		{
345 			bv.bv_val = buf;
346 			bv.bv_len = snprintf( buf, sizeof( buf ), "%d", count );
347 			if ( bv.bv_len < sizeof( buf ) ) {
348 				ber_bvreplace( &a->a_vals[ 0 ], &bv );
349 			}
350 		}
351 		break;
352 	}
353 
354 	/* FIXME: touch modifyTimestamp? */
355 
356 	return SLAP_CB_CONTINUE;
357 }
358 #endif /* ! NO_THREADS */
359