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