4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This module contains a cache used to optimized scope and DA
31 * discovery. Entries live for a short duration only (about 10 seconds),
32 * although their lifetime can be advanced somewhat by frequent use.
33 * The intent is that the canonical source for DAs will always be slpd,
34 * so the short lifetime of cache entries is designed to force clients
35 * to consult slpd frequently so as to pick up the latest DA state
38 * The cache is managed by a thread which monitors calls into the cache.
39 * If the cache has been unused for a certain amount of time, the thread
40 * frees the cache and exits.
42 * The cache is keyed on the queries sent to slpd to access slpd's DA
43 * table. Associated with each query is a reply (in the format of an
44 * on-the-wire SLP SRVRPLY message).
45 * The cache is accessed by the following two functions:
47 * slp_find_das_cached: searches the cache
48 * slp_put_das_cached: adds a reply to the cache
50 * All parameters added to the cache are copied in first, and all results
51 * read from the cache are copied out, so all memory must be freed by
61 #include <sys/types.h>
64 #include <slp-internal.h>
66 /* These constants control the behaviour of the cache */
67 #define MAX_LIFETIME 25 /* max lifetime, in seconds */
68 #define ADVANCE_PER_USE 5 /* seconds lifetime is extended on each use */
69 #define INIT_LIFETIME 10 /* cache entries start with this lifetime */
71 /* Management thread components */
72 #define IDLE_TIMEOUT 30 /* thread will exit after this idle time */
73 static int cache_thr_running
;
74 static mutex_t start_lock
= DEFAULTMUTEX
;
75 static int cache_called
;
76 static cond_t cache_called_cond
;
77 static mutex_t cache_called_lock
= DEFAULTMUTEX
;
78 static SLPError
start_cache_thr();
79 static void cache_thr();
81 /* The cache and cache synchronization */
82 static void *da_cache
;
83 static mutex_t cache_lock
= DEFAULTMUTEX
;
87 unsigned int reply_len
;
91 typedef struct cache_entry cache_entry_t
;
93 /* cache management and searching */
94 static int compare_entries(const void *, const void *);
95 static void free_cache_entry(void *, VISIT
);
98 * Searches the cache for the reply to 'query'. Returns the reply if
99 * found, otherwise NULL.
100 * The caller must free the result.
102 char *slp_find_das_cached(const char *query
) {
103 cache_entry_t ce
[1], **ans
;
107 if (!cache_thr_running
) {
108 if (start_cache_thr() != SLP_OK
) {
113 (void) mutex_lock(&cache_lock
);
116 ans
= slp_tfind(ce
, &da_cache
, compare_entries
);
119 if ((*ans
)->expires
< now
|| (*ans
)->max_life
< now
) {
123 /* copy out the reply */
124 if (!(reply
= malloc((*ans
)->reply_len
))) {
125 slp_err(LOG_CRIT
, 0, "slp_find_das_cached",
129 (void) memcpy(reply
, (*ans
)->reply
, (*ans
)->reply_len
);
130 (*ans
)->expires
+= ADVANCE_PER_USE
;
133 /* notify cache thread of call */
134 (void) mutex_lock(&cache_called_lock
);
136 (void) cond_signal(&cache_called_cond
);
137 (void) mutex_unlock(&cache_called_lock
);
140 (void) mutex_unlock(&cache_lock
);
145 * Adds 'reply' to the cache under the index 'query'. Both parameters
146 * are copied in first, so the caller may free them after the call.
147 * 'len' is the length of 'reply' in bytes.
149 void slp_put_das_cached(const char *query
, const char *reply
,
151 cache_entry_t
*ce
, **ce2
;
154 if (!cache_thr_running
) {
155 if (start_cache_thr() != SLP_OK
) {
160 /* create the cache entry for this reply */
161 if (!(ce
= malloc(sizeof (*ce
)))) {
162 slp_err(LOG_CRIT
, 0, "slp_put_das_cached", "out of memory");
166 if (!(ce
->query
= strdup(query
))) {
168 slp_err(LOG_CRIT
, 0, "slp_put_das_cached", "out of memory");
172 if (!(ce
->reply
= malloc(len
))) {
173 free((void *) (ce
->query
));
175 slp_err(LOG_CRIT
, 0, "slp_put_das_cached", "out of memory");
178 (void) memcpy((void *) (ce
->reply
), reply
, len
);
181 ce
->max_life
= now
+ MAX_LIFETIME
;
182 ce
->expires
= now
+ INIT_LIFETIME
;
184 /* write to the cache */
185 (void) mutex_lock(&cache_lock
);
186 ce2
= slp_tsearch((void *) ce
, &da_cache
, compare_entries
);
188 /* overwrite existing entry */
189 free((void *) ((*ce2
)->query
));
190 free((void *) ((*ce2
)->reply
));
195 (void) mutex_unlock(&cache_lock
);
198 static int compare_entries(const void *x1
, const void *x2
) {
199 cache_entry_t
*e1
= (cache_entry_t
*)x1
;
200 cache_entry_t
*e2
= (cache_entry_t
*)x2
;
202 return (strcasecmp(e1
->query
, e2
->query
));
205 static void free_cache_entry(void *node
, VISIT order
) {
206 if (order
== endorder
|| order
== leaf
) {
207 cache_entry_t
*ce
= *(cache_entry_t
**)node
;
209 free((void *) (ce
->query
));
210 free((void *) (ce
->reply
));
216 static SLPError
start_cache_thr() {
218 SLPError err
= SLP_OK
;
220 (void) mutex_lock(&start_lock
);
222 if (cache_thr_running
) {
226 (void) cond_init(&cache_called_cond
, 0, NULL
);
228 if ((terr
= thr_create(
229 0, NULL
, (void *(*)(void *)) cache_thr
,
230 NULL
, 0, NULL
)) != 0) {
231 slp_err(LOG_CRIT
, 0, "start_cache_thr",
232 "could not start thread: %s", strerror(terr
));
233 err
= SLP_INTERNAL_SYSTEM_ERROR
;
236 cache_thr_running
= 1;
239 (void) mutex_unlock(&start_lock
);
243 static void cache_thr() {
247 (void) mutex_lock(&cache_called_lock
);
250 while (cache_called
== 0) {
253 timeout
.tv_sec
= IDLE_TIMEOUT
;
254 err
= cond_reltimedwait(&cache_called_cond
,
255 &cache_called_lock
, &timeout
);
258 (void) mutex_lock(&cache_lock
);
262 (void (*)(void *, VISIT
, int, void *))free_cache_entry
,
266 (void) mutex_unlock(&cache_lock
);
267 cache_thr_running
= 0;
268 (void) mutex_unlock(&cache_called_lock
);