1 /* seqmod.c - sequenced modifies */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 2004-2008 The OpenLDAP Foundation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
16 * This work was initially developed by Howard Chu for inclusion in
22 #ifdef SLAPD_OVER_SEQMOD
27 /* This overlay serializes concurrent attempts to modify a single entry */
29 typedef struct modtarget
{
30 struct modtarget
*mt_next
;
31 struct modtarget
*mt_tail
;
35 typedef struct seqmod_info
{
36 Avlnode
*sm_mods
; /* entries being modified */
37 ldap_pvt_thread_mutex_t sm_mutex
;
41 sm_avl_cmp( const void *c1
, const void *c2
)
43 const modtarget
*m1
, *m2
;
47 rc
= m1
->mt_op
->o_req_ndn
.bv_len
- m2
->mt_op
->o_req_ndn
.bv_len
;
50 return ber_bvcmp( &m1
->mt_op
->o_req_ndn
, &m2
->mt_op
->o_req_ndn
);
54 seqmod_op_cleanup( Operation
*op
, SlapReply
*rs
)
56 slap_callback
*sc
= op
->o_callback
;
57 seqmod_info
*sm
= sc
->sc_private
;
58 modtarget
*mt
, mtdummy
;
62 /* This op is done, remove it */
63 ldap_pvt_thread_mutex_lock( &sm
->sm_mutex
);
64 av
= avl_find2( sm
->sm_mods
, &mtdummy
, sm_avl_cmp
);
69 /* If there are more, promote the next one */
71 av
->avl_data
= mt
->mt_next
;
72 mt
->mt_next
->mt_tail
= mt
->mt_tail
;
74 avl_delete( &sm
->sm_mods
, mt
, sm_avl_cmp
);
76 ldap_pvt_thread_mutex_unlock( &sm
->sm_mutex
);
77 op
->o_callback
= sc
->sc_next
;
78 op
->o_tmpfree( sc
, op
->o_tmpmemctx
);
84 seqmod_op_mod( Operation
*op
, SlapReply
*rs
)
86 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
87 seqmod_info
*sm
= on
->on_bi
.bi_private
;
92 cb
= op
->o_tmpcalloc( 1, sizeof(slap_callback
) + sizeof(modtarget
),
94 mt
= (modtarget
*)(cb
+1);
99 /* See if we're already modifying this entry - don't allow
100 * near-simultaneous mods of the same entry
102 ldap_pvt_thread_mutex_lock( &sm
->sm_mutex
);
103 av
= avl_find2( sm
->sm_mods
, mt
, sm_avl_cmp
);
105 modtarget
*mtp
= av
->avl_data
;
106 mtp
->mt_tail
->mt_next
= mt
;
108 /* Wait for this op to get to head of list */
109 while ( mtp
!= mt
) {
110 ldap_pvt_thread_mutex_unlock( &sm
->sm_mutex
);
111 ldap_pvt_thread_yield();
112 /* Let it finish - should use a condition
113 * variable here... */
114 ldap_pvt_thread_mutex_lock( &sm
->sm_mutex
);
118 /* Record that we're modifying this now */
119 avl_insert( &sm
->sm_mods
, mt
, sm_avl_cmp
, avl_dup_error
);
121 ldap_pvt_thread_mutex_unlock( &sm
->sm_mutex
);
123 cb
->sc_cleanup
= seqmod_op_cleanup
;
125 cb
->sc_next
= op
->o_callback
;
128 return SLAP_CB_CONTINUE
;
137 if ( exop_is_write( op
)) return seqmod_op_mod( op
, rs
);
138 else return SLAP_CB_CONTINUE
;
147 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
150 sm
= ch_calloc(1, sizeof(seqmod_info
));
151 on
->on_bi
.bi_private
= sm
;
153 ldap_pvt_thread_mutex_init( &sm
->sm_mutex
);
164 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
165 seqmod_info
*sm
= (seqmod_info
*)on
->on_bi
.bi_private
;
168 ldap_pvt_thread_mutex_destroy( &sm
->sm_mutex
);
176 /* This overlay is set up for dynamic loading via moduleload. For static
177 * configuration, you'll need to arrange for the slap_overinst to be
178 * initialized and registered by some other function inside slapd.
181 static slap_overinst seqmod
;
186 seqmod
.on_bi
.bi_type
= "seqmod";
187 seqmod
.on_bi
.bi_db_open
= seqmod_db_open
;
188 seqmod
.on_bi
.bi_db_close
= seqmod_db_close
;
190 seqmod
.on_bi
.bi_op_modify
= seqmod_op_mod
;
191 seqmod
.on_bi
.bi_op_modrdn
= seqmod_op_mod
;
192 seqmod
.on_bi
.bi_extended
= seqmod_op_extended
;
194 return overlay_register( &seqmod
);
197 #if SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC
199 init_module( int argc
, char *argv
[] )
201 return seqmod_initialize();
203 #endif /* SLAPD_OVER_SEQMOD == SLAPD_MOD_DYNAMIC */
205 #endif /* defined(SLAPD_OVER_SEQMOD) */