1/* readw.c - deal with read waiters subsystem */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2001-2011 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 "lutil.h"
29#include "back-monitor.h"
30
31static int
32monitor_subsys_rww_destroy(
33	BackendDB		*be,
34	monitor_subsys_t	*ms );
35
36static int
37monitor_subsys_rww_update(
38	Operation		*op,
39	SlapReply		*rs,
40	Entry                   *e );
41
42enum {
43	MONITOR_RWW_READ = 0,
44	MONITOR_RWW_WRITE,
45
46	MONITOR_RWW_LAST
47};
48
49static struct monitor_rww_t {
50	struct berval	rdn;
51	struct berval	nrdn;
52} monitor_rww[] = {
53	{ BER_BVC("cn=Read"),		BER_BVNULL },
54	{ BER_BVC("cn=Write"),		BER_BVNULL },
55	{ BER_BVNULL,			BER_BVNULL }
56};
57
58int
59monitor_subsys_rww_init(
60	BackendDB		*be,
61	monitor_subsys_t	*ms )
62{
63	monitor_info_t	*mi;
64
65	Entry		**ep, *e_conn;
66	monitor_entry_t	*mp;
67	int			i;
68
69	assert( be != NULL );
70
71	ms->mss_destroy = monitor_subsys_rww_destroy;
72	ms->mss_update = monitor_subsys_rww_update;
73
74	mi = ( monitor_info_t * )be->be_private;
75
76	if ( monitor_cache_get( mi, &ms->mss_ndn, &e_conn ) ) {
77		Debug( LDAP_DEBUG_ANY,
78			"monitor_subsys_rww_init: "
79			"unable to get entry \"%s\"\n",
80			ms->mss_ndn.bv_val, 0, 0 );
81		return( -1 );
82	}
83
84	mp = ( monitor_entry_t * )e_conn->e_private;
85	mp->mp_children = NULL;
86	ep = &mp->mp_children;
87
88	for ( i = 0; i < MONITOR_RWW_LAST; i++ ) {
89		struct berval		nrdn, bv;
90		Entry			*e;
91
92		e = monitor_entry_stub( &ms->mss_dn, &ms->mss_ndn, &monitor_rww[i].rdn,
93			mi->mi_oc_monitorCounterObject, mi, NULL, NULL );
94		if ( e == NULL ) {
95			Debug( LDAP_DEBUG_ANY,
96				"monitor_subsys_rww_init: "
97				"unable to create entry \"cn=Read,%s\"\n",
98				ms->mss_ndn.bv_val, 0, 0 );
99			return( -1 );
100		}
101
102		/* steal normalized RDN */
103		dnRdn( &e->e_nname, &nrdn );
104		ber_dupbv( &monitor_rww[ i ].nrdn, &nrdn );
105
106		BER_BVSTR( &bv, "0" );
107		attr_merge_one( e, mi->mi_ad_monitorCounter, &bv, NULL );
108
109		mp = monitor_entrypriv_create();
110		if ( mp == NULL ) {
111			return -1;
112		}
113		e->e_private = ( void * )mp;
114		mp->mp_info = ms;
115		mp->mp_flags = ms->mss_flags \
116			| MONITOR_F_SUB | MONITOR_F_PERSISTENT;
117
118		if ( monitor_cache_add( mi, e ) ) {
119			Debug( LDAP_DEBUG_ANY,
120				"monitor_subsys_rww_init: "
121				"unable to add entry \"%s,%s\"\n",
122				monitor_rww[ i ].rdn.bv_val,
123				ms->mss_ndn.bv_val, 0 );
124			return( -1 );
125		}
126
127		*ep = e;
128		ep = &mp->mp_next;
129	}
130
131	monitor_cache_release( mi, e_conn );
132
133	return( 0 );
134}
135
136static int
137monitor_subsys_rww_destroy(
138	BackendDB		*be,
139	monitor_subsys_t	*ms )
140{
141	int		i;
142
143	for ( i = 0; i < MONITOR_RWW_LAST; i++ ) {
144		ber_memfree_x( monitor_rww[ i ].nrdn.bv_val, NULL );
145	}
146
147	return 0;
148}
149
150static int
151monitor_subsys_rww_update(
152	Operation		*op,
153	SlapReply		*rs,
154	Entry                   *e )
155{
156	monitor_info_t *mi = (monitor_info_t *)op->o_bd->be_private;
157	Connection	*c;
158	int		connindex;
159	long		nconns, nwritewaiters, nreadwaiters;
160
161	int		i;
162	struct berval	nrdn;
163
164	Attribute	*a;
165	char 		buf[LDAP_PVT_INTTYPE_CHARS(long)];
166	long		num = 0;
167	ber_len_t	len;
168
169	assert( mi != NULL );
170	assert( e != NULL );
171
172	dnRdn( &e->e_nname, &nrdn );
173
174	for ( i = 0; !BER_BVISNULL( &monitor_rww[ i ].nrdn ); i++ ) {
175		if ( dn_match( &nrdn, &monitor_rww[ i ].nrdn ) ) {
176			break;
177		}
178	}
179
180	if ( i == MONITOR_RWW_LAST ) {
181		return SLAP_CB_CONTINUE;
182	}
183
184	nconns = nwritewaiters = nreadwaiters = 0;
185	for ( c = connection_first( &connindex );
186			c != NULL;
187			c = connection_next( c, &connindex ), nconns++ )
188	{
189		if ( c->c_writewaiter ) {
190			nwritewaiters++;
191		}
192
193		/* FIXME: ?!? */
194		if ( c->c_currentber != NULL ) {
195			nreadwaiters++;
196		}
197	}
198	connection_done(c);
199
200	switch ( i ) {
201	case MONITOR_RWW_READ:
202		num = nreadwaiters;
203		break;
204
205	case MONITOR_RWW_WRITE:
206		num = nwritewaiters;
207		break;
208
209	default:
210		assert( 0 );
211	}
212
213	snprintf( buf, sizeof( buf ), "%ld", num );
214
215	a = attr_find( e->e_attrs, mi->mi_ad_monitorCounter );
216	assert( a != NULL );
217	len = strlen( buf );
218	if ( len > a->a_vals[ 0 ].bv_len ) {
219		a->a_vals[ 0 ].bv_val = ber_memrealloc( a->a_vals[ 0 ].bv_val, len + 1 );
220		if ( BER_BVISNULL( &a->a_vals[ 0 ] ) ) {
221			BER_BVZERO( &a->a_vals[ 0 ] );
222			return SLAP_CB_CONTINUE;
223		}
224	}
225	AC_MEMCPY( a->a_vals[ 0 ].bv_val, buf, len + 1 );
226	a->a_vals[ 0 ].bv_len = len;
227
228	/* FIXME: touch modifyTimestamp? */
229
230	return SLAP_CB_CONTINUE;
231}
232
233