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
asyncmeta_dncache_cmp(const void * c1,const void * c2)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
asyncmeta_dncache_dup(void * c1,void * c2)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
asyncmeta_dncache_get_target(a_metadncache_t * cache,struct berval * ndn)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
asyncmeta_dncache_update_entry(a_metadncache_t * cache,struct berval * ndn,int target)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
asyncmeta_dncache_delete_entry(a_metadncache_t * cache,struct berval * ndn)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
asyncmeta_dncache_free(void * e)229 asyncmeta_dncache_free(
230 void *e )
231 {
232 free( e );
233 }
234