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