1/* ctxcsn.c -- Context CSN Management Routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2003-2011 The OpenLDAP Foundation. 6 * Portions Copyright 2003 IBM Corporation. 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 18#include "portable.h" 19 20#include <stdio.h> 21 22#include <ac/string.h> 23#include <ac/socket.h> 24 25#include "lutil.h" 26#include "slap.h" 27#include "lutil_ldap.h" 28 29const struct berval slap_ldapsync_bv = BER_BVC("ldapsync"); 30const struct berval slap_ldapsync_cn_bv = BER_BVC("cn=ldapsync"); 31int slap_serverID; 32 33/* maxcsn->bv_val must point to a char buf[LDAP_PVT_CSNSTR_BUFSIZE] */ 34void 35slap_get_commit_csn( 36 Operation *op, 37 struct berval *maxcsn, 38 int *foundit 39) 40{ 41 struct slap_csn_entry *csne, *committed_csne = NULL; 42 BackendDB *be = op->o_bd->bd_self; 43 int sid = -1; 44 45 if ( maxcsn ) { 46 assert( maxcsn->bv_val != NULL ); 47 assert( maxcsn->bv_len >= LDAP_PVT_CSNSTR_BUFSIZE ); 48 } 49 if ( foundit ) { 50 *foundit = 0; 51 } 52 53 ldap_pvt_thread_mutex_lock( &be->be_pcl_mutex ); 54 55 if ( !BER_BVISEMPTY( &op->o_csn )) { 56 sid = slap_parse_csn_sid( &op->o_csn ); 57 } 58 59 LDAP_TAILQ_FOREACH( csne, be->be_pending_csn_list, ce_csn_link ) { 60 if ( csne->ce_opid == op->o_opid && csne->ce_connid == op->o_connid ) { 61 csne->ce_state = SLAP_CSN_COMMIT; 62 if ( foundit ) *foundit = 1; 63 break; 64 } 65 } 66 67 LDAP_TAILQ_FOREACH( csne, be->be_pending_csn_list, ce_csn_link ) { 68 if ( sid != -1 && sid == csne->ce_sid ) { 69 if ( csne->ce_state == SLAP_CSN_COMMIT ) committed_csne = csne; 70 if ( csne->ce_state == SLAP_CSN_PENDING ) break; 71 } 72 } 73 74 if ( maxcsn ) { 75 if ( committed_csne ) { 76 if ( committed_csne->ce_csn.bv_len < maxcsn->bv_len ) 77 maxcsn->bv_len = committed_csne->ce_csn.bv_len; 78 AC_MEMCPY( maxcsn->bv_val, committed_csne->ce_csn.bv_val, 79 maxcsn->bv_len+1 ); 80 } else { 81 maxcsn->bv_len = 0; 82 maxcsn->bv_val[0] = 0; 83 } 84 } 85 ldap_pvt_thread_mutex_unlock( &be->be_pcl_mutex ); 86} 87 88void 89slap_rewind_commit_csn( Operation *op ) 90{ 91 struct slap_csn_entry *csne; 92 BackendDB *be = op->o_bd->bd_self; 93 94 ldap_pvt_thread_mutex_lock( &be->be_pcl_mutex ); 95 96 LDAP_TAILQ_FOREACH( csne, be->be_pending_csn_list, ce_csn_link ) { 97 if ( csne->ce_opid == op->o_opid && csne->ce_connid == op->o_connid ) { 98 csne->ce_state = SLAP_CSN_PENDING; 99 break; 100 } 101 } 102 103 ldap_pvt_thread_mutex_unlock( &be->be_pcl_mutex ); 104} 105 106void 107slap_graduate_commit_csn( Operation *op ) 108{ 109 struct slap_csn_entry *csne; 110 BackendDB *be; 111 112 if ( op == NULL ) return; 113 if ( op->o_bd == NULL ) return; 114 be = op->o_bd->bd_self; 115 116 ldap_pvt_thread_mutex_lock( &be->be_pcl_mutex ); 117 118 LDAP_TAILQ_FOREACH( csne, be->be_pending_csn_list, ce_csn_link ) { 119 if ( csne->ce_opid == op->o_opid && csne->ce_connid == op->o_connid ) { 120 LDAP_TAILQ_REMOVE( be->be_pending_csn_list, 121 csne, ce_csn_link ); 122 Debug( LDAP_DEBUG_SYNC, "slap_graduate_commit_csn: removing %p %s\n", 123 csne->ce_csn.bv_val, csne->ce_csn.bv_val, 0 ); 124 if ( op->o_csn.bv_val == csne->ce_csn.bv_val ) { 125 BER_BVZERO( &op->o_csn ); 126 } 127 ch_free( csne->ce_csn.bv_val ); 128 ch_free( csne ); 129 break; 130 } 131 } 132 133 ldap_pvt_thread_mutex_unlock( &be->be_pcl_mutex ); 134 135 return; 136} 137 138static struct berval ocbva[] = { 139 BER_BVC("top"), 140 BER_BVC("subentry"), 141 BER_BVC("syncProviderSubentry"), 142 BER_BVNULL 143}; 144 145Entry * 146slap_create_context_csn_entry( 147 Backend *be, 148 struct berval *context_csn ) 149{ 150 Entry* e; 151 152 struct berval bv; 153 154 e = entry_alloc(); 155 156 attr_merge( e, slap_schema.si_ad_objectClass, 157 ocbva, NULL ); 158 attr_merge_one( e, slap_schema.si_ad_structuralObjectClass, 159 &ocbva[1], NULL ); 160 attr_merge_one( e, slap_schema.si_ad_cn, 161 (struct berval *)&slap_ldapsync_bv, NULL ); 162 163 if ( context_csn ) { 164 attr_merge_one( e, slap_schema.si_ad_contextCSN, 165 context_csn, NULL ); 166 } 167 168 BER_BVSTR( &bv, "{}" ); 169 attr_merge_one( e, slap_schema.si_ad_subtreeSpecification, &bv, NULL ); 170 171 build_new_dn( &e->e_name, &be->be_nsuffix[0], 172 (struct berval *)&slap_ldapsync_cn_bv, NULL ); 173 ber_dupbv( &e->e_nname, &e->e_name ); 174 175 return e; 176} 177 178void 179slap_queue_csn( 180 Operation *op, 181 struct berval *csn ) 182{ 183 struct slap_csn_entry *pending; 184 BackendDB *be = op->o_bd->bd_self; 185 186 pending = (struct slap_csn_entry *) ch_calloc( 1, 187 sizeof( struct slap_csn_entry )); 188 189 Debug( LDAP_DEBUG_SYNC, "slap_queue_csn: queing %p %s\n", csn->bv_val, csn->bv_val, 0 ); 190 191 ldap_pvt_thread_mutex_lock( &be->be_pcl_mutex ); 192 193 ber_dupbv( &pending->ce_csn, csn ); 194 ber_bvreplace_x( &op->o_csn, &pending->ce_csn, op->o_tmpmemctx ); 195 pending->ce_sid = slap_parse_csn_sid( csn ); 196 pending->ce_connid = op->o_connid; 197 pending->ce_opid = op->o_opid; 198 pending->ce_state = SLAP_CSN_PENDING; 199 LDAP_TAILQ_INSERT_TAIL( be->be_pending_csn_list, 200 pending, ce_csn_link ); 201 ldap_pvt_thread_mutex_unlock( &be->be_pcl_mutex ); 202} 203 204int 205slap_get_csn( 206 Operation *op, 207 struct berval *csn, 208 int manage_ctxcsn ) 209{ 210 if ( csn == NULL ) return LDAP_OTHER; 211 212 csn->bv_len = ldap_pvt_csnstr( csn->bv_val, csn->bv_len, slap_serverID, 0 ); 213 if ( manage_ctxcsn ) 214 slap_queue_csn( op, csn ); 215 216 return LDAP_SUCCESS; 217} 218