xref: /dflybsd-src/usr.sbin/nscd/cachelib.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*-
2*86d7f5d3SJohn Marino  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3*86d7f5d3SJohn Marino  * All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
9*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
10*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
11*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
12*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
13*86d7f5d3SJohn Marino  *
14*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*86d7f5d3SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*86d7f5d3SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*86d7f5d3SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*86d7f5d3SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*86d7f5d3SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*86d7f5d3SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*86d7f5d3SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*86d7f5d3SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*86d7f5d3SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*86d7f5d3SJohn Marino  * SUCH DAMAGE.
25*86d7f5d3SJohn Marino  *
26*86d7f5d3SJohn Marino  * $FreeBSD: src/usr.sbin/nscd/cachelib.c,v 1.4 2008/10/23 00:31:15 delphij Exp $
27*86d7f5d3SJohn Marino  */
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino #include <sys/time.h>
30*86d7f5d3SJohn Marino #include <assert.h>
31*86d7f5d3SJohn Marino #include <stdlib.h>
32*86d7f5d3SJohn Marino #include <string.h>
33*86d7f5d3SJohn Marino #include "cachelib.h"
34*86d7f5d3SJohn Marino #include "debug.h"
35*86d7f5d3SJohn Marino 
36*86d7f5d3SJohn Marino #define INITIAL_ENTRIES_CAPACITY 32
37*86d7f5d3SJohn Marino #define ENTRIES_CAPACITY_STEP 32
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino #define STRING_SIMPLE_HASH_BODY(in_var, var, a, M)		\
40*86d7f5d3SJohn Marino 	for ((var) = 0; *(in_var) != '\0'; ++(in_var))		\
41*86d7f5d3SJohn Marino 		(var) = ((a)*(var) + *(in_var)) % (M)
42*86d7f5d3SJohn Marino 
43*86d7f5d3SJohn Marino #define STRING_SIMPLE_MP2_HASH_BODY(in_var, var, a, M)		\
44*86d7f5d3SJohn Marino 	for ((var) = 0; *(in_var) != 0; ++(in_var))		\
45*86d7f5d3SJohn Marino 		(var) = ((a)*(var) + *(in_var)) & (M - 1)
46*86d7f5d3SJohn Marino 
47*86d7f5d3SJohn Marino static int cache_elemsize_common_continue_func(struct cache_common_entry_ *,
48*86d7f5d3SJohn Marino 	struct cache_policy_item_ *);
49*86d7f5d3SJohn Marino static int cache_lifetime_common_continue_func(struct cache_common_entry_ *,
50*86d7f5d3SJohn Marino 	struct cache_policy_item_ *);
51*86d7f5d3SJohn Marino static void clear_cache_entry(struct cache_entry_ *);
52*86d7f5d3SJohn Marino static void destroy_cache_entry(struct cache_entry_ *);
53*86d7f5d3SJohn Marino static void destroy_cache_mp_read_session(struct cache_mp_read_session_ *);
54*86d7f5d3SJohn Marino static void destroy_cache_mp_write_session(struct cache_mp_write_session_ *);
55*86d7f5d3SJohn Marino static int entries_bsearch_cmp_func(const void *, const void *);
56*86d7f5d3SJohn Marino static int entries_qsort_cmp_func(const void *, const void *);
57*86d7f5d3SJohn Marino static struct cache_entry_ ** find_cache_entry_p(struct cache_ *,
58*86d7f5d3SJohn Marino 	const char *);
59*86d7f5d3SJohn Marino static void flush_cache_entry(struct cache_entry_ *);
60*86d7f5d3SJohn Marino static void flush_cache_policy(struct cache_common_entry_ *,
61*86d7f5d3SJohn Marino 	struct cache_policy_ *, struct cache_policy_ *,
62*86d7f5d3SJohn Marino 		int (*)(struct cache_common_entry_ *,
63*86d7f5d3SJohn Marino 		struct cache_policy_item_ *));
64*86d7f5d3SJohn Marino static int ht_items_cmp_func(const void *, const void *);
65*86d7f5d3SJohn Marino static int ht_items_fixed_size_left_cmp_func(const void *, const void *);
66*86d7f5d3SJohn Marino static hashtable_index_t ht_item_hash_func(const void *, size_t);
67*86d7f5d3SJohn Marino 
68*86d7f5d3SJohn Marino /*
69*86d7f5d3SJohn Marino  * Hashing and comparing routines, that are used with the hash tables
70*86d7f5d3SJohn Marino  */
71*86d7f5d3SJohn Marino static int
ht_items_cmp_func(const void * p1,const void * p2)72*86d7f5d3SJohn Marino ht_items_cmp_func(const void *p1, const void *p2)
73*86d7f5d3SJohn Marino {
74*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *hp1, *hp2;
75*86d7f5d3SJohn Marino 	size_t min_size;
76*86d7f5d3SJohn Marino 	int result;
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino 	hp1 = (struct cache_ht_item_data_ *)p1;
79*86d7f5d3SJohn Marino 	hp2 = (struct cache_ht_item_data_ *)p2;
80*86d7f5d3SJohn Marino 
81*86d7f5d3SJohn Marino 	assert(hp1->key != NULL);
82*86d7f5d3SJohn Marino 	assert(hp2->key != NULL);
83*86d7f5d3SJohn Marino 
84*86d7f5d3SJohn Marino 	if (hp1->key_size != hp2->key_size) {
85*86d7f5d3SJohn Marino 		min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size :
86*86d7f5d3SJohn Marino 			hp2->key_size;
87*86d7f5d3SJohn Marino 		result = memcmp(hp1->key, hp2->key, min_size);
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino 		if (result == 0)
90*86d7f5d3SJohn Marino 			return ((hp1->key_size < hp2->key_size) ? -1 : 1);
91*86d7f5d3SJohn Marino 		else
92*86d7f5d3SJohn Marino 			return (result);
93*86d7f5d3SJohn Marino 	} else
94*86d7f5d3SJohn Marino 		return (memcmp(hp1->key, hp2->key, hp1->key_size));
95*86d7f5d3SJohn Marino }
96*86d7f5d3SJohn Marino 
97*86d7f5d3SJohn Marino static int
ht_items_fixed_size_left_cmp_func(const void * p1,const void * p2)98*86d7f5d3SJohn Marino ht_items_fixed_size_left_cmp_func(const void *p1, const void *p2)
99*86d7f5d3SJohn Marino {
100*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *hp1, *hp2;
101*86d7f5d3SJohn Marino 	size_t min_size;
102*86d7f5d3SJohn Marino 	int result;
103*86d7f5d3SJohn Marino 
104*86d7f5d3SJohn Marino 	hp1 = (struct cache_ht_item_data_ *)p1;
105*86d7f5d3SJohn Marino 	hp2 = (struct cache_ht_item_data_ *)p2;
106*86d7f5d3SJohn Marino 
107*86d7f5d3SJohn Marino 	assert(hp1->key != NULL);
108*86d7f5d3SJohn Marino 	assert(hp2->key != NULL);
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino 	if (hp1->key_size != hp2->key_size) {
111*86d7f5d3SJohn Marino 		min_size = (hp1->key_size < hp2->key_size) ? hp1->key_size :
112*86d7f5d3SJohn Marino 			hp2->key_size;
113*86d7f5d3SJohn Marino 		result = memcmp(hp1->key, hp2->key, min_size);
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino 		if (result == 0)
116*86d7f5d3SJohn Marino 			if (min_size == hp1->key_size)
117*86d7f5d3SJohn Marino 			    return (0);
118*86d7f5d3SJohn Marino 			else
119*86d7f5d3SJohn Marino 			    return ((hp1->key_size < hp2->key_size) ? -1 : 1);
120*86d7f5d3SJohn Marino 		else
121*86d7f5d3SJohn Marino 			return (result);
122*86d7f5d3SJohn Marino 	} else
123*86d7f5d3SJohn Marino 		return (memcmp(hp1->key, hp2->key, hp1->key_size));
124*86d7f5d3SJohn Marino }
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino static hashtable_index_t
ht_item_hash_func(const void * p,size_t cache_entries_size)127*86d7f5d3SJohn Marino ht_item_hash_func(const void *p, size_t cache_entries_size)
128*86d7f5d3SJohn Marino {
129*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *hp;
130*86d7f5d3SJohn Marino 	size_t i;
131*86d7f5d3SJohn Marino 
132*86d7f5d3SJohn Marino 	hashtable_index_t retval;
133*86d7f5d3SJohn Marino 
134*86d7f5d3SJohn Marino 	hp = (struct cache_ht_item_data_ *)p;
135*86d7f5d3SJohn Marino 	assert(hp->key != NULL);
136*86d7f5d3SJohn Marino 
137*86d7f5d3SJohn Marino 	retval = 0;
138*86d7f5d3SJohn Marino 	for (i = 0; i < hp->key_size; ++i)
139*86d7f5d3SJohn Marino 	    retval = (127 * retval + (unsigned char)hp->key[i]) %
140*86d7f5d3SJohn Marino 		cache_entries_size;
141*86d7f5d3SJohn Marino 
142*86d7f5d3SJohn Marino 	return retval;
143*86d7f5d3SJohn Marino }
144*86d7f5d3SJohn Marino 
145*86d7f5d3SJohn Marino HASHTABLE_GENERATE(cache_ht_, cache_ht_item_, struct cache_ht_item_data_, data,
146*86d7f5d3SJohn Marino 	ht_item_hash_func, ht_items_cmp_func);
147*86d7f5d3SJohn Marino 
148*86d7f5d3SJohn Marino /*
149*86d7f5d3SJohn Marino  * Routines to sort and search the entries by name
150*86d7f5d3SJohn Marino  */
151*86d7f5d3SJohn Marino static int
entries_bsearch_cmp_func(const void * key,const void * ent)152*86d7f5d3SJohn Marino entries_bsearch_cmp_func(const void *key, const void *ent)
153*86d7f5d3SJohn Marino {
154*86d7f5d3SJohn Marino 
155*86d7f5d3SJohn Marino 	assert(key != NULL);
156*86d7f5d3SJohn Marino 	assert(ent != NULL);
157*86d7f5d3SJohn Marino 
158*86d7f5d3SJohn Marino 	return (strcmp((char const *)key,
159*86d7f5d3SJohn Marino 		(*(struct cache_entry_ const **)ent)->name));
160*86d7f5d3SJohn Marino }
161*86d7f5d3SJohn Marino 
162*86d7f5d3SJohn Marino static int
entries_qsort_cmp_func(const void * e1,const void * e2)163*86d7f5d3SJohn Marino entries_qsort_cmp_func(const void *e1, const void *e2)
164*86d7f5d3SJohn Marino {
165*86d7f5d3SJohn Marino 
166*86d7f5d3SJohn Marino 	assert(e1 != NULL);
167*86d7f5d3SJohn Marino 	assert(e2 != NULL);
168*86d7f5d3SJohn Marino 
169*86d7f5d3SJohn Marino 	return (strcmp((*(struct cache_entry_ const **)e1)->name,
170*86d7f5d3SJohn Marino 		(*(struct cache_entry_ const **)e2)->name));
171*86d7f5d3SJohn Marino }
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino static struct cache_entry_ **
find_cache_entry_p(struct cache_ * the_cache,const char * entry_name)174*86d7f5d3SJohn Marino find_cache_entry_p(struct cache_ *the_cache, const char *entry_name)
175*86d7f5d3SJohn Marino {
176*86d7f5d3SJohn Marino 
177*86d7f5d3SJohn Marino 	return ((struct cache_entry_ **)(bsearch(entry_name, the_cache->entries,
178*86d7f5d3SJohn Marino 		the_cache->entries_size, sizeof(struct cache_entry_ *),
179*86d7f5d3SJohn Marino 		entries_bsearch_cmp_func)));
180*86d7f5d3SJohn Marino }
181*86d7f5d3SJohn Marino 
182*86d7f5d3SJohn Marino static void
destroy_cache_mp_write_session(struct cache_mp_write_session_ * ws)183*86d7f5d3SJohn Marino destroy_cache_mp_write_session(struct cache_mp_write_session_ *ws)
184*86d7f5d3SJohn Marino {
185*86d7f5d3SJohn Marino 
186*86d7f5d3SJohn Marino 	struct cache_mp_data_item_	*data_item;
187*86d7f5d3SJohn Marino 
188*86d7f5d3SJohn Marino 	TRACE_IN(destroy_cache_mp_write_session);
189*86d7f5d3SJohn Marino 	assert(ws != NULL);
190*86d7f5d3SJohn Marino 	while (!TAILQ_EMPTY(&ws->items)) {
191*86d7f5d3SJohn Marino 		data_item = TAILQ_FIRST(&ws->items);
192*86d7f5d3SJohn Marino 		TAILQ_REMOVE(&ws->items, data_item, entries);
193*86d7f5d3SJohn Marino 		free(data_item->value);
194*86d7f5d3SJohn Marino 		free(data_item);
195*86d7f5d3SJohn Marino 	}
196*86d7f5d3SJohn Marino 
197*86d7f5d3SJohn Marino 	free(ws);
198*86d7f5d3SJohn Marino 	TRACE_OUT(destroy_cache_mp_write_session);
199*86d7f5d3SJohn Marino }
200*86d7f5d3SJohn Marino 
201*86d7f5d3SJohn Marino static void
destroy_cache_mp_read_session(struct cache_mp_read_session_ * rs)202*86d7f5d3SJohn Marino destroy_cache_mp_read_session(struct cache_mp_read_session_ *rs)
203*86d7f5d3SJohn Marino {
204*86d7f5d3SJohn Marino 
205*86d7f5d3SJohn Marino 	TRACE_IN(destroy_cache_mp_read_session);
206*86d7f5d3SJohn Marino 	assert(rs != NULL);
207*86d7f5d3SJohn Marino 	free(rs);
208*86d7f5d3SJohn Marino 	TRACE_OUT(destroy_cache_mp_read_session);
209*86d7f5d3SJohn Marino }
210*86d7f5d3SJohn Marino 
211*86d7f5d3SJohn Marino static void
destroy_cache_entry(struct cache_entry_ * entry)212*86d7f5d3SJohn Marino destroy_cache_entry(struct cache_entry_ *entry)
213*86d7f5d3SJohn Marino {
214*86d7f5d3SJohn Marino 	struct cache_common_entry_	*common_entry;
215*86d7f5d3SJohn Marino 	struct cache_mp_entry_		*mp_entry;
216*86d7f5d3SJohn Marino 	struct cache_mp_read_session_	*rs;
217*86d7f5d3SJohn Marino 	struct cache_mp_write_session_	*ws;
218*86d7f5d3SJohn Marino 	struct cache_ht_item_ *ht_item;
219*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *ht_item_data;
220*86d7f5d3SJohn Marino 
221*86d7f5d3SJohn Marino 	TRACE_IN(destroy_cache_entry);
222*86d7f5d3SJohn Marino 	assert(entry != NULL);
223*86d7f5d3SJohn Marino 
224*86d7f5d3SJohn Marino 	if (entry->params->entry_type == CET_COMMON) {
225*86d7f5d3SJohn Marino 		common_entry = (struct cache_common_entry_ *)entry;
226*86d7f5d3SJohn Marino 
227*86d7f5d3SJohn Marino 		HASHTABLE_FOREACH(&(common_entry->items), ht_item) {
228*86d7f5d3SJohn Marino 			HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data)
229*86d7f5d3SJohn Marino 			{
230*86d7f5d3SJohn Marino 				free(ht_item_data->key);
231*86d7f5d3SJohn Marino 				free(ht_item_data->value);
232*86d7f5d3SJohn Marino 			}
233*86d7f5d3SJohn Marino 			HASHTABLE_ENTRY_CLEAR(ht_item, data);
234*86d7f5d3SJohn Marino 		}
235*86d7f5d3SJohn Marino 
236*86d7f5d3SJohn Marino 		HASHTABLE_DESTROY(&(common_entry->items), data);
237*86d7f5d3SJohn Marino 
238*86d7f5d3SJohn Marino 		/* FIFO policy is always first */
239*86d7f5d3SJohn Marino 		destroy_cache_fifo_policy(common_entry->policies[0]);
240*86d7f5d3SJohn Marino 		switch (common_entry->common_params.policy) {
241*86d7f5d3SJohn Marino 		case CPT_LRU:
242*86d7f5d3SJohn Marino 			destroy_cache_lru_policy(common_entry->policies[1]);
243*86d7f5d3SJohn Marino 			break;
244*86d7f5d3SJohn Marino 		case CPT_LFU:
245*86d7f5d3SJohn Marino 			destroy_cache_lfu_policy(common_entry->policies[1]);
246*86d7f5d3SJohn Marino 			break;
247*86d7f5d3SJohn Marino 		default:
248*86d7f5d3SJohn Marino 		break;
249*86d7f5d3SJohn Marino 		}
250*86d7f5d3SJohn Marino 		free(common_entry->policies);
251*86d7f5d3SJohn Marino 	} else {
252*86d7f5d3SJohn Marino 		mp_entry = (struct cache_mp_entry_ *)entry;
253*86d7f5d3SJohn Marino 
254*86d7f5d3SJohn Marino 		while (!TAILQ_EMPTY(&mp_entry->ws_head)) {
255*86d7f5d3SJohn Marino 			ws = TAILQ_FIRST(&mp_entry->ws_head);
256*86d7f5d3SJohn Marino 			TAILQ_REMOVE(&mp_entry->ws_head, ws, entries);
257*86d7f5d3SJohn Marino 			destroy_cache_mp_write_session(ws);
258*86d7f5d3SJohn Marino 		}
259*86d7f5d3SJohn Marino 
260*86d7f5d3SJohn Marino 		while (!TAILQ_EMPTY(&mp_entry->rs_head)) {
261*86d7f5d3SJohn Marino 			rs = TAILQ_FIRST(&mp_entry->rs_head);
262*86d7f5d3SJohn Marino 			TAILQ_REMOVE(&mp_entry->rs_head, rs, entries);
263*86d7f5d3SJohn Marino 			destroy_cache_mp_read_session(rs);
264*86d7f5d3SJohn Marino 		}
265*86d7f5d3SJohn Marino 
266*86d7f5d3SJohn Marino 		if (mp_entry->completed_write_session != NULL)
267*86d7f5d3SJohn Marino 			destroy_cache_mp_write_session(
268*86d7f5d3SJohn Marino 				mp_entry->completed_write_session);
269*86d7f5d3SJohn Marino 
270*86d7f5d3SJohn Marino 		if (mp_entry->pending_write_session != NULL)
271*86d7f5d3SJohn Marino 			destroy_cache_mp_write_session(
272*86d7f5d3SJohn Marino 				mp_entry->pending_write_session);
273*86d7f5d3SJohn Marino 	}
274*86d7f5d3SJohn Marino 
275*86d7f5d3SJohn Marino 	free(entry->name);
276*86d7f5d3SJohn Marino 	free(entry);
277*86d7f5d3SJohn Marino 	TRACE_OUT(destroy_cache_entry);
278*86d7f5d3SJohn Marino }
279*86d7f5d3SJohn Marino 
280*86d7f5d3SJohn Marino static void
clear_cache_entry(struct cache_entry_ * entry)281*86d7f5d3SJohn Marino clear_cache_entry(struct cache_entry_ *entry)
282*86d7f5d3SJohn Marino {
283*86d7f5d3SJohn Marino 	struct cache_mp_entry_		*mp_entry;
284*86d7f5d3SJohn Marino 	struct cache_common_entry_	*common_entry;
285*86d7f5d3SJohn Marino 	struct cache_ht_item_ *ht_item;
286*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *ht_item_data;
287*86d7f5d3SJohn Marino 	struct cache_policy_ *policy;
288*86d7f5d3SJohn Marino 	struct cache_policy_item_ *item, *next_item;
289*86d7f5d3SJohn Marino 	size_t entry_size;
290*86d7f5d3SJohn Marino 	int i;
291*86d7f5d3SJohn Marino 
292*86d7f5d3SJohn Marino 	if (entry->params->entry_type == CET_COMMON) {
293*86d7f5d3SJohn Marino 		common_entry = (struct cache_common_entry_ *)entry;
294*86d7f5d3SJohn Marino 
295*86d7f5d3SJohn Marino 		entry_size = 0;
296*86d7f5d3SJohn Marino 		HASHTABLE_FOREACH(&(common_entry->items), ht_item) {
297*86d7f5d3SJohn Marino 			HASHTABLE_ENTRY_FOREACH(ht_item, data, ht_item_data)
298*86d7f5d3SJohn Marino 			{
299*86d7f5d3SJohn Marino 				free(ht_item_data->key);
300*86d7f5d3SJohn Marino 				free(ht_item_data->value);
301*86d7f5d3SJohn Marino 			}
302*86d7f5d3SJohn Marino 			entry_size += HASHTABLE_ENTRY_SIZE(ht_item, data);
303*86d7f5d3SJohn Marino 			HASHTABLE_ENTRY_CLEAR(ht_item, data);
304*86d7f5d3SJohn Marino 		}
305*86d7f5d3SJohn Marino 
306*86d7f5d3SJohn Marino 		common_entry->items_size -= entry_size;
307*86d7f5d3SJohn Marino 		for (i = 0; i < common_entry->policies_size; ++i) {
308*86d7f5d3SJohn Marino 			policy = common_entry->policies[i];
309*86d7f5d3SJohn Marino 
310*86d7f5d3SJohn Marino 			next_item = NULL;
311*86d7f5d3SJohn Marino 			item = policy->get_first_item_func(policy);
312*86d7f5d3SJohn Marino 			while (item != NULL) {
313*86d7f5d3SJohn Marino 				next_item = policy->get_next_item_func(policy,
314*86d7f5d3SJohn Marino 					item);
315*86d7f5d3SJohn Marino 				policy->remove_item_func(policy, item);
316*86d7f5d3SJohn Marino 				policy->destroy_item_func(item);
317*86d7f5d3SJohn Marino 				item = next_item;
318*86d7f5d3SJohn Marino 			}
319*86d7f5d3SJohn Marino 		}
320*86d7f5d3SJohn Marino 	} else {
321*86d7f5d3SJohn Marino 		mp_entry = (struct cache_mp_entry_ *)entry;
322*86d7f5d3SJohn Marino 
323*86d7f5d3SJohn Marino 		if (mp_entry->rs_size == 0) {
324*86d7f5d3SJohn Marino 			if (mp_entry->completed_write_session != NULL) {
325*86d7f5d3SJohn Marino 				destroy_cache_mp_write_session(
326*86d7f5d3SJohn Marino 					mp_entry->completed_write_session);
327*86d7f5d3SJohn Marino 				mp_entry->completed_write_session = NULL;
328*86d7f5d3SJohn Marino 			}
329*86d7f5d3SJohn Marino 
330*86d7f5d3SJohn Marino 			memset(&mp_entry->creation_time, 0,
331*86d7f5d3SJohn Marino 				sizeof(struct timeval));
332*86d7f5d3SJohn Marino 			memset(&mp_entry->last_request_time, 0,
333*86d7f5d3SJohn Marino 				sizeof(struct timeval));
334*86d7f5d3SJohn Marino 		}
335*86d7f5d3SJohn Marino 	}
336*86d7f5d3SJohn Marino }
337*86d7f5d3SJohn Marino 
338*86d7f5d3SJohn Marino /*
339*86d7f5d3SJohn Marino  * When passed to the flush_cache_policy, ensures that all old elements are
340*86d7f5d3SJohn Marino  * deleted.
341*86d7f5d3SJohn Marino  */
342*86d7f5d3SJohn Marino static int
cache_lifetime_common_continue_func(struct cache_common_entry_ * entry,struct cache_policy_item_ * item)343*86d7f5d3SJohn Marino cache_lifetime_common_continue_func(struct cache_common_entry_ *entry,
344*86d7f5d3SJohn Marino 	struct cache_policy_item_ *item)
345*86d7f5d3SJohn Marino {
346*86d7f5d3SJohn Marino 
347*86d7f5d3SJohn Marino 	return ((item->last_request_time.tv_sec - item->creation_time.tv_sec >
348*86d7f5d3SJohn Marino 		entry->common_params.max_lifetime.tv_sec) ? 1: 0);
349*86d7f5d3SJohn Marino }
350*86d7f5d3SJohn Marino 
351*86d7f5d3SJohn Marino /*
352*86d7f5d3SJohn Marino  * When passed to the flush_cache_policy, ensures that all elements, that
353*86d7f5d3SJohn Marino  * exceed the size limit, are deleted.
354*86d7f5d3SJohn Marino  */
355*86d7f5d3SJohn Marino static int
cache_elemsize_common_continue_func(struct cache_common_entry_ * entry,struct cache_policy_item_ * item)356*86d7f5d3SJohn Marino cache_elemsize_common_continue_func(struct cache_common_entry_ *entry,
357*86d7f5d3SJohn Marino 	struct cache_policy_item_ *item)
358*86d7f5d3SJohn Marino {
359*86d7f5d3SJohn Marino 
360*86d7f5d3SJohn Marino 	return ((entry->items_size > entry->common_params.satisf_elemsize) ? 1
361*86d7f5d3SJohn Marino 		: 0);
362*86d7f5d3SJohn Marino }
363*86d7f5d3SJohn Marino 
364*86d7f5d3SJohn Marino /*
365*86d7f5d3SJohn Marino  * Removes the elements from the cache entry, while the continue_func returns 1.
366*86d7f5d3SJohn Marino  */
367*86d7f5d3SJohn Marino static void
flush_cache_policy(struct cache_common_entry_ * entry,struct cache_policy_ * policy,struct cache_policy_ * connected_policy,int (* continue_func)(struct cache_common_entry_ *,struct cache_policy_item_ *))368*86d7f5d3SJohn Marino flush_cache_policy(struct cache_common_entry_ *entry,
369*86d7f5d3SJohn Marino 	struct cache_policy_ *policy,
370*86d7f5d3SJohn Marino 	struct cache_policy_ *connected_policy,
371*86d7f5d3SJohn Marino 	int (*continue_func)(struct cache_common_entry_ *,
372*86d7f5d3SJohn Marino 		struct cache_policy_item_ *))
373*86d7f5d3SJohn Marino {
374*86d7f5d3SJohn Marino 	struct cache_policy_item_ *item, *next_item, *connected_item;
375*86d7f5d3SJohn Marino 	struct cache_ht_item_ *ht_item;
376*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *ht_item_data, ht_key;
377*86d7f5d3SJohn Marino 	hashtable_index_t hash;
378*86d7f5d3SJohn Marino 
379*86d7f5d3SJohn Marino 	assert(policy != NULL);
380*86d7f5d3SJohn Marino 
381*86d7f5d3SJohn Marino 	next_item = NULL;
382*86d7f5d3SJohn Marino 	item = policy->get_first_item_func(policy);
383*86d7f5d3SJohn Marino 	while ((item != NULL) && (continue_func(entry, item) == 1)) {
384*86d7f5d3SJohn Marino 		next_item = policy->get_next_item_func(policy, item);
385*86d7f5d3SJohn Marino 
386*86d7f5d3SJohn Marino 		connected_item = item->connected_item;
387*86d7f5d3SJohn Marino 		policy->remove_item_func(policy, item);
388*86d7f5d3SJohn Marino 
389*86d7f5d3SJohn Marino 		memset(&ht_key, 0, sizeof(struct cache_ht_item_data_));
390*86d7f5d3SJohn Marino 		ht_key.key = item->key;
391*86d7f5d3SJohn Marino 		ht_key.key_size = item->key_size;
392*86d7f5d3SJohn Marino 
393*86d7f5d3SJohn Marino 		hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &entry->items,
394*86d7f5d3SJohn Marino 			&ht_key);
395*86d7f5d3SJohn Marino 		assert(hash >= 0);
396*86d7f5d3SJohn Marino 		assert(hash < HASHTABLE_ENTRIES_COUNT(&entry->items));
397*86d7f5d3SJohn Marino 
398*86d7f5d3SJohn Marino 		ht_item = HASHTABLE_GET_ENTRY(&(entry->items), hash);
399*86d7f5d3SJohn Marino 		ht_item_data = HASHTABLE_ENTRY_FIND(cache_ht_, ht_item,
400*86d7f5d3SJohn Marino 			&ht_key);
401*86d7f5d3SJohn Marino 		assert(ht_item_data != NULL);
402*86d7f5d3SJohn Marino 		free(ht_item_data->key);
403*86d7f5d3SJohn Marino 		free(ht_item_data->value);
404*86d7f5d3SJohn Marino 		HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item, ht_item_data);
405*86d7f5d3SJohn Marino 		--entry->items_size;
406*86d7f5d3SJohn Marino 
407*86d7f5d3SJohn Marino 		policy->destroy_item_func(item);
408*86d7f5d3SJohn Marino 
409*86d7f5d3SJohn Marino 		if (connected_item != NULL) {
410*86d7f5d3SJohn Marino 			connected_policy->remove_item_func(connected_policy,
411*86d7f5d3SJohn Marino 				connected_item);
412*86d7f5d3SJohn Marino 			connected_policy->destroy_item_func(connected_item);
413*86d7f5d3SJohn Marino 		}
414*86d7f5d3SJohn Marino 
415*86d7f5d3SJohn Marino 		item = next_item;
416*86d7f5d3SJohn Marino 	}
417*86d7f5d3SJohn Marino }
418*86d7f5d3SJohn Marino 
419*86d7f5d3SJohn Marino static void
flush_cache_entry(struct cache_entry_ * entry)420*86d7f5d3SJohn Marino flush_cache_entry(struct cache_entry_ *entry)
421*86d7f5d3SJohn Marino {
422*86d7f5d3SJohn Marino 	struct cache_mp_entry_		*mp_entry;
423*86d7f5d3SJohn Marino 	struct cache_common_entry_	*common_entry;
424*86d7f5d3SJohn Marino 	struct cache_policy_ *policy, *connected_policy;
425*86d7f5d3SJohn Marino 
426*86d7f5d3SJohn Marino 	connected_policy = NULL;
427*86d7f5d3SJohn Marino 	if (entry->params->entry_type == CET_COMMON) {
428*86d7f5d3SJohn Marino 		common_entry = (struct cache_common_entry_ *)entry;
429*86d7f5d3SJohn Marino 		if ((common_entry->common_params.max_lifetime.tv_sec != 0) ||
430*86d7f5d3SJohn Marino 		    (common_entry->common_params.max_lifetime.tv_usec != 0)) {
431*86d7f5d3SJohn Marino 
432*86d7f5d3SJohn Marino 			policy = common_entry->policies[0];
433*86d7f5d3SJohn Marino 			if (common_entry->policies_size > 1)
434*86d7f5d3SJohn Marino 				connected_policy = common_entry->policies[1];
435*86d7f5d3SJohn Marino 
436*86d7f5d3SJohn Marino 			flush_cache_policy(common_entry, policy,
437*86d7f5d3SJohn Marino 				connected_policy,
438*86d7f5d3SJohn Marino 				cache_lifetime_common_continue_func);
439*86d7f5d3SJohn Marino 		}
440*86d7f5d3SJohn Marino 
441*86d7f5d3SJohn Marino 
442*86d7f5d3SJohn Marino 		if ((common_entry->common_params.max_elemsize != 0) &&
443*86d7f5d3SJohn Marino 			common_entry->items_size >
444*86d7f5d3SJohn Marino 			common_entry->common_params.max_elemsize) {
445*86d7f5d3SJohn Marino 
446*86d7f5d3SJohn Marino 			if (common_entry->policies_size > 1) {
447*86d7f5d3SJohn Marino 				policy = common_entry->policies[1];
448*86d7f5d3SJohn Marino 				connected_policy = common_entry->policies[0];
449*86d7f5d3SJohn Marino 			} else {
450*86d7f5d3SJohn Marino 				policy = common_entry->policies[0];
451*86d7f5d3SJohn Marino 				connected_policy = NULL;
452*86d7f5d3SJohn Marino 			}
453*86d7f5d3SJohn Marino 
454*86d7f5d3SJohn Marino 			flush_cache_policy(common_entry, policy,
455*86d7f5d3SJohn Marino 				connected_policy,
456*86d7f5d3SJohn Marino 				cache_elemsize_common_continue_func);
457*86d7f5d3SJohn Marino 		}
458*86d7f5d3SJohn Marino 	} else {
459*86d7f5d3SJohn Marino 		mp_entry = (struct cache_mp_entry_ *)entry;
460*86d7f5d3SJohn Marino 
461*86d7f5d3SJohn Marino 		if ((mp_entry->mp_params.max_lifetime.tv_sec != 0)
462*86d7f5d3SJohn Marino 			|| (mp_entry->mp_params.max_lifetime.tv_usec != 0)) {
463*86d7f5d3SJohn Marino 
464*86d7f5d3SJohn Marino 			if (mp_entry->last_request_time.tv_sec -
465*86d7f5d3SJohn Marino 				mp_entry->last_request_time.tv_sec >
466*86d7f5d3SJohn Marino 				mp_entry->mp_params.max_lifetime.tv_sec)
467*86d7f5d3SJohn Marino 				clear_cache_entry(entry);
468*86d7f5d3SJohn Marino 		}
469*86d7f5d3SJohn Marino 	}
470*86d7f5d3SJohn Marino }
471*86d7f5d3SJohn Marino 
472*86d7f5d3SJohn Marino struct cache_ *
init_cache(struct cache_params const * params)473*86d7f5d3SJohn Marino init_cache(struct cache_params const *params)
474*86d7f5d3SJohn Marino {
475*86d7f5d3SJohn Marino 	struct cache_ *retval;
476*86d7f5d3SJohn Marino 
477*86d7f5d3SJohn Marino 	TRACE_IN(init_cache);
478*86d7f5d3SJohn Marino 	assert(params != NULL);
479*86d7f5d3SJohn Marino 
480*86d7f5d3SJohn Marino 	retval = (struct cache_ *)calloc(1, sizeof(struct cache_));
481*86d7f5d3SJohn Marino 	assert(retval != NULL);
482*86d7f5d3SJohn Marino 
483*86d7f5d3SJohn Marino 	assert(params != NULL);
484*86d7f5d3SJohn Marino 	memcpy(&retval->params, params, sizeof(struct cache_params));
485*86d7f5d3SJohn Marino 
486*86d7f5d3SJohn Marino 	retval->entries = (struct cache_entry_ **)calloc(1,
487*86d7f5d3SJohn Marino 		sizeof(struct cache_entry_ *) * INITIAL_ENTRIES_CAPACITY);
488*86d7f5d3SJohn Marino 	assert(retval->entries != NULL);
489*86d7f5d3SJohn Marino 
490*86d7f5d3SJohn Marino 	retval->entries_capacity = INITIAL_ENTRIES_CAPACITY;
491*86d7f5d3SJohn Marino 	retval->entries_size = 0;
492*86d7f5d3SJohn Marino 
493*86d7f5d3SJohn Marino 	TRACE_OUT(init_cache);
494*86d7f5d3SJohn Marino 	return (retval);
495*86d7f5d3SJohn Marino }
496*86d7f5d3SJohn Marino 
497*86d7f5d3SJohn Marino void
destroy_cache(struct cache_ * the_cache)498*86d7f5d3SJohn Marino destroy_cache(struct cache_ *the_cache)
499*86d7f5d3SJohn Marino {
500*86d7f5d3SJohn Marino 
501*86d7f5d3SJohn Marino 	TRACE_IN(destroy_cache);
502*86d7f5d3SJohn Marino 	assert(the_cache != NULL);
503*86d7f5d3SJohn Marino 
504*86d7f5d3SJohn Marino 	if (the_cache->entries != NULL) {
505*86d7f5d3SJohn Marino 		size_t i;
506*86d7f5d3SJohn Marino 		for (i = 0; i < the_cache->entries_size; ++i)
507*86d7f5d3SJohn Marino 			destroy_cache_entry(the_cache->entries[i]);
508*86d7f5d3SJohn Marino 
509*86d7f5d3SJohn Marino 		free(the_cache->entries);
510*86d7f5d3SJohn Marino 	}
511*86d7f5d3SJohn Marino 
512*86d7f5d3SJohn Marino 	free(the_cache);
513*86d7f5d3SJohn Marino 	TRACE_OUT(destroy_cache);
514*86d7f5d3SJohn Marino }
515*86d7f5d3SJohn Marino 
516*86d7f5d3SJohn Marino int
register_cache_entry(struct cache_ * the_cache,struct cache_entry_params const * params)517*86d7f5d3SJohn Marino register_cache_entry(struct cache_ *the_cache,
518*86d7f5d3SJohn Marino 	struct cache_entry_params const *params)
519*86d7f5d3SJohn Marino {
520*86d7f5d3SJohn Marino 	int policies_size;
521*86d7f5d3SJohn Marino 	size_t entry_name_size;
522*86d7f5d3SJohn Marino 	struct cache_common_entry_	*new_common_entry;
523*86d7f5d3SJohn Marino 	struct cache_mp_entry_		*new_mp_entry;
524*86d7f5d3SJohn Marino 
525*86d7f5d3SJohn Marino 	TRACE_IN(register_cache_entry);
526*86d7f5d3SJohn Marino 	assert(the_cache != NULL);
527*86d7f5d3SJohn Marino 
528*86d7f5d3SJohn Marino 	if (find_cache_entry(the_cache, params->entry_name) != NULL) {
529*86d7f5d3SJohn Marino 		TRACE_OUT(register_cache_entry);
530*86d7f5d3SJohn Marino 		return (-1);
531*86d7f5d3SJohn Marino 	}
532*86d7f5d3SJohn Marino 
533*86d7f5d3SJohn Marino 	if (the_cache->entries_size == the_cache->entries_capacity) {
534*86d7f5d3SJohn Marino 		struct cache_entry_ **new_entries;
535*86d7f5d3SJohn Marino 		size_t	new_capacity;
536*86d7f5d3SJohn Marino 
537*86d7f5d3SJohn Marino 		new_capacity = the_cache->entries_capacity +
538*86d7f5d3SJohn Marino 			ENTRIES_CAPACITY_STEP;
539*86d7f5d3SJohn Marino 		new_entries = (struct cache_entry_ **)calloc(1,
540*86d7f5d3SJohn Marino 			sizeof(struct cache_entry_ *) * new_capacity);
541*86d7f5d3SJohn Marino 		assert(new_entries != NULL);
542*86d7f5d3SJohn Marino 
543*86d7f5d3SJohn Marino 		memcpy(new_entries, the_cache->entries,
544*86d7f5d3SJohn Marino 			sizeof(struct cache_entry_ *)
545*86d7f5d3SJohn Marino 			* the_cache->entries_size);
546*86d7f5d3SJohn Marino 
547*86d7f5d3SJohn Marino 		free(the_cache->entries);
548*86d7f5d3SJohn Marino 		the_cache->entries = new_entries;
549*86d7f5d3SJohn Marino 	}
550*86d7f5d3SJohn Marino 
551*86d7f5d3SJohn Marino 	entry_name_size = strlen(params->entry_name) + 1;
552*86d7f5d3SJohn Marino 	switch (params->entry_type)
553*86d7f5d3SJohn Marino 	{
554*86d7f5d3SJohn Marino 	case CET_COMMON:
555*86d7f5d3SJohn Marino 		new_common_entry = (struct cache_common_entry_ *)calloc(1,
556*86d7f5d3SJohn Marino 			sizeof(struct cache_common_entry_));
557*86d7f5d3SJohn Marino 		assert(new_common_entry != NULL);
558*86d7f5d3SJohn Marino 
559*86d7f5d3SJohn Marino 		memcpy(&new_common_entry->common_params, params,
560*86d7f5d3SJohn Marino 			sizeof(struct common_cache_entry_params));
561*86d7f5d3SJohn Marino 		new_common_entry->params =
562*86d7f5d3SJohn Marino 		  (struct cache_entry_params *)&new_common_entry->common_params;
563*86d7f5d3SJohn Marino 
564*86d7f5d3SJohn Marino 		new_common_entry->common_params.entry_name = (char *)calloc(1,
565*86d7f5d3SJohn Marino 			entry_name_size);
566*86d7f5d3SJohn Marino 		assert(new_common_entry->common_params.entry_name != NULL);
567*86d7f5d3SJohn Marino 		strlcpy(new_common_entry->common_params.entry_name,
568*86d7f5d3SJohn Marino 			params->entry_name, entry_name_size);
569*86d7f5d3SJohn Marino 		new_common_entry->name =
570*86d7f5d3SJohn Marino 			new_common_entry->common_params.entry_name;
571*86d7f5d3SJohn Marino 
572*86d7f5d3SJohn Marino 		HASHTABLE_INIT(&(new_common_entry->items),
573*86d7f5d3SJohn Marino 			struct cache_ht_item_data_, data,
574*86d7f5d3SJohn Marino 			new_common_entry->common_params.cache_entries_size);
575*86d7f5d3SJohn Marino 
576*86d7f5d3SJohn Marino 		if (new_common_entry->common_params.policy == CPT_FIFO)
577*86d7f5d3SJohn Marino 			policies_size = 1;
578*86d7f5d3SJohn Marino 		else
579*86d7f5d3SJohn Marino 			policies_size = 2;
580*86d7f5d3SJohn Marino 
581*86d7f5d3SJohn Marino 		new_common_entry->policies = (struct cache_policy_ **)calloc(1,
582*86d7f5d3SJohn Marino 			sizeof(struct cache_policy_ *) * policies_size);
583*86d7f5d3SJohn Marino 		assert(new_common_entry->policies != NULL);
584*86d7f5d3SJohn Marino 
585*86d7f5d3SJohn Marino 		new_common_entry->policies_size = policies_size;
586*86d7f5d3SJohn Marino 		new_common_entry->policies[0] = init_cache_fifo_policy();
587*86d7f5d3SJohn Marino 
588*86d7f5d3SJohn Marino 		if (policies_size > 1) {
589*86d7f5d3SJohn Marino 			switch (new_common_entry->common_params.policy) {
590*86d7f5d3SJohn Marino 			case CPT_LRU:
591*86d7f5d3SJohn Marino 				new_common_entry->policies[1] =
592*86d7f5d3SJohn Marino 					init_cache_lru_policy();
593*86d7f5d3SJohn Marino 			break;
594*86d7f5d3SJohn Marino 			case CPT_LFU:
595*86d7f5d3SJohn Marino 				new_common_entry->policies[1] =
596*86d7f5d3SJohn Marino 					init_cache_lfu_policy();
597*86d7f5d3SJohn Marino 			break;
598*86d7f5d3SJohn Marino 			default:
599*86d7f5d3SJohn Marino 			break;
600*86d7f5d3SJohn Marino 			}
601*86d7f5d3SJohn Marino 		}
602*86d7f5d3SJohn Marino 
603*86d7f5d3SJohn Marino 		new_common_entry->get_time_func =
604*86d7f5d3SJohn Marino 			the_cache->params.get_time_func;
605*86d7f5d3SJohn Marino 		the_cache->entries[the_cache->entries_size++] =
606*86d7f5d3SJohn Marino 			(struct cache_entry_ *)new_common_entry;
607*86d7f5d3SJohn Marino 		break;
608*86d7f5d3SJohn Marino 	case CET_MULTIPART:
609*86d7f5d3SJohn Marino 		new_mp_entry = (struct cache_mp_entry_ *)calloc(1,
610*86d7f5d3SJohn Marino 			sizeof(struct cache_mp_entry_));
611*86d7f5d3SJohn Marino 		assert(new_mp_entry != NULL);
612*86d7f5d3SJohn Marino 
613*86d7f5d3SJohn Marino 		memcpy(&new_mp_entry->mp_params, params,
614*86d7f5d3SJohn Marino 			sizeof(struct mp_cache_entry_params));
615*86d7f5d3SJohn Marino 		new_mp_entry->params =
616*86d7f5d3SJohn Marino 			(struct cache_entry_params *)&new_mp_entry->mp_params;
617*86d7f5d3SJohn Marino 
618*86d7f5d3SJohn Marino 		new_mp_entry->mp_params.entry_name = (char *)calloc(1,
619*86d7f5d3SJohn Marino 			entry_name_size);
620*86d7f5d3SJohn Marino 		assert(new_mp_entry->mp_params.entry_name != NULL);
621*86d7f5d3SJohn Marino 		strlcpy(new_mp_entry->mp_params.entry_name, params->entry_name,
622*86d7f5d3SJohn Marino 			entry_name_size);
623*86d7f5d3SJohn Marino 		new_mp_entry->name = new_mp_entry->mp_params.entry_name;
624*86d7f5d3SJohn Marino 
625*86d7f5d3SJohn Marino 		TAILQ_INIT(&new_mp_entry->ws_head);
626*86d7f5d3SJohn Marino 		TAILQ_INIT(&new_mp_entry->rs_head);
627*86d7f5d3SJohn Marino 
628*86d7f5d3SJohn Marino 		new_mp_entry->get_time_func = the_cache->params.get_time_func;
629*86d7f5d3SJohn Marino 		the_cache->entries[the_cache->entries_size++] =
630*86d7f5d3SJohn Marino 			(struct cache_entry_ *)new_mp_entry;
631*86d7f5d3SJohn Marino 		break;
632*86d7f5d3SJohn Marino 	}
633*86d7f5d3SJohn Marino 
634*86d7f5d3SJohn Marino 
635*86d7f5d3SJohn Marino 	qsort(the_cache->entries, the_cache->entries_size,
636*86d7f5d3SJohn Marino 		sizeof(struct cache_entry_ *), entries_qsort_cmp_func);
637*86d7f5d3SJohn Marino 
638*86d7f5d3SJohn Marino 	TRACE_OUT(register_cache_entry);
639*86d7f5d3SJohn Marino 	return (0);
640*86d7f5d3SJohn Marino }
641*86d7f5d3SJohn Marino 
642*86d7f5d3SJohn Marino int
unregister_cache_entry(struct cache_ * the_cache,const char * entry_name)643*86d7f5d3SJohn Marino unregister_cache_entry(struct cache_ *the_cache, const char *entry_name)
644*86d7f5d3SJohn Marino {
645*86d7f5d3SJohn Marino 	struct cache_entry_ **del_ent;
646*86d7f5d3SJohn Marino 
647*86d7f5d3SJohn Marino 	TRACE_IN(unregister_cache_entry);
648*86d7f5d3SJohn Marino 	assert(the_cache != NULL);
649*86d7f5d3SJohn Marino 
650*86d7f5d3SJohn Marino 	del_ent = find_cache_entry_p(the_cache, entry_name);
651*86d7f5d3SJohn Marino 	if (del_ent != NULL) {
652*86d7f5d3SJohn Marino 		destroy_cache_entry(*del_ent);
653*86d7f5d3SJohn Marino 		--the_cache->entries_size;
654*86d7f5d3SJohn Marino 
655*86d7f5d3SJohn Marino 		memmove(del_ent, del_ent + 1,
656*86d7f5d3SJohn Marino 			(&(the_cache->entries[--the_cache->entries_size]) -
657*86d7f5d3SJohn Marino 			del_ent) * sizeof(struct cache_entry_ *));
658*86d7f5d3SJohn Marino 
659*86d7f5d3SJohn Marino 		TRACE_OUT(unregister_cache_entry);
660*86d7f5d3SJohn Marino 		return (0);
661*86d7f5d3SJohn Marino 	} else {
662*86d7f5d3SJohn Marino 		TRACE_OUT(unregister_cache_entry);
663*86d7f5d3SJohn Marino 		return (-1);
664*86d7f5d3SJohn Marino 	}
665*86d7f5d3SJohn Marino }
666*86d7f5d3SJohn Marino 
667*86d7f5d3SJohn Marino struct cache_entry_ *
find_cache_entry(struct cache_ * the_cache,const char * entry_name)668*86d7f5d3SJohn Marino find_cache_entry(struct cache_ *the_cache, const char *entry_name)
669*86d7f5d3SJohn Marino {
670*86d7f5d3SJohn Marino 	struct cache_entry_ **result;
671*86d7f5d3SJohn Marino 
672*86d7f5d3SJohn Marino 	TRACE_IN(find_cache_entry);
673*86d7f5d3SJohn Marino 	result = find_cache_entry_p(the_cache, entry_name);
674*86d7f5d3SJohn Marino 
675*86d7f5d3SJohn Marino 	if (result == NULL) {
676*86d7f5d3SJohn Marino 		TRACE_OUT(find_cache_entry);
677*86d7f5d3SJohn Marino 		return (NULL);
678*86d7f5d3SJohn Marino 	} else {
679*86d7f5d3SJohn Marino 		TRACE_OUT(find_cache_entry);
680*86d7f5d3SJohn Marino 		return (*result);
681*86d7f5d3SJohn Marino 	}
682*86d7f5d3SJohn Marino }
683*86d7f5d3SJohn Marino 
684*86d7f5d3SJohn Marino /*
685*86d7f5d3SJohn Marino  * Tries to read the element with the specified key from the cache. If the
686*86d7f5d3SJohn Marino  * value_size is too small, it will be filled with the proper number, and
687*86d7f5d3SJohn Marino  * the user will need to call cache_read again with the value buffer, that
688*86d7f5d3SJohn Marino  * is large enough.
689*86d7f5d3SJohn Marino  * Function returns 0 on success, -1 on error, and -2 if the value_size is too
690*86d7f5d3SJohn Marino  * small.
691*86d7f5d3SJohn Marino  */
692*86d7f5d3SJohn Marino int
cache_read(struct cache_entry_ * entry,const char * key,size_t key_size,char * value,size_t * value_size)693*86d7f5d3SJohn Marino cache_read(struct cache_entry_ *entry, const char *key, size_t key_size,
694*86d7f5d3SJohn Marino 	char *value, size_t *value_size)
695*86d7f5d3SJohn Marino {
696*86d7f5d3SJohn Marino 	struct cache_common_entry_	*common_entry;
697*86d7f5d3SJohn Marino 	struct cache_ht_item_data_	item_data, *find_res;
698*86d7f5d3SJohn Marino 	struct cache_ht_item_		*item;
699*86d7f5d3SJohn Marino 	hashtable_index_t	hash;
700*86d7f5d3SJohn Marino 	struct cache_policy_item_ *connected_item;
701*86d7f5d3SJohn Marino 
702*86d7f5d3SJohn Marino 	TRACE_IN(cache_read);
703*86d7f5d3SJohn Marino 	assert(entry != NULL);
704*86d7f5d3SJohn Marino 	assert(key != NULL);
705*86d7f5d3SJohn Marino 	assert(value_size != NULL);
706*86d7f5d3SJohn Marino 	assert(entry->params->entry_type == CET_COMMON);
707*86d7f5d3SJohn Marino 
708*86d7f5d3SJohn Marino 	common_entry = (struct cache_common_entry_ *)entry;
709*86d7f5d3SJohn Marino 
710*86d7f5d3SJohn Marino 	memset(&item_data, 0, sizeof(struct cache_ht_item_data_));
711*86d7f5d3SJohn Marino 	/* can't avoid the cast here */
712*86d7f5d3SJohn Marino 	item_data.key = (char *)key;
713*86d7f5d3SJohn Marino 	item_data.key_size = key_size;
714*86d7f5d3SJohn Marino 
715*86d7f5d3SJohn Marino 	hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items,
716*86d7f5d3SJohn Marino 		&item_data);
717*86d7f5d3SJohn Marino 	assert(hash >= 0);
718*86d7f5d3SJohn Marino 	assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items));
719*86d7f5d3SJohn Marino 
720*86d7f5d3SJohn Marino 	item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash);
721*86d7f5d3SJohn Marino 	find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data);
722*86d7f5d3SJohn Marino 	if (find_res == NULL) {
723*86d7f5d3SJohn Marino 		TRACE_OUT(cache_read);
724*86d7f5d3SJohn Marino 		return (-1);
725*86d7f5d3SJohn Marino 	}
726*86d7f5d3SJohn Marino 
727*86d7f5d3SJohn Marino 	if ((common_entry->common_params.max_lifetime.tv_sec != 0) ||
728*86d7f5d3SJohn Marino 		(common_entry->common_params.max_lifetime.tv_usec != 0)) {
729*86d7f5d3SJohn Marino 
730*86d7f5d3SJohn Marino 		if (find_res->fifo_policy_item->last_request_time.tv_sec -
731*86d7f5d3SJohn Marino 			find_res->fifo_policy_item->creation_time.tv_sec >
732*86d7f5d3SJohn Marino 			common_entry->common_params.max_lifetime.tv_sec) {
733*86d7f5d3SJohn Marino 
734*86d7f5d3SJohn Marino 			free(find_res->key);
735*86d7f5d3SJohn Marino 			free(find_res->value);
736*86d7f5d3SJohn Marino 
737*86d7f5d3SJohn Marino 			connected_item =
738*86d7f5d3SJohn Marino 			    find_res->fifo_policy_item->connected_item;
739*86d7f5d3SJohn Marino 			if (connected_item != NULL) {
740*86d7f5d3SJohn Marino 				common_entry->policies[1]->remove_item_func(
741*86d7f5d3SJohn Marino 					common_entry->policies[1],
742*86d7f5d3SJohn Marino 					connected_item);
743*86d7f5d3SJohn Marino 				common_entry->policies[1]->destroy_item_func(
744*86d7f5d3SJohn Marino 					connected_item);
745*86d7f5d3SJohn Marino 			}
746*86d7f5d3SJohn Marino 
747*86d7f5d3SJohn Marino 			common_entry->policies[0]->remove_item_func(
748*86d7f5d3SJohn Marino 				common_entry->policies[0],
749*86d7f5d3SJohn Marino 					find_res->fifo_policy_item);
750*86d7f5d3SJohn Marino 			common_entry->policies[0]->destroy_item_func(
751*86d7f5d3SJohn Marino 				find_res->fifo_policy_item);
752*86d7f5d3SJohn Marino 
753*86d7f5d3SJohn Marino 			HASHTABLE_ENTRY_REMOVE(cache_ht_, item, find_res);
754*86d7f5d3SJohn Marino 			--common_entry->items_size;
755*86d7f5d3SJohn Marino 		}
756*86d7f5d3SJohn Marino 	}
757*86d7f5d3SJohn Marino 
758*86d7f5d3SJohn Marino 	if ((*value_size < find_res->value_size) || (value == NULL)) {
759*86d7f5d3SJohn Marino 		*value_size = find_res->value_size;
760*86d7f5d3SJohn Marino 		TRACE_OUT(cache_read);
761*86d7f5d3SJohn Marino 		return (-2);
762*86d7f5d3SJohn Marino 	}
763*86d7f5d3SJohn Marino 
764*86d7f5d3SJohn Marino 	*value_size = find_res->value_size;
765*86d7f5d3SJohn Marino 	memcpy(value, find_res->value, find_res->value_size);
766*86d7f5d3SJohn Marino 
767*86d7f5d3SJohn Marino 	++find_res->fifo_policy_item->request_count;
768*86d7f5d3SJohn Marino 	common_entry->get_time_func(
769*86d7f5d3SJohn Marino 		&find_res->fifo_policy_item->last_request_time);
770*86d7f5d3SJohn Marino 	common_entry->policies[0]->update_item_func(common_entry->policies[0],
771*86d7f5d3SJohn Marino 		find_res->fifo_policy_item);
772*86d7f5d3SJohn Marino 
773*86d7f5d3SJohn Marino 	if (find_res->fifo_policy_item->connected_item != NULL) {
774*86d7f5d3SJohn Marino 		connected_item = find_res->fifo_policy_item->connected_item;
775*86d7f5d3SJohn Marino 		memcpy(&connected_item->last_request_time,
776*86d7f5d3SJohn Marino 			&find_res->fifo_policy_item->last_request_time,
777*86d7f5d3SJohn Marino 			sizeof(struct timeval));
778*86d7f5d3SJohn Marino 		connected_item->request_count =
779*86d7f5d3SJohn Marino 			find_res->fifo_policy_item->request_count;
780*86d7f5d3SJohn Marino 
781*86d7f5d3SJohn Marino 		common_entry->policies[1]->update_item_func(
782*86d7f5d3SJohn Marino 			common_entry->policies[1], connected_item);
783*86d7f5d3SJohn Marino 	}
784*86d7f5d3SJohn Marino 
785*86d7f5d3SJohn Marino 	TRACE_OUT(cache_read);
786*86d7f5d3SJohn Marino 	return (0);
787*86d7f5d3SJohn Marino }
788*86d7f5d3SJohn Marino 
789*86d7f5d3SJohn Marino /*
790*86d7f5d3SJohn Marino  * Writes the value with the specified key into the cache entry.
791*86d7f5d3SJohn Marino  * Functions returns 0 on success, and -1 on error.
792*86d7f5d3SJohn Marino  */
793*86d7f5d3SJohn Marino int
cache_write(struct cache_entry_ * entry,const char * key,size_t key_size,char const * value,size_t value_size)794*86d7f5d3SJohn Marino cache_write(struct cache_entry_ *entry, const char *key, size_t key_size,
795*86d7f5d3SJohn Marino 	char const *value, size_t value_size)
796*86d7f5d3SJohn Marino {
797*86d7f5d3SJohn Marino 	struct cache_common_entry_	*common_entry;
798*86d7f5d3SJohn Marino 	struct cache_ht_item_data_	item_data, *find_res;
799*86d7f5d3SJohn Marino 	struct cache_ht_item_		*item;
800*86d7f5d3SJohn Marino 	hashtable_index_t	hash;
801*86d7f5d3SJohn Marino 
802*86d7f5d3SJohn Marino 	struct cache_policy_		*policy, *connected_policy;
803*86d7f5d3SJohn Marino 	struct cache_policy_item_	*policy_item;
804*86d7f5d3SJohn Marino 	struct cache_policy_item_	*connected_policy_item;
805*86d7f5d3SJohn Marino 
806*86d7f5d3SJohn Marino 	TRACE_IN(cache_write);
807*86d7f5d3SJohn Marino 	assert(entry != NULL);
808*86d7f5d3SJohn Marino 	assert(key != NULL);
809*86d7f5d3SJohn Marino 	assert(value != NULL);
810*86d7f5d3SJohn Marino 	assert(entry->params->entry_type == CET_COMMON);
811*86d7f5d3SJohn Marino 
812*86d7f5d3SJohn Marino 	common_entry = (struct cache_common_entry_ *)entry;
813*86d7f5d3SJohn Marino 
814*86d7f5d3SJohn Marino 	memset(&item_data, 0, sizeof(struct cache_ht_item_data_));
815*86d7f5d3SJohn Marino 	/* can't avoid the cast here */
816*86d7f5d3SJohn Marino 	item_data.key = (char *)key;
817*86d7f5d3SJohn Marino 	item_data.key_size = key_size;
818*86d7f5d3SJohn Marino 
819*86d7f5d3SJohn Marino 	hash = HASHTABLE_CALCULATE_HASH(cache_ht_, &common_entry->items,
820*86d7f5d3SJohn Marino 		&item_data);
821*86d7f5d3SJohn Marino 	assert(hash >= 0);
822*86d7f5d3SJohn Marino 	assert(hash < HASHTABLE_ENTRIES_COUNT(&common_entry->items));
823*86d7f5d3SJohn Marino 
824*86d7f5d3SJohn Marino 	item = HASHTABLE_GET_ENTRY(&(common_entry->items), hash);
825*86d7f5d3SJohn Marino 	find_res = HASHTABLE_ENTRY_FIND(cache_ht_, item, &item_data);
826*86d7f5d3SJohn Marino 	if (find_res != NULL) {
827*86d7f5d3SJohn Marino 		TRACE_OUT(cache_write);
828*86d7f5d3SJohn Marino 		return (-1);
829*86d7f5d3SJohn Marino 	}
830*86d7f5d3SJohn Marino 
831*86d7f5d3SJohn Marino 	item_data.key = (char *)malloc(key_size);
832*86d7f5d3SJohn Marino 	memcpy(item_data.key, key, key_size);
833*86d7f5d3SJohn Marino 
834*86d7f5d3SJohn Marino 	item_data.value = (char *)malloc(value_size);
835*86d7f5d3SJohn Marino 	assert(item_data.value != NULL);
836*86d7f5d3SJohn Marino 
837*86d7f5d3SJohn Marino 	memcpy(item_data.value, value, value_size);
838*86d7f5d3SJohn Marino 	item_data.value_size = value_size;
839*86d7f5d3SJohn Marino 
840*86d7f5d3SJohn Marino 	policy_item = common_entry->policies[0]->create_item_func();
841*86d7f5d3SJohn Marino 	policy_item->key = item_data.key;
842*86d7f5d3SJohn Marino 	policy_item->key_size = item_data.key_size;
843*86d7f5d3SJohn Marino 	common_entry->get_time_func(&policy_item->creation_time);
844*86d7f5d3SJohn Marino 
845*86d7f5d3SJohn Marino 	if (common_entry->policies_size > 1) {
846*86d7f5d3SJohn Marino 		connected_policy_item =
847*86d7f5d3SJohn Marino 			common_entry->policies[1]->create_item_func();
848*86d7f5d3SJohn Marino 		memcpy(&connected_policy_item->creation_time,
849*86d7f5d3SJohn Marino 			&policy_item->creation_time,
850*86d7f5d3SJohn Marino 			sizeof(struct timeval));
851*86d7f5d3SJohn Marino 		connected_policy_item->key = policy_item->key;
852*86d7f5d3SJohn Marino 		connected_policy_item->key_size = policy_item->key_size;
853*86d7f5d3SJohn Marino 
854*86d7f5d3SJohn Marino 		connected_policy_item->connected_item = policy_item;
855*86d7f5d3SJohn Marino 		policy_item->connected_item = connected_policy_item;
856*86d7f5d3SJohn Marino 	}
857*86d7f5d3SJohn Marino 
858*86d7f5d3SJohn Marino 	item_data.fifo_policy_item = policy_item;
859*86d7f5d3SJohn Marino 
860*86d7f5d3SJohn Marino 	common_entry->policies[0]->add_item_func(common_entry->policies[0],
861*86d7f5d3SJohn Marino 		policy_item);
862*86d7f5d3SJohn Marino 	if (common_entry->policies_size > 1)
863*86d7f5d3SJohn Marino 		common_entry->policies[1]->add_item_func(
864*86d7f5d3SJohn Marino 			common_entry->policies[1], connected_policy_item);
865*86d7f5d3SJohn Marino 
866*86d7f5d3SJohn Marino 	HASHTABLE_ENTRY_STORE(cache_ht_, item, &item_data);
867*86d7f5d3SJohn Marino 	++common_entry->items_size;
868*86d7f5d3SJohn Marino 
869*86d7f5d3SJohn Marino 	if ((common_entry->common_params.max_elemsize != 0) &&
870*86d7f5d3SJohn Marino 		(common_entry->items_size >
871*86d7f5d3SJohn Marino 		common_entry->common_params.max_elemsize)) {
872*86d7f5d3SJohn Marino 		if (common_entry->policies_size > 1) {
873*86d7f5d3SJohn Marino 			policy = common_entry->policies[1];
874*86d7f5d3SJohn Marino 			connected_policy = common_entry->policies[0];
875*86d7f5d3SJohn Marino 		} else {
876*86d7f5d3SJohn Marino 			policy = common_entry->policies[0];
877*86d7f5d3SJohn Marino 			connected_policy = NULL;
878*86d7f5d3SJohn Marino 		}
879*86d7f5d3SJohn Marino 
880*86d7f5d3SJohn Marino 		flush_cache_policy(common_entry, policy, connected_policy,
881*86d7f5d3SJohn Marino 			cache_elemsize_common_continue_func);
882*86d7f5d3SJohn Marino 	}
883*86d7f5d3SJohn Marino 
884*86d7f5d3SJohn Marino 	TRACE_OUT(cache_write);
885*86d7f5d3SJohn Marino 	return (0);
886*86d7f5d3SJohn Marino }
887*86d7f5d3SJohn Marino 
888*86d7f5d3SJohn Marino /*
889*86d7f5d3SJohn Marino  * Initializes the write session for the specified multipart entry. This
890*86d7f5d3SJohn Marino  * session then should be filled with data either committed or abandoned by
891*86d7f5d3SJohn Marino  * using close_cache_mp_write_session or abandon_cache_mp_write_session
892*86d7f5d3SJohn Marino  * respectively.
893*86d7f5d3SJohn Marino  * Returns NULL on errors (when there are too many opened write sessions for
894*86d7f5d3SJohn Marino  * the entry).
895*86d7f5d3SJohn Marino  */
896*86d7f5d3SJohn Marino struct cache_mp_write_session_ *
open_cache_mp_write_session(struct cache_entry_ * entry)897*86d7f5d3SJohn Marino open_cache_mp_write_session(struct cache_entry_ *entry)
898*86d7f5d3SJohn Marino {
899*86d7f5d3SJohn Marino 	struct cache_mp_entry_	*mp_entry;
900*86d7f5d3SJohn Marino 	struct cache_mp_write_session_	*retval;
901*86d7f5d3SJohn Marino 
902*86d7f5d3SJohn Marino 	TRACE_IN(open_cache_mp_write_session);
903*86d7f5d3SJohn Marino 	assert(entry != NULL);
904*86d7f5d3SJohn Marino 	assert(entry->params->entry_type == CET_MULTIPART);
905*86d7f5d3SJohn Marino 	mp_entry = (struct cache_mp_entry_ *)entry;
906*86d7f5d3SJohn Marino 
907*86d7f5d3SJohn Marino 	if ((mp_entry->mp_params.max_sessions > 0) &&
908*86d7f5d3SJohn Marino 		(mp_entry->ws_size == mp_entry->mp_params.max_sessions)) {
909*86d7f5d3SJohn Marino 		TRACE_OUT(open_cache_mp_write_session);
910*86d7f5d3SJohn Marino 		return (NULL);
911*86d7f5d3SJohn Marino 	}
912*86d7f5d3SJohn Marino 
913*86d7f5d3SJohn Marino 	retval = (struct cache_mp_write_session_ *)calloc(1,
914*86d7f5d3SJohn Marino 		sizeof(struct cache_mp_write_session_));
915*86d7f5d3SJohn Marino 	assert(retval != NULL);
916*86d7f5d3SJohn Marino 
917*86d7f5d3SJohn Marino 	TAILQ_INIT(&retval->items);
918*86d7f5d3SJohn Marino 	retval->parent_entry = mp_entry;
919*86d7f5d3SJohn Marino 
920*86d7f5d3SJohn Marino 	TAILQ_INSERT_HEAD(&mp_entry->ws_head, retval, entries);
921*86d7f5d3SJohn Marino 	++mp_entry->ws_size;
922*86d7f5d3SJohn Marino 
923*86d7f5d3SJohn Marino 	TRACE_OUT(open_cache_mp_write_session);
924*86d7f5d3SJohn Marino 	return (retval);
925*86d7f5d3SJohn Marino }
926*86d7f5d3SJohn Marino 
927*86d7f5d3SJohn Marino /*
928*86d7f5d3SJohn Marino  * Writes data to the specified session. Return 0 on success and -1 on errors
929*86d7f5d3SJohn Marino  * (when write session size limit is exceeded).
930*86d7f5d3SJohn Marino  */
931*86d7f5d3SJohn Marino int
cache_mp_write(struct cache_mp_write_session_ * ws,char * data,size_t data_size)932*86d7f5d3SJohn Marino cache_mp_write(struct cache_mp_write_session_ *ws, char *data,
933*86d7f5d3SJohn Marino 	size_t data_size)
934*86d7f5d3SJohn Marino {
935*86d7f5d3SJohn Marino 	struct cache_mp_data_item_	*new_item;
936*86d7f5d3SJohn Marino 
937*86d7f5d3SJohn Marino 	TRACE_IN(cache_mp_write);
938*86d7f5d3SJohn Marino 	assert(ws != NULL);
939*86d7f5d3SJohn Marino 	assert(ws->parent_entry != NULL);
940*86d7f5d3SJohn Marino 	assert(ws->parent_entry->params->entry_type == CET_MULTIPART);
941*86d7f5d3SJohn Marino 
942*86d7f5d3SJohn Marino 	if ((ws->parent_entry->mp_params.max_elemsize > 0) &&
943*86d7f5d3SJohn Marino 		(ws->parent_entry->mp_params.max_elemsize == ws->items_size)) {
944*86d7f5d3SJohn Marino 		TRACE_OUT(cache_mp_write);
945*86d7f5d3SJohn Marino 		return (-1);
946*86d7f5d3SJohn Marino 	}
947*86d7f5d3SJohn Marino 
948*86d7f5d3SJohn Marino 	new_item = (struct cache_mp_data_item_ *)calloc(1,
949*86d7f5d3SJohn Marino 		sizeof(struct cache_mp_data_item_));
950*86d7f5d3SJohn Marino 	assert(new_item != NULL);
951*86d7f5d3SJohn Marino 
952*86d7f5d3SJohn Marino 	new_item->value = (char *)malloc(data_size);
953*86d7f5d3SJohn Marino 	assert(new_item->value != NULL);
954*86d7f5d3SJohn Marino 	memcpy(new_item->value, data, data_size);
955*86d7f5d3SJohn Marino 	new_item->value_size = data_size;
956*86d7f5d3SJohn Marino 
957*86d7f5d3SJohn Marino 	TAILQ_INSERT_TAIL(&ws->items, new_item, entries);
958*86d7f5d3SJohn Marino 	++ws->items_size;
959*86d7f5d3SJohn Marino 
960*86d7f5d3SJohn Marino 	TRACE_OUT(cache_mp_write);
961*86d7f5d3SJohn Marino 	return (0);
962*86d7f5d3SJohn Marino }
963*86d7f5d3SJohn Marino 
964*86d7f5d3SJohn Marino /*
965*86d7f5d3SJohn Marino  * Abandons the write session and frees all the connected resources.
966*86d7f5d3SJohn Marino  */
967*86d7f5d3SJohn Marino void
abandon_cache_mp_write_session(struct cache_mp_write_session_ * ws)968*86d7f5d3SJohn Marino abandon_cache_mp_write_session(struct cache_mp_write_session_ *ws)
969*86d7f5d3SJohn Marino {
970*86d7f5d3SJohn Marino 
971*86d7f5d3SJohn Marino 	TRACE_IN(abandon_cache_mp_write_session);
972*86d7f5d3SJohn Marino 	assert(ws != NULL);
973*86d7f5d3SJohn Marino 	assert(ws->parent_entry != NULL);
974*86d7f5d3SJohn Marino 	assert(ws->parent_entry->params->entry_type == CET_MULTIPART);
975*86d7f5d3SJohn Marino 
976*86d7f5d3SJohn Marino 	TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries);
977*86d7f5d3SJohn Marino 	--ws->parent_entry->ws_size;
978*86d7f5d3SJohn Marino 
979*86d7f5d3SJohn Marino 	destroy_cache_mp_write_session(ws);
980*86d7f5d3SJohn Marino 	TRACE_OUT(abandon_cache_mp_write_session);
981*86d7f5d3SJohn Marino }
982*86d7f5d3SJohn Marino 
983*86d7f5d3SJohn Marino /*
984*86d7f5d3SJohn Marino  * Commits the session to the entry, for which it was created.
985*86d7f5d3SJohn Marino  */
986*86d7f5d3SJohn Marino void
close_cache_mp_write_session(struct cache_mp_write_session_ * ws)987*86d7f5d3SJohn Marino close_cache_mp_write_session(struct cache_mp_write_session_ *ws)
988*86d7f5d3SJohn Marino {
989*86d7f5d3SJohn Marino 
990*86d7f5d3SJohn Marino 	TRACE_IN(close_cache_mp_write_session);
991*86d7f5d3SJohn Marino 	assert(ws != NULL);
992*86d7f5d3SJohn Marino 	assert(ws->parent_entry != NULL);
993*86d7f5d3SJohn Marino 	assert(ws->parent_entry->params->entry_type == CET_MULTIPART);
994*86d7f5d3SJohn Marino 
995*86d7f5d3SJohn Marino 	TAILQ_REMOVE(&ws->parent_entry->ws_head, ws, entries);
996*86d7f5d3SJohn Marino 	--ws->parent_entry->ws_size;
997*86d7f5d3SJohn Marino 
998*86d7f5d3SJohn Marino 	if (ws->parent_entry->completed_write_session == NULL) {
999*86d7f5d3SJohn Marino 		/*
1000*86d7f5d3SJohn Marino 		 * If there is no completed session yet, this will be the one
1001*86d7f5d3SJohn Marino 		 */
1002*86d7f5d3SJohn Marino 		ws->parent_entry->get_time_func(
1003*86d7f5d3SJohn Marino 			&ws->parent_entry->creation_time);
1004*86d7f5d3SJohn Marino 		ws->parent_entry->completed_write_session = ws;
1005*86d7f5d3SJohn Marino 	} else {
1006*86d7f5d3SJohn Marino 		/*
1007*86d7f5d3SJohn Marino 		 * If there is a completed session, then we'll save our session
1008*86d7f5d3SJohn Marino 		 * as a pending session. If there is already a pending session,
1009*86d7f5d3SJohn Marino 		 * it would be destroyed.
1010*86d7f5d3SJohn Marino 		 */
1011*86d7f5d3SJohn Marino 		if (ws->parent_entry->pending_write_session != NULL)
1012*86d7f5d3SJohn Marino 			destroy_cache_mp_write_session(
1013*86d7f5d3SJohn Marino 				ws->parent_entry->pending_write_session);
1014*86d7f5d3SJohn Marino 
1015*86d7f5d3SJohn Marino 		ws->parent_entry->pending_write_session = ws;
1016*86d7f5d3SJohn Marino 	}
1017*86d7f5d3SJohn Marino 	TRACE_OUT(close_cache_mp_write_session);
1018*86d7f5d3SJohn Marino }
1019*86d7f5d3SJohn Marino 
1020*86d7f5d3SJohn Marino /*
1021*86d7f5d3SJohn Marino  * Opens read session for the specified entry. Returns NULL on errors (when
1022*86d7f5d3SJohn Marino  * there are no data in the entry, or the data are obsolete).
1023*86d7f5d3SJohn Marino  */
1024*86d7f5d3SJohn Marino struct cache_mp_read_session_ *
open_cache_mp_read_session(struct cache_entry_ * entry)1025*86d7f5d3SJohn Marino open_cache_mp_read_session(struct cache_entry_ *entry)
1026*86d7f5d3SJohn Marino {
1027*86d7f5d3SJohn Marino 	struct cache_mp_entry_			*mp_entry;
1028*86d7f5d3SJohn Marino 	struct cache_mp_read_session_	*retval;
1029*86d7f5d3SJohn Marino 
1030*86d7f5d3SJohn Marino 	TRACE_IN(open_cache_mp_read_session);
1031*86d7f5d3SJohn Marino 	assert(entry != NULL);
1032*86d7f5d3SJohn Marino 	assert(entry->params->entry_type == CET_MULTIPART);
1033*86d7f5d3SJohn Marino 	mp_entry = (struct cache_mp_entry_ *)entry;
1034*86d7f5d3SJohn Marino 
1035*86d7f5d3SJohn Marino 	if (mp_entry->completed_write_session == NULL) {
1036*86d7f5d3SJohn Marino 		TRACE_OUT(open_cache_mp_read_session);
1037*86d7f5d3SJohn Marino 		return (NULL);
1038*86d7f5d3SJohn Marino 	}
1039*86d7f5d3SJohn Marino 
1040*86d7f5d3SJohn Marino 	if ((mp_entry->mp_params.max_lifetime.tv_sec != 0)
1041*86d7f5d3SJohn Marino 		|| (mp_entry->mp_params.max_lifetime.tv_usec != 0)) {
1042*86d7f5d3SJohn Marino 		if (mp_entry->last_request_time.tv_sec -
1043*86d7f5d3SJohn Marino 			mp_entry->last_request_time.tv_sec >
1044*86d7f5d3SJohn Marino 			mp_entry->mp_params.max_lifetime.tv_sec) {
1045*86d7f5d3SJohn Marino 			flush_cache_entry(entry);
1046*86d7f5d3SJohn Marino 			TRACE_OUT(open_cache_mp_read_session);
1047*86d7f5d3SJohn Marino 			return (NULL);
1048*86d7f5d3SJohn Marino 		}
1049*86d7f5d3SJohn Marino 	}
1050*86d7f5d3SJohn Marino 
1051*86d7f5d3SJohn Marino 	retval = (struct cache_mp_read_session_ *)calloc(1,
1052*86d7f5d3SJohn Marino 		sizeof(struct cache_mp_read_session_));
1053*86d7f5d3SJohn Marino 	assert(retval != NULL);
1054*86d7f5d3SJohn Marino 
1055*86d7f5d3SJohn Marino 	retval->parent_entry = mp_entry;
1056*86d7f5d3SJohn Marino 	retval->current_item = TAILQ_FIRST(
1057*86d7f5d3SJohn Marino 		&mp_entry->completed_write_session->items);
1058*86d7f5d3SJohn Marino 
1059*86d7f5d3SJohn Marino 	TAILQ_INSERT_HEAD(&mp_entry->rs_head, retval, entries);
1060*86d7f5d3SJohn Marino 	++mp_entry->rs_size;
1061*86d7f5d3SJohn Marino 
1062*86d7f5d3SJohn Marino 	mp_entry->get_time_func(&mp_entry->last_request_time);
1063*86d7f5d3SJohn Marino 	TRACE_OUT(open_cache_mp_read_session);
1064*86d7f5d3SJohn Marino 	return (retval);
1065*86d7f5d3SJohn Marino }
1066*86d7f5d3SJohn Marino 
1067*86d7f5d3SJohn Marino /*
1068*86d7f5d3SJohn Marino  * Reads the data from the read session - step by step.
1069*86d7f5d3SJohn Marino  * Returns 0 on success, -1 on error (when there are no more data), and -2 if
1070*86d7f5d3SJohn Marino  * the data_size is too small.  In the last case, data_size would be filled
1071*86d7f5d3SJohn Marino  * the proper value.
1072*86d7f5d3SJohn Marino  */
1073*86d7f5d3SJohn Marino int
cache_mp_read(struct cache_mp_read_session_ * rs,char * data,size_t * data_size)1074*86d7f5d3SJohn Marino cache_mp_read(struct cache_mp_read_session_ *rs, char *data, size_t *data_size)
1075*86d7f5d3SJohn Marino {
1076*86d7f5d3SJohn Marino 
1077*86d7f5d3SJohn Marino 	TRACE_IN(cache_mp_read);
1078*86d7f5d3SJohn Marino 	assert(rs != NULL);
1079*86d7f5d3SJohn Marino 
1080*86d7f5d3SJohn Marino 	if (rs->current_item == NULL) {
1081*86d7f5d3SJohn Marino 		TRACE_OUT(cache_mp_read);
1082*86d7f5d3SJohn Marino 		return (-1);
1083*86d7f5d3SJohn Marino 	}
1084*86d7f5d3SJohn Marino 
1085*86d7f5d3SJohn Marino 	if (rs->current_item->value_size > *data_size) {
1086*86d7f5d3SJohn Marino 		*data_size = rs->current_item->value_size;
1087*86d7f5d3SJohn Marino 		if (data == NULL) {
1088*86d7f5d3SJohn Marino 			TRACE_OUT(cache_mp_read);
1089*86d7f5d3SJohn Marino 			return (0);
1090*86d7f5d3SJohn Marino 		}
1091*86d7f5d3SJohn Marino 
1092*86d7f5d3SJohn Marino 		TRACE_OUT(cache_mp_read);
1093*86d7f5d3SJohn Marino 		return (-2);
1094*86d7f5d3SJohn Marino 	}
1095*86d7f5d3SJohn Marino 
1096*86d7f5d3SJohn Marino 	*data_size = rs->current_item->value_size;
1097*86d7f5d3SJohn Marino 	memcpy(data, rs->current_item->value, rs->current_item->value_size);
1098*86d7f5d3SJohn Marino 	rs->current_item = TAILQ_NEXT(rs->current_item, entries);
1099*86d7f5d3SJohn Marino 
1100*86d7f5d3SJohn Marino 	TRACE_OUT(cache_mp_read);
1101*86d7f5d3SJohn Marino 	return (0);
1102*86d7f5d3SJohn Marino }
1103*86d7f5d3SJohn Marino 
1104*86d7f5d3SJohn Marino /*
1105*86d7f5d3SJohn Marino  * Closes the read session. If there are no more read sessions and there is
1106*86d7f5d3SJohn Marino  * a pending write session, it will be committed and old
1107*86d7f5d3SJohn Marino  * completed_write_session will be destroyed.
1108*86d7f5d3SJohn Marino  */
1109*86d7f5d3SJohn Marino void
close_cache_mp_read_session(struct cache_mp_read_session_ * rs)1110*86d7f5d3SJohn Marino close_cache_mp_read_session(struct cache_mp_read_session_ *rs)
1111*86d7f5d3SJohn Marino {
1112*86d7f5d3SJohn Marino 
1113*86d7f5d3SJohn Marino 	TRACE_IN(close_cache_mp_read_session);
1114*86d7f5d3SJohn Marino 	assert(rs != NULL);
1115*86d7f5d3SJohn Marino 	assert(rs->parent_entry != NULL);
1116*86d7f5d3SJohn Marino 
1117*86d7f5d3SJohn Marino 	TAILQ_REMOVE(&rs->parent_entry->rs_head, rs, entries);
1118*86d7f5d3SJohn Marino 	--rs->parent_entry->rs_size;
1119*86d7f5d3SJohn Marino 
1120*86d7f5d3SJohn Marino 	if ((rs->parent_entry->rs_size == 0) &&
1121*86d7f5d3SJohn Marino 		(rs->parent_entry->pending_write_session != NULL)) {
1122*86d7f5d3SJohn Marino 		destroy_cache_mp_write_session(
1123*86d7f5d3SJohn Marino 			rs->parent_entry->completed_write_session);
1124*86d7f5d3SJohn Marino 		rs->parent_entry->completed_write_session =
1125*86d7f5d3SJohn Marino 			rs->parent_entry->pending_write_session;
1126*86d7f5d3SJohn Marino 		rs->parent_entry->pending_write_session = NULL;
1127*86d7f5d3SJohn Marino 	}
1128*86d7f5d3SJohn Marino 
1129*86d7f5d3SJohn Marino 	destroy_cache_mp_read_session(rs);
1130*86d7f5d3SJohn Marino 	TRACE_OUT(close_cache_mp_read_session);
1131*86d7f5d3SJohn Marino }
1132*86d7f5d3SJohn Marino 
1133*86d7f5d3SJohn Marino int
transform_cache_entry(struct cache_entry_ * entry,enum cache_transformation_t transformation)1134*86d7f5d3SJohn Marino transform_cache_entry(struct cache_entry_ *entry,
1135*86d7f5d3SJohn Marino 	enum cache_transformation_t transformation)
1136*86d7f5d3SJohn Marino {
1137*86d7f5d3SJohn Marino 
1138*86d7f5d3SJohn Marino 	TRACE_IN(transform_cache_entry);
1139*86d7f5d3SJohn Marino 	switch (transformation) {
1140*86d7f5d3SJohn Marino 	case CTT_CLEAR:
1141*86d7f5d3SJohn Marino 		clear_cache_entry(entry);
1142*86d7f5d3SJohn Marino 		TRACE_OUT(transform_cache_entry);
1143*86d7f5d3SJohn Marino 		return (0);
1144*86d7f5d3SJohn Marino 	case CTT_FLUSH:
1145*86d7f5d3SJohn Marino 		flush_cache_entry(entry);
1146*86d7f5d3SJohn Marino 		TRACE_OUT(transform_cache_entry);
1147*86d7f5d3SJohn Marino 		return (0);
1148*86d7f5d3SJohn Marino 	default:
1149*86d7f5d3SJohn Marino 		TRACE_OUT(transform_cache_entry);
1150*86d7f5d3SJohn Marino 		return (-1);
1151*86d7f5d3SJohn Marino 	}
1152*86d7f5d3SJohn Marino }
1153*86d7f5d3SJohn Marino 
1154*86d7f5d3SJohn Marino int
transform_cache_entry_part(struct cache_entry_ * entry,enum cache_transformation_t transformation,const char * key_part,size_t key_part_size,enum part_position_t part_position)1155*86d7f5d3SJohn Marino transform_cache_entry_part(struct cache_entry_ *entry,
1156*86d7f5d3SJohn Marino 	enum cache_transformation_t transformation, const char *key_part,
1157*86d7f5d3SJohn Marino 	size_t key_part_size, enum part_position_t part_position)
1158*86d7f5d3SJohn Marino {
1159*86d7f5d3SJohn Marino 	struct cache_common_entry_ *common_entry;
1160*86d7f5d3SJohn Marino 	struct cache_ht_item_ *ht_item;
1161*86d7f5d3SJohn Marino 	struct cache_ht_item_data_ *ht_item_data, ht_key;
1162*86d7f5d3SJohn Marino 
1163*86d7f5d3SJohn Marino 	struct cache_policy_item_ *item, *connected_item;
1164*86d7f5d3SJohn Marino 
1165*86d7f5d3SJohn Marino 	TRACE_IN(transform_cache_entry_part);
1166*86d7f5d3SJohn Marino 	if (entry->params->entry_type != CET_COMMON) {
1167*86d7f5d3SJohn Marino 		TRACE_OUT(transform_cache_entry_part);
1168*86d7f5d3SJohn Marino 		return (-1);
1169*86d7f5d3SJohn Marino 	}
1170*86d7f5d3SJohn Marino 
1171*86d7f5d3SJohn Marino 	if (transformation != CTT_CLEAR) {
1172*86d7f5d3SJohn Marino 		TRACE_OUT(transform_cache_entry_part);
1173*86d7f5d3SJohn Marino 		return (-1);
1174*86d7f5d3SJohn Marino 	}
1175*86d7f5d3SJohn Marino 
1176*86d7f5d3SJohn Marino 	memset(&ht_key, 0, sizeof(struct cache_ht_item_data_));
1177*86d7f5d3SJohn Marino 	ht_key.key = (char *)key_part;	/* can't avoid casting here */
1178*86d7f5d3SJohn Marino 	ht_key.key_size = key_part_size;
1179*86d7f5d3SJohn Marino 
1180*86d7f5d3SJohn Marino 	common_entry = (struct cache_common_entry_ *)entry;
1181*86d7f5d3SJohn Marino 	HASHTABLE_FOREACH(&(common_entry->items), ht_item) {
1182*86d7f5d3SJohn Marino 		do {
1183*86d7f5d3SJohn Marino 			ht_item_data = HASHTABLE_ENTRY_FIND_SPECIAL(cache_ht_,
1184*86d7f5d3SJohn Marino 				ht_item, &ht_key,
1185*86d7f5d3SJohn Marino 				ht_items_fixed_size_left_cmp_func);
1186*86d7f5d3SJohn Marino 
1187*86d7f5d3SJohn Marino 			if (ht_item_data != NULL) {
1188*86d7f5d3SJohn Marino 			    item = ht_item_data->fifo_policy_item;
1189*86d7f5d3SJohn Marino 			    connected_item = item->connected_item;
1190*86d7f5d3SJohn Marino 
1191*86d7f5d3SJohn Marino 			    common_entry->policies[0]->remove_item_func(
1192*86d7f5d3SJohn Marino 				common_entry->policies[0],
1193*86d7f5d3SJohn Marino 				item);
1194*86d7f5d3SJohn Marino 
1195*86d7f5d3SJohn Marino 			    free(ht_item_data->key);
1196*86d7f5d3SJohn Marino 			    free(ht_item_data->value);
1197*86d7f5d3SJohn Marino 			    HASHTABLE_ENTRY_REMOVE(cache_ht_, ht_item,
1198*86d7f5d3SJohn Marino 				ht_item_data);
1199*86d7f5d3SJohn Marino 			    --common_entry->items_size;
1200*86d7f5d3SJohn Marino 
1201*86d7f5d3SJohn Marino 			    common_entry->policies[0]->destroy_item_func(
1202*86d7f5d3SJohn Marino 				item);
1203*86d7f5d3SJohn Marino 			    if (common_entry->policies_size == 2) {
1204*86d7f5d3SJohn Marino 				common_entry->policies[1]->remove_item_func(
1205*86d7f5d3SJohn Marino 				    common_entry->policies[1],
1206*86d7f5d3SJohn Marino 				    connected_item);
1207*86d7f5d3SJohn Marino 				common_entry->policies[1]->destroy_item_func(
1208*86d7f5d3SJohn Marino 				    connected_item);
1209*86d7f5d3SJohn Marino 			    }
1210*86d7f5d3SJohn Marino 			}
1211*86d7f5d3SJohn Marino 		} while (ht_item_data != NULL);
1212*86d7f5d3SJohn Marino 	}
1213*86d7f5d3SJohn Marino 
1214*86d7f5d3SJohn Marino 	TRACE_OUT(transform_cache_entry_part);
1215*86d7f5d3SJohn Marino 	return (0);
1216*86d7f5d3SJohn Marino }
1217