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