1 /* $NetBSD: dncache.c,v 1.2 2021/08/14 16:14:59 christos Exp $ */ 2 3 /* dncache.c - dn caching for back-asyncmeta */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2016-2021 The OpenLDAP Foundation. 8 * Portions Copyright 2016 Symas 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 /* ACKNOWLEDGEMENTS: 21 * This work was developed by Symas Corporation 22 * based on back-meta module for inclusion in OpenLDAP Software. 23 * This work was sponsored by Ericsson. */ 24 25 #include <sys/cdefs.h> 26 __RCSID("$NetBSD: dncache.c,v 1.2 2021/08/14 16:14:59 christos Exp $"); 27 28 #include "portable.h" 29 30 #include <stdio.h> 31 #include <ac/string.h> 32 33 #include "slap.h" 34 #include "../back-ldap/back-ldap.h" 35 #include "back-asyncmeta.h" 36 37 /* 38 * The dncache, at present, maps an entry to the target that holds it. 39 */ 40 41 typedef struct metadncacheentry_t { 42 struct berval dn; 43 int target; 44 45 time_t lastupdated; 46 } metadncacheentry_t; 47 48 /* 49 * asyncmeta_dncache_cmp 50 * 51 * compares two struct metadncacheentry; used by avl stuff 52 * FIXME: modify avl stuff to delete an entry based on cmp 53 * (e.g. when ttl expired?) 54 */ 55 int 56 asyncmeta_dncache_cmp( 57 const void *c1, 58 const void *c2 ) 59 { 60 metadncacheentry_t *cc1 = ( metadncacheentry_t * )c1; 61 metadncacheentry_t *cc2 = ( metadncacheentry_t * )c2; 62 63 /* 64 * case sensitive, because the dn MUST be normalized 65 */ 66 return ber_bvcmp( &cc1->dn, &cc2->dn); 67 } 68 69 /* 70 * asyncmeta_dncache_dup 71 * 72 * returns -1 in case a duplicate struct metadncacheentry has been inserted; 73 * used by avl stuff 74 */ 75 int 76 asyncmeta_dncache_dup( 77 void *c1, 78 void *c2 ) 79 { 80 metadncacheentry_t *cc1 = ( metadncacheentry_t * )c1; 81 metadncacheentry_t *cc2 = ( metadncacheentry_t * )c2; 82 83 /* 84 * case sensitive, because the dn MUST be normalized 85 */ 86 return ( ber_bvcmp( &cc1->dn, &cc2->dn ) == 0 ) ? -1 : 0; 87 } 88 89 /* 90 * asyncmeta_dncache_get_target 91 * 92 * returns the target a dn belongs to, or -1 in case the dn is not 93 * in the cache 94 */ 95 int 96 asyncmeta_dncache_get_target( 97 a_metadncache_t *cache, 98 struct berval *ndn ) 99 { 100 metadncacheentry_t tmp_entry, 101 *entry; 102 int target = META_TARGET_NONE; 103 104 assert( cache != NULL ); 105 assert( ndn != NULL ); 106 107 tmp_entry.dn = *ndn; 108 ldap_pvt_thread_mutex_lock( &cache->mutex ); 109 entry = ( metadncacheentry_t * )ldap_avl_find( cache->tree, 110 ( caddr_t )&tmp_entry, asyncmeta_dncache_cmp ); 111 112 if ( entry != NULL ) { 113 114 /* 115 * if cache->ttl < 0, cache never expires; 116 * if cache->ttl = 0 no cache is used; shouldn't get here 117 * else, cache is used with ttl 118 */ 119 if ( cache->ttl < 0 ) { 120 target = entry->target; 121 122 } else { 123 if ( entry->lastupdated+cache->ttl > slap_get_time() ) { 124 target = entry->target; 125 } 126 } 127 } 128 ldap_pvt_thread_mutex_unlock( &cache->mutex ); 129 130 return target; 131 } 132 133 /* 134 * asyncmeta_dncache_update_entry 135 * 136 * updates target and lastupdated of a struct metadncacheentry if exists, 137 * otherwise it gets created; returns -1 in case of error 138 */ 139 int 140 asyncmeta_dncache_update_entry( 141 a_metadncache_t *cache, 142 struct berval *ndn, 143 int target ) 144 { 145 metadncacheentry_t *entry, 146 tmp_entry; 147 time_t curr_time = 0L; 148 int err = 0; 149 150 assert( cache != NULL ); 151 assert( ndn != NULL ); 152 153 /* 154 * if cache->ttl < 0, cache never expires; 155 * if cache->ttl = 0 no cache is used; shouldn't get here 156 * else, cache is used with ttl 157 */ 158 if ( cache->ttl > 0 ) { 159 curr_time = slap_get_time(); 160 } 161 162 tmp_entry.dn = *ndn; 163 164 ldap_pvt_thread_mutex_lock( &cache->mutex ); 165 entry = ( metadncacheentry_t * )ldap_avl_find( cache->tree, 166 ( caddr_t )&tmp_entry, asyncmeta_dncache_cmp ); 167 168 if ( entry != NULL ) { 169 entry->target = target; 170 entry->lastupdated = curr_time; 171 172 } else { 173 entry = ch_malloc( sizeof( metadncacheentry_t ) + ndn->bv_len + 1 ); 174 if ( entry == NULL ) { 175 err = -1; 176 goto error_return; 177 } 178 179 entry->dn.bv_len = ndn->bv_len; 180 entry->dn.bv_val = (char *)&entry[ 1 ]; 181 AC_MEMCPY( entry->dn.bv_val, ndn->bv_val, ndn->bv_len ); 182 entry->dn.bv_val[ ndn->bv_len ] = '\0'; 183 184 entry->target = target; 185 entry->lastupdated = curr_time; 186 187 err = ldap_avl_insert( &cache->tree, ( caddr_t )entry, 188 asyncmeta_dncache_cmp, asyncmeta_dncache_dup ); 189 } 190 191 error_return:; 192 ldap_pvt_thread_mutex_unlock( &cache->mutex ); 193 194 return err; 195 } 196 197 int 198 asyncmeta_dncache_delete_entry( 199 a_metadncache_t *cache, 200 struct berval *ndn ) 201 { 202 metadncacheentry_t *entry, 203 tmp_entry; 204 205 assert( cache != NULL ); 206 assert( ndn != NULL ); 207 208 tmp_entry.dn = *ndn; 209 210 ldap_pvt_thread_mutex_lock( &cache->mutex ); 211 entry = ldap_avl_delete( &cache->tree, ( caddr_t )&tmp_entry, 212 asyncmeta_dncache_cmp ); 213 ldap_pvt_thread_mutex_unlock( &cache->mutex ); 214 215 if ( entry != NULL ) { 216 asyncmeta_dncache_free( ( void * )entry ); 217 } 218 219 return 0; 220 } 221 222 /* 223 * meta_dncache_free 224 * 225 * frees an entry 226 * 227 */ 228 void 229 asyncmeta_dncache_free( 230 void *e ) 231 { 232 free( e ); 233 } 234