xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/overlays/seqmod.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: seqmod.c,v 1.3 2021/08/14 16:15:02 christos Exp $	*/
2 
3 /* seqmod.c - sequenced modifies */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 2004-2021 The OpenLDAP Foundation.
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 the 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 Howard Chu for inclusion in
19  * OpenLDAP Software.
20  */
21 
22 #include <sys/cdefs.h>
23 __RCSID("$NetBSD: seqmod.c,v 1.3 2021/08/14 16:15:02 christos Exp $");
24 
25 #include "portable.h"
26 
27 #ifdef SLAPD_OVER_SEQMOD
28 
29 #include "slap.h"
30 #include "slap-config.h"
31 
32 /* This overlay serializes concurrent attempts to modify a single entry */
33 
34 typedef struct modtarget {
35 	struct modtarget *mt_next;
36 	struct modtarget *mt_tail;
37 	Operation *mt_op;
38 } modtarget;
39 
40 typedef struct seqmod_info {
41 	Avlnode		*sm_mods;	/* entries being modified */
42 	ldap_pvt_thread_mutex_t	sm_mutex;
43 } seqmod_info;
44 
45 static int
sm_avl_cmp(const void * c1,const void * c2)46 sm_avl_cmp( const void *c1, const void *c2 )
47 {
48 	const modtarget *m1, *m2;
49 	int rc;
50 
51 	m1 = c1; m2 = c2;
52 	rc = m1->mt_op->o_req_ndn.bv_len - m2->mt_op->o_req_ndn.bv_len;
53 
54 	if ( rc ) return rc;
55 	return ber_bvcmp( &m1->mt_op->o_req_ndn, &m2->mt_op->o_req_ndn );
56 }
57 
58 static int
seqmod_op_cleanup(Operation * op,SlapReply * rs)59 seqmod_op_cleanup( Operation *op, SlapReply *rs )
60 {
61 	slap_callback *sc = op->o_callback;
62 	seqmod_info *sm = sc->sc_private;
63 	modtarget *mt, mtdummy;
64 	Avlnode	 *av;
65 
66 	mtdummy.mt_op = op;
67 	/* This op is done, remove it */
68 	ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
69 	av = ldap_avl_find2( sm->sm_mods, &mtdummy, sm_avl_cmp );
70 	assert(av != NULL);
71 
72 	mt = av->avl_data;
73 
74 	/* If there are more, promote the next one */
75 	if ( mt->mt_next ) {
76 		av->avl_data = mt->mt_next;
77 		mt->mt_next->mt_tail = mt->mt_tail;
78 	} else {
79 		ldap_avl_delete( &sm->sm_mods, mt, sm_avl_cmp );
80 	}
81 	ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
82 	op->o_callback = sc->sc_next;
83 	op->o_tmpfree( sc, op->o_tmpmemctx );
84 
85 	return 0;
86 }
87 
88 static int
seqmod_op_mod(Operation * op,SlapReply * rs)89 seqmod_op_mod( Operation *op, SlapReply *rs )
90 {
91 	slap_overinst		*on = (slap_overinst *)op->o_bd->bd_info;
92 	seqmod_info		*sm = on->on_bi.bi_private;
93 	modtarget	*mt;
94 	Avlnode	*av;
95 	slap_callback *cb;
96 
97 	cb = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(modtarget),
98 		op->o_tmpmemctx );
99 	mt = (modtarget *)(cb+1);
100 	mt->mt_next = NULL;
101 	mt->mt_tail = mt;
102 	mt->mt_op = op;
103 
104 	/* See if we're already modifying this entry - don't allow
105 	 * near-simultaneous mods of the same entry
106 	 */
107 	ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
108 	av = ldap_avl_find2( sm->sm_mods, mt, sm_avl_cmp );
109 	if ( av ) {
110 		modtarget *mtp = av->avl_data;
111 		mtp->mt_tail->mt_next = mt;
112 		mtp->mt_tail = mt;
113 		/* Wait for this op to get to head of list */
114 		while ( mtp != mt ) {
115 			ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
116 			ldap_pvt_thread_yield();
117 			/* Let it finish - should use a condition
118 			 * variable here... */
119 			ldap_pvt_thread_mutex_lock( &sm->sm_mutex );
120 			mtp = av->avl_data;
121 		}
122 	} else {
123 		/* Record that we're modifying this now */
124 		ldap_avl_insert( &sm->sm_mods, mt, sm_avl_cmp, ldap_avl_dup_error );
125 	}
126 	ldap_pvt_thread_mutex_unlock( &sm->sm_mutex );
127 
128 	cb->sc_cleanup = seqmod_op_cleanup;
129 	cb->sc_private = sm;
130 	cb->sc_next = op->o_callback;
131 	op->o_callback = cb;
132 
133 	return SLAP_CB_CONTINUE;
134 }
135 
136 static int
seqmod_op_extended(Operation * op,SlapReply * rs)137 seqmod_op_extended(
138 	Operation *op,
139 	SlapReply *rs
140 )
141 {
142 	if ( exop_is_write( op )) return seqmod_op_mod( op, rs );
143 	else return SLAP_CB_CONTINUE;
144 }
145 
146 static int
seqmod_db_open(BackendDB * be,ConfigReply * cr)147 seqmod_db_open(
148 	BackendDB *be,
149 	ConfigReply *cr
150 )
151 {
152 	slap_overinst	*on = (slap_overinst *)be->bd_info;
153 	seqmod_info	*sm;
154 
155 	sm = ch_calloc(1, sizeof(seqmod_info));
156 	on->on_bi.bi_private = sm;
157 
158 	ldap_pvt_thread_mutex_init( &sm->sm_mutex );
159 
160 	return 0;
161 }
162 
163 static int
seqmod_db_close(BackendDB * be,ConfigReply * cr)164 seqmod_db_close(
165 	BackendDB *be,
166 	ConfigReply *cr
167 )
168 {
169 	slap_overinst	*on = (slap_overinst *)be->bd_info;
170 	seqmod_info	*sm = (seqmod_info *)on->on_bi.bi_private;
171 
172 	if ( sm ) {
173 		ldap_pvt_thread_mutex_destroy( &sm->sm_mutex );
174 
175 		ch_free( sm );
176 		on->on_bi.bi_private = NULL;
177 	}
178 
179 	return 0;
180 }
181 
182 /* This overlay is set up for dynamic loading via moduleload. For static
183  * configuration, you'll need to arrange for the slap_overinst to be
184  * initialized and registered by some other function inside slapd.
185  */
186 
187 static slap_overinst 		seqmod;
188 
189 int
seqmod_initialize()190 seqmod_initialize()
191 {
192 	seqmod.on_bi.bi_type = "seqmod";
193 	seqmod.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
194 	seqmod.on_bi.bi_db_open = seqmod_db_open;
195 	seqmod.on_bi.bi_db_close = seqmod_db_close;
196 
197 	seqmod.on_bi.bi_op_modify = seqmod_op_mod;
198 	seqmod.on_bi.bi_op_modrdn = seqmod_op_mod;
199 	seqmod.on_bi.bi_extended = seqmod_op_extended;
200 
201 	return overlay_register( &seqmod );
202 }
203 
204 #if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
205 int
init_module(int argc,char * argv[])206 init_module( int argc, char *argv[] )
207 {
208 	return seqmod_initialize();
209 }
210 #endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
211 
212 #endif /* defined(SLAPD_OVER_SEQMOD) */
213