1*ed5d5720SPeter Avalos /*-
2*ed5d5720SPeter Avalos * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3*ed5d5720SPeter Avalos * All rights reserved.
4*ed5d5720SPeter Avalos *
5*ed5d5720SPeter Avalos * Redistribution and use in source and binary forms, with or without
6*ed5d5720SPeter Avalos * modification, are permitted provided that the following conditions
7*ed5d5720SPeter Avalos * are met:
8*ed5d5720SPeter Avalos * 1. Redistributions of source code must retain the above copyright
9*ed5d5720SPeter Avalos * notice, this list of conditions and the following disclaimer.
10*ed5d5720SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright
11*ed5d5720SPeter Avalos * notice, this list of conditions and the following disclaimer in the
12*ed5d5720SPeter Avalos * documentation and/or other materials provided with the distribution.
13*ed5d5720SPeter Avalos *
14*ed5d5720SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*ed5d5720SPeter Avalos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*ed5d5720SPeter Avalos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*ed5d5720SPeter Avalos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*ed5d5720SPeter Avalos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*ed5d5720SPeter Avalos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*ed5d5720SPeter Avalos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*ed5d5720SPeter Avalos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*ed5d5720SPeter Avalos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*ed5d5720SPeter Avalos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*ed5d5720SPeter Avalos * SUCH DAMAGE.
25*ed5d5720SPeter Avalos *
26*ed5d5720SPeter Avalos * $FreeBSD: src/usr.sbin/nscd/cacheplcs.c,v 1.3 2008/10/12 00:44:27 delphij Exp $
27*ed5d5720SPeter Avalos */
28*ed5d5720SPeter Avalos
29*ed5d5720SPeter Avalos #include <assert.h>
30*ed5d5720SPeter Avalos #include <string.h>
31*ed5d5720SPeter Avalos #include "cacheplcs.h"
32*ed5d5720SPeter Avalos #include "debug.h"
33*ed5d5720SPeter Avalos
34*ed5d5720SPeter Avalos static void cache_fifo_policy_update_item(struct cache_policy_ *,
35*ed5d5720SPeter Avalos struct cache_policy_item_ *);
36*ed5d5720SPeter Avalos static void cache_lfu_policy_add_item(struct cache_policy_ *,
37*ed5d5720SPeter Avalos struct cache_policy_item_ *);
38*ed5d5720SPeter Avalos static struct cache_policy_item_ * cache_lfu_policy_create_item(void);
39*ed5d5720SPeter Avalos static void cache_lfu_policy_destroy_item(struct cache_policy_item_ *);
40*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_lfu_policy_get_first_item(
41*ed5d5720SPeter Avalos struct cache_policy_ *);
42*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_lfu_policy_get_last_item(
43*ed5d5720SPeter Avalos struct cache_policy_ *);
44*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_lfu_policy_get_next_item(
45*ed5d5720SPeter Avalos struct cache_policy_ *, struct cache_policy_item_ *);
46*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_lfu_policy_get_prev_item(
47*ed5d5720SPeter Avalos struct cache_policy_ *, struct cache_policy_item_ *);
48*ed5d5720SPeter Avalos static void cache_lfu_policy_remove_item(struct cache_policy_ *,
49*ed5d5720SPeter Avalos struct cache_policy_item_ *);
50*ed5d5720SPeter Avalos static void cache_lfu_policy_update_item(struct cache_policy_ *,
51*ed5d5720SPeter Avalos struct cache_policy_item_ *);
52*ed5d5720SPeter Avalos static void cache_lru_policy_update_item(struct cache_policy_ *,
53*ed5d5720SPeter Avalos struct cache_policy_item_ *);
54*ed5d5720SPeter Avalos static void cache_queue_policy_add_item(struct cache_policy_ *,
55*ed5d5720SPeter Avalos struct cache_policy_item_ *);
56*ed5d5720SPeter Avalos static struct cache_policy_item_ * cache_queue_policy_create_item();
57*ed5d5720SPeter Avalos static void cache_queue_policy_destroy_item(struct cache_policy_item_ *);
58*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_queue_policy_get_first_item(
59*ed5d5720SPeter Avalos struct cache_policy_ *);
60*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_queue_policy_get_last_item(
61*ed5d5720SPeter Avalos struct cache_policy_ *);
62*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_queue_policy_get_next_item(
63*ed5d5720SPeter Avalos struct cache_policy_ *, struct cache_policy_item_ *);
64*ed5d5720SPeter Avalos static struct cache_policy_item_ *cache_queue_policy_get_prev_item(
65*ed5d5720SPeter Avalos struct cache_policy_ *, struct cache_policy_item_ *);
66*ed5d5720SPeter Avalos static void cache_queue_policy_remove_item(struct cache_policy_ *,
67*ed5d5720SPeter Avalos struct cache_policy_item_ *);
68*ed5d5720SPeter Avalos static void destroy_cache_queue_policy(struct cache_queue_policy_ *);
69*ed5d5720SPeter Avalos static struct cache_queue_policy_ *init_cache_queue_policy(void);
70*ed5d5720SPeter Avalos
71*ed5d5720SPeter Avalos /*
72*ed5d5720SPeter Avalos * All cache_queue_policy_XXX functions below will be used to fill
73*ed5d5720SPeter Avalos * the cache_queue_policy structure. They implement the most functionality of
74*ed5d5720SPeter Avalos * LRU and FIFO policies. LRU and FIFO policies are actually the
75*ed5d5720SPeter Avalos * cache_queue_policy_ with cache_update_item function changed.
76*ed5d5720SPeter Avalos */
77*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_queue_policy_create_item(void)78*ed5d5720SPeter Avalos cache_queue_policy_create_item(void)
79*ed5d5720SPeter Avalos {
80*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *retval;
81*ed5d5720SPeter Avalos
82*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_create_item);
83*ed5d5720SPeter Avalos retval = (struct cache_queue_policy_item_ *)calloc(1,
84*ed5d5720SPeter Avalos sizeof(struct cache_queue_policy_item_));
85*ed5d5720SPeter Avalos assert(retval != NULL);
86*ed5d5720SPeter Avalos
87*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_create_item);
88*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)retval);
89*ed5d5720SPeter Avalos }
90*ed5d5720SPeter Avalos
91*ed5d5720SPeter Avalos static void
cache_queue_policy_destroy_item(struct cache_policy_item_ * item)92*ed5d5720SPeter Avalos cache_queue_policy_destroy_item(struct cache_policy_item_ *item)
93*ed5d5720SPeter Avalos {
94*ed5d5720SPeter Avalos
95*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_destroy_item);
96*ed5d5720SPeter Avalos assert(item != NULL);
97*ed5d5720SPeter Avalos free(item);
98*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_destroy_item);
99*ed5d5720SPeter Avalos }
100*ed5d5720SPeter Avalos
101*ed5d5720SPeter Avalos static void
cache_queue_policy_add_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)102*ed5d5720SPeter Avalos cache_queue_policy_add_item(struct cache_policy_ *policy,
103*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
104*ed5d5720SPeter Avalos {
105*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
106*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
107*ed5d5720SPeter Avalos
108*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_add_item);
109*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
110*ed5d5720SPeter Avalos queue_item = (struct cache_queue_policy_item_ *)item;
111*ed5d5720SPeter Avalos TAILQ_INSERT_TAIL(&queue_policy->head, queue_item, entries);
112*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_add_item);
113*ed5d5720SPeter Avalos }
114*ed5d5720SPeter Avalos
115*ed5d5720SPeter Avalos static void
cache_queue_policy_remove_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)116*ed5d5720SPeter Avalos cache_queue_policy_remove_item(struct cache_policy_ *policy,
117*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
118*ed5d5720SPeter Avalos {
119*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
120*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
121*ed5d5720SPeter Avalos
122*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_remove_item);
123*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
124*ed5d5720SPeter Avalos queue_item = (struct cache_queue_policy_item_ *)item;
125*ed5d5720SPeter Avalos TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
126*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_remove_item);
127*ed5d5720SPeter Avalos }
128*ed5d5720SPeter Avalos
129*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_queue_policy_get_first_item(struct cache_policy_ * policy)130*ed5d5720SPeter Avalos cache_queue_policy_get_first_item(struct cache_policy_ *policy)
131*ed5d5720SPeter Avalos {
132*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
133*ed5d5720SPeter Avalos
134*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_get_first_item);
135*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
136*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_get_first_item);
137*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)TAILQ_FIRST(&queue_policy->head));
138*ed5d5720SPeter Avalos }
139*ed5d5720SPeter Avalos
140*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_queue_policy_get_last_item(struct cache_policy_ * policy)141*ed5d5720SPeter Avalos cache_queue_policy_get_last_item(struct cache_policy_ *policy)
142*ed5d5720SPeter Avalos {
143*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
144*ed5d5720SPeter Avalos
145*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_get_last_item);
146*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
147*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_get_last_item);
148*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)TAILQ_LAST(&queue_policy->head,
149*ed5d5720SPeter Avalos cache_queue_policy_head_));
150*ed5d5720SPeter Avalos }
151*ed5d5720SPeter Avalos
152*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_queue_policy_get_next_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)153*ed5d5720SPeter Avalos cache_queue_policy_get_next_item(struct cache_policy_ *policy,
154*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
155*ed5d5720SPeter Avalos {
156*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
157*ed5d5720SPeter Avalos
158*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_get_next_item);
159*ed5d5720SPeter Avalos queue_item = (struct cache_queue_policy_item_ *)item;
160*ed5d5720SPeter Avalos
161*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_get_next_item);
162*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)TAILQ_NEXT(queue_item, entries));
163*ed5d5720SPeter Avalos }
164*ed5d5720SPeter Avalos
165*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_queue_policy_get_prev_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)166*ed5d5720SPeter Avalos cache_queue_policy_get_prev_item(struct cache_policy_ *policy,
167*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
168*ed5d5720SPeter Avalos {
169*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
170*ed5d5720SPeter Avalos
171*ed5d5720SPeter Avalos TRACE_IN(cache_queue_policy_get_prev_item);
172*ed5d5720SPeter Avalos queue_item = (struct cache_queue_policy_item_ *)item;
173*ed5d5720SPeter Avalos
174*ed5d5720SPeter Avalos TRACE_OUT(cache_queue_policy_get_prev_item);
175*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)TAILQ_PREV(queue_item,
176*ed5d5720SPeter Avalos cache_queue_policy_head_, entries));
177*ed5d5720SPeter Avalos }
178*ed5d5720SPeter Avalos
179*ed5d5720SPeter Avalos /*
180*ed5d5720SPeter Avalos * Initializes cache_queue_policy_ by filling the structure with the functions
181*ed5d5720SPeter Avalos * pointers, defined above
182*ed5d5720SPeter Avalos */
183*ed5d5720SPeter Avalos static struct cache_queue_policy_ *
init_cache_queue_policy(void)184*ed5d5720SPeter Avalos init_cache_queue_policy(void)
185*ed5d5720SPeter Avalos {
186*ed5d5720SPeter Avalos struct cache_queue_policy_ *retval;
187*ed5d5720SPeter Avalos
188*ed5d5720SPeter Avalos TRACE_IN(init_cache_queue_policy);
189*ed5d5720SPeter Avalos retval = (struct cache_queue_policy_ *)calloc(1,
190*ed5d5720SPeter Avalos sizeof(struct cache_queue_policy_));
191*ed5d5720SPeter Avalos assert(retval != NULL);
192*ed5d5720SPeter Avalos
193*ed5d5720SPeter Avalos retval->parent_data.create_item_func = cache_queue_policy_create_item;
194*ed5d5720SPeter Avalos retval->parent_data.destroy_item_func = cache_queue_policy_destroy_item;
195*ed5d5720SPeter Avalos
196*ed5d5720SPeter Avalos retval->parent_data.add_item_func = cache_queue_policy_add_item;
197*ed5d5720SPeter Avalos retval->parent_data.remove_item_func = cache_queue_policy_remove_item;
198*ed5d5720SPeter Avalos
199*ed5d5720SPeter Avalos retval->parent_data.get_first_item_func =
200*ed5d5720SPeter Avalos cache_queue_policy_get_first_item;
201*ed5d5720SPeter Avalos retval->parent_data.get_last_item_func =
202*ed5d5720SPeter Avalos cache_queue_policy_get_last_item;
203*ed5d5720SPeter Avalos retval->parent_data.get_next_item_func =
204*ed5d5720SPeter Avalos cache_queue_policy_get_next_item;
205*ed5d5720SPeter Avalos retval->parent_data.get_prev_item_func =
206*ed5d5720SPeter Avalos cache_queue_policy_get_prev_item;
207*ed5d5720SPeter Avalos
208*ed5d5720SPeter Avalos TAILQ_INIT(&retval->head);
209*ed5d5720SPeter Avalos TRACE_OUT(init_cache_queue_policy);
210*ed5d5720SPeter Avalos return (retval);
211*ed5d5720SPeter Avalos }
212*ed5d5720SPeter Avalos
213*ed5d5720SPeter Avalos static void
destroy_cache_queue_policy(struct cache_queue_policy_ * queue_policy)214*ed5d5720SPeter Avalos destroy_cache_queue_policy(struct cache_queue_policy_ *queue_policy)
215*ed5d5720SPeter Avalos {
216*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
217*ed5d5720SPeter Avalos
218*ed5d5720SPeter Avalos TRACE_IN(destroy_cache_queue_policy);
219*ed5d5720SPeter Avalos while (!TAILQ_EMPTY(&queue_policy->head)) {
220*ed5d5720SPeter Avalos queue_item = TAILQ_FIRST(&queue_policy->head);
221*ed5d5720SPeter Avalos TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
222*ed5d5720SPeter Avalos cache_queue_policy_destroy_item(
223*ed5d5720SPeter Avalos (struct cache_policy_item_ *)queue_item);
224*ed5d5720SPeter Avalos }
225*ed5d5720SPeter Avalos free(queue_policy);
226*ed5d5720SPeter Avalos TRACE_OUT(destroy_cache_queue_policy);
227*ed5d5720SPeter Avalos }
228*ed5d5720SPeter Avalos
229*ed5d5720SPeter Avalos /*
230*ed5d5720SPeter Avalos * Makes cache_queue_policy_ behave like FIFO policy - we don't do anything,
231*ed5d5720SPeter Avalos * when the cache element is updated. So it always stays in its initial
232*ed5d5720SPeter Avalos * position in the queue - that is exactly the FIFO functionality.
233*ed5d5720SPeter Avalos */
234*ed5d5720SPeter Avalos static void
cache_fifo_policy_update_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)235*ed5d5720SPeter Avalos cache_fifo_policy_update_item(struct cache_policy_ *policy,
236*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
237*ed5d5720SPeter Avalos {
238*ed5d5720SPeter Avalos
239*ed5d5720SPeter Avalos TRACE_IN(cache_fifo_policy_update_item);
240*ed5d5720SPeter Avalos /* policy and item arguments are ignored */
241*ed5d5720SPeter Avalos TRACE_OUT(cache_fifo_policy_update_item);
242*ed5d5720SPeter Avalos }
243*ed5d5720SPeter Avalos
244*ed5d5720SPeter Avalos struct cache_policy_ *
init_cache_fifo_policy(void)245*ed5d5720SPeter Avalos init_cache_fifo_policy(void)
246*ed5d5720SPeter Avalos {
247*ed5d5720SPeter Avalos struct cache_queue_policy_ *retval;
248*ed5d5720SPeter Avalos
249*ed5d5720SPeter Avalos TRACE_IN(init_cache_fifo_policy);
250*ed5d5720SPeter Avalos retval = init_cache_queue_policy();
251*ed5d5720SPeter Avalos retval->parent_data.update_item_func = cache_fifo_policy_update_item;
252*ed5d5720SPeter Avalos
253*ed5d5720SPeter Avalos TRACE_OUT(init_cache_fifo_policy);
254*ed5d5720SPeter Avalos return ((struct cache_policy_ *)retval);
255*ed5d5720SPeter Avalos }
256*ed5d5720SPeter Avalos
257*ed5d5720SPeter Avalos void
destroy_cache_fifo_policy(struct cache_policy_ * policy)258*ed5d5720SPeter Avalos destroy_cache_fifo_policy(struct cache_policy_ *policy)
259*ed5d5720SPeter Avalos {
260*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
261*ed5d5720SPeter Avalos
262*ed5d5720SPeter Avalos TRACE_IN(destroy_cache_fifo_policy);
263*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
264*ed5d5720SPeter Avalos destroy_cache_queue_policy(queue_policy);
265*ed5d5720SPeter Avalos TRACE_OUT(destroy_cache_fifo_policy);
266*ed5d5720SPeter Avalos }
267*ed5d5720SPeter Avalos
268*ed5d5720SPeter Avalos /*
269*ed5d5720SPeter Avalos * Makes cache_queue_policy_ behave like LRU policy. On each update, cache
270*ed5d5720SPeter Avalos * element is moved to the end of the queue - so it would be deleted in last
271*ed5d5720SPeter Avalos * turn. That is exactly the LRU policy functionality.
272*ed5d5720SPeter Avalos */
273*ed5d5720SPeter Avalos static void
cache_lru_policy_update_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)274*ed5d5720SPeter Avalos cache_lru_policy_update_item(struct cache_policy_ *policy,
275*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
276*ed5d5720SPeter Avalos {
277*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
278*ed5d5720SPeter Avalos struct cache_queue_policy_item_ *queue_item;
279*ed5d5720SPeter Avalos
280*ed5d5720SPeter Avalos TRACE_IN(cache_lru_policy_update_item);
281*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
282*ed5d5720SPeter Avalos queue_item = (struct cache_queue_policy_item_ *)item;
283*ed5d5720SPeter Avalos
284*ed5d5720SPeter Avalos TAILQ_REMOVE(&queue_policy->head, queue_item, entries);
285*ed5d5720SPeter Avalos TAILQ_INSERT_TAIL(&queue_policy->head, queue_item, entries);
286*ed5d5720SPeter Avalos TRACE_OUT(cache_lru_policy_update_item);
287*ed5d5720SPeter Avalos }
288*ed5d5720SPeter Avalos
289*ed5d5720SPeter Avalos struct cache_policy_ *
init_cache_lru_policy(void)290*ed5d5720SPeter Avalos init_cache_lru_policy(void)
291*ed5d5720SPeter Avalos {
292*ed5d5720SPeter Avalos struct cache_queue_policy_ *retval;
293*ed5d5720SPeter Avalos
294*ed5d5720SPeter Avalos TRACE_IN(init_cache_lru_policy);
295*ed5d5720SPeter Avalos retval = init_cache_queue_policy();
296*ed5d5720SPeter Avalos retval->parent_data.update_item_func = cache_lru_policy_update_item;
297*ed5d5720SPeter Avalos
298*ed5d5720SPeter Avalos TRACE_OUT(init_cache_lru_policy);
299*ed5d5720SPeter Avalos return ((struct cache_policy_ *)retval);
300*ed5d5720SPeter Avalos }
301*ed5d5720SPeter Avalos
302*ed5d5720SPeter Avalos void
destroy_cache_lru_policy(struct cache_policy_ * policy)303*ed5d5720SPeter Avalos destroy_cache_lru_policy(struct cache_policy_ *policy)
304*ed5d5720SPeter Avalos {
305*ed5d5720SPeter Avalos struct cache_queue_policy_ *queue_policy;
306*ed5d5720SPeter Avalos
307*ed5d5720SPeter Avalos TRACE_IN(destroy_cache_lru_policy);
308*ed5d5720SPeter Avalos queue_policy = (struct cache_queue_policy_ *)policy;
309*ed5d5720SPeter Avalos destroy_cache_queue_policy(queue_policy);
310*ed5d5720SPeter Avalos TRACE_OUT(destroy_cache_lru_policy);
311*ed5d5720SPeter Avalos }
312*ed5d5720SPeter Avalos
313*ed5d5720SPeter Avalos /*
314*ed5d5720SPeter Avalos * LFU (least frequently used) policy implementation differs much from the
315*ed5d5720SPeter Avalos * LRU and FIFO (both based on cache_queue_policy_). Almost all cache_policy_
316*ed5d5720SPeter Avalos * functions are implemented specifically for this policy. The idea of this
317*ed5d5720SPeter Avalos * policy is to represent frequency (real number) as the integer number and
318*ed5d5720SPeter Avalos * use it as the index in the array. Each array's element is
319*ed5d5720SPeter Avalos * the list of elements. For example, if we have the 100-elements
320*ed5d5720SPeter Avalos * array for this policy, the elements with frequency 0.1 (calls per-second)
321*ed5d5720SPeter Avalos * would be in 10th element of the array.
322*ed5d5720SPeter Avalos */
323*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_lfu_policy_create_item(void)324*ed5d5720SPeter Avalos cache_lfu_policy_create_item(void)
325*ed5d5720SPeter Avalos {
326*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *retval;
327*ed5d5720SPeter Avalos
328*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_create_item);
329*ed5d5720SPeter Avalos retval = (struct cache_lfu_policy_item_ *)calloc(1,
330*ed5d5720SPeter Avalos sizeof(struct cache_lfu_policy_item_));
331*ed5d5720SPeter Avalos assert(retval != NULL);
332*ed5d5720SPeter Avalos
333*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_create_item);
334*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)retval);
335*ed5d5720SPeter Avalos }
336*ed5d5720SPeter Avalos
337*ed5d5720SPeter Avalos static void
cache_lfu_policy_destroy_item(struct cache_policy_item_ * item)338*ed5d5720SPeter Avalos cache_lfu_policy_destroy_item(struct cache_policy_item_ *item)
339*ed5d5720SPeter Avalos {
340*ed5d5720SPeter Avalos
341*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_destroy_item);
342*ed5d5720SPeter Avalos assert(item != NULL);
343*ed5d5720SPeter Avalos free(item);
344*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_destroy_item);
345*ed5d5720SPeter Avalos }
346*ed5d5720SPeter Avalos
347*ed5d5720SPeter Avalos /*
348*ed5d5720SPeter Avalos * When placed in the LFU policy queue for the first time, the maximum
349*ed5d5720SPeter Avalos * frequency is assigned to the element
350*ed5d5720SPeter Avalos */
351*ed5d5720SPeter Avalos static void
cache_lfu_policy_add_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)352*ed5d5720SPeter Avalos cache_lfu_policy_add_item(struct cache_policy_ *policy,
353*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
354*ed5d5720SPeter Avalos {
355*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
356*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
357*ed5d5720SPeter Avalos
358*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_add_item);
359*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
360*ed5d5720SPeter Avalos lfu_item = (struct cache_lfu_policy_item_ *)item;
361*ed5d5720SPeter Avalos
362*ed5d5720SPeter Avalos lfu_item->frequency = CACHELIB_MAX_FREQUENCY - 1;
363*ed5d5720SPeter Avalos TAILQ_INSERT_HEAD(&(lfu_policy->groups[CACHELIB_MAX_FREQUENCY - 1]),
364*ed5d5720SPeter Avalos lfu_item, entries);
365*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_add_item);
366*ed5d5720SPeter Avalos }
367*ed5d5720SPeter Avalos
368*ed5d5720SPeter Avalos /*
369*ed5d5720SPeter Avalos * On each update the frequency of the element is recalculated and, if it
370*ed5d5720SPeter Avalos * changed, the element would be moved to the another place in the array.
371*ed5d5720SPeter Avalos */
372*ed5d5720SPeter Avalos static void
cache_lfu_policy_update_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)373*ed5d5720SPeter Avalos cache_lfu_policy_update_item(struct cache_policy_ *policy,
374*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
375*ed5d5720SPeter Avalos {
376*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
377*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
378*ed5d5720SPeter Avalos int index;
379*ed5d5720SPeter Avalos
380*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_update_item);
381*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
382*ed5d5720SPeter Avalos lfu_item = (struct cache_lfu_policy_item_ *)item;
383*ed5d5720SPeter Avalos
384*ed5d5720SPeter Avalos /*
385*ed5d5720SPeter Avalos * We calculate the square of the request_count to avoid grouping of
386*ed5d5720SPeter Avalos * all elements at the start of the array (for example, if array size is
387*ed5d5720SPeter Avalos * 100 and most of its elements has frequency below the 0.01, they
388*ed5d5720SPeter Avalos * all would be grouped in the first array's position). Other
389*ed5d5720SPeter Avalos * techniques should be used here later to ensure, that elements are
390*ed5d5720SPeter Avalos * equally distributed in the array and not grouped in its beginning.
391*ed5d5720SPeter Avalos */
392*ed5d5720SPeter Avalos if (lfu_item->parent_data.last_request_time.tv_sec !=
393*ed5d5720SPeter Avalos lfu_item->parent_data.creation_time.tv_sec) {
394*ed5d5720SPeter Avalos index = ((double)lfu_item->parent_data.request_count *
395*ed5d5720SPeter Avalos (double)lfu_item->parent_data.request_count /
396*ed5d5720SPeter Avalos (lfu_item->parent_data.last_request_time.tv_sec -
397*ed5d5720SPeter Avalos lfu_item->parent_data.creation_time.tv_sec + 1)) *
398*ed5d5720SPeter Avalos CACHELIB_MAX_FREQUENCY;
399*ed5d5720SPeter Avalos if (index >= CACHELIB_MAX_FREQUENCY)
400*ed5d5720SPeter Avalos index = CACHELIB_MAX_FREQUENCY - 1;
401*ed5d5720SPeter Avalos } else
402*ed5d5720SPeter Avalos index = CACHELIB_MAX_FREQUENCY - 1;
403*ed5d5720SPeter Avalos
404*ed5d5720SPeter Avalos TAILQ_REMOVE(&(lfu_policy->groups[lfu_item->frequency]), lfu_item,
405*ed5d5720SPeter Avalos entries);
406*ed5d5720SPeter Avalos lfu_item->frequency = index;
407*ed5d5720SPeter Avalos TAILQ_INSERT_HEAD(&(lfu_policy->groups[index]), lfu_item, entries);
408*ed5d5720SPeter Avalos
409*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_update_item);
410*ed5d5720SPeter Avalos }
411*ed5d5720SPeter Avalos
412*ed5d5720SPeter Avalos static void
cache_lfu_policy_remove_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)413*ed5d5720SPeter Avalos cache_lfu_policy_remove_item(struct cache_policy_ *policy,
414*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
415*ed5d5720SPeter Avalos {
416*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
417*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
418*ed5d5720SPeter Avalos
419*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_remove_item);
420*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
421*ed5d5720SPeter Avalos lfu_item = (struct cache_lfu_policy_item_ *)item;
422*ed5d5720SPeter Avalos
423*ed5d5720SPeter Avalos TAILQ_REMOVE(&(lfu_policy->groups[lfu_item->frequency]), lfu_item,
424*ed5d5720SPeter Avalos entries);
425*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_remove_item);
426*ed5d5720SPeter Avalos }
427*ed5d5720SPeter Avalos
428*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_lfu_policy_get_first_item(struct cache_policy_ * policy)429*ed5d5720SPeter Avalos cache_lfu_policy_get_first_item(struct cache_policy_ *policy)
430*ed5d5720SPeter Avalos {
431*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
432*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
433*ed5d5720SPeter Avalos int i;
434*ed5d5720SPeter Avalos
435*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_get_first_item);
436*ed5d5720SPeter Avalos lfu_item = NULL;
437*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
438*ed5d5720SPeter Avalos for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i)
439*ed5d5720SPeter Avalos if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
440*ed5d5720SPeter Avalos lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
441*ed5d5720SPeter Avalos break;
442*ed5d5720SPeter Avalos }
443*ed5d5720SPeter Avalos
444*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_get_first_item);
445*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)lfu_item);
446*ed5d5720SPeter Avalos }
447*ed5d5720SPeter Avalos
448*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_lfu_policy_get_last_item(struct cache_policy_ * policy)449*ed5d5720SPeter Avalos cache_lfu_policy_get_last_item(struct cache_policy_ *policy)
450*ed5d5720SPeter Avalos {
451*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
452*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
453*ed5d5720SPeter Avalos int i;
454*ed5d5720SPeter Avalos
455*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_get_last_item);
456*ed5d5720SPeter Avalos lfu_item = NULL;
457*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
458*ed5d5720SPeter Avalos for (i = CACHELIB_MAX_FREQUENCY - 1; i >= 0; --i)
459*ed5d5720SPeter Avalos if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
460*ed5d5720SPeter Avalos lfu_item = TAILQ_LAST(&(lfu_policy->groups[i]),
461*ed5d5720SPeter Avalos cache_lfu_policy_group_);
462*ed5d5720SPeter Avalos break;
463*ed5d5720SPeter Avalos }
464*ed5d5720SPeter Avalos
465*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_get_last_item);
466*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)lfu_item);
467*ed5d5720SPeter Avalos }
468*ed5d5720SPeter Avalos
469*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_lfu_policy_get_next_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)470*ed5d5720SPeter Avalos cache_lfu_policy_get_next_item(struct cache_policy_ *policy,
471*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
472*ed5d5720SPeter Avalos {
473*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
474*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
475*ed5d5720SPeter Avalos int i;
476*ed5d5720SPeter Avalos
477*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_get_next_item);
478*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
479*ed5d5720SPeter Avalos lfu_item = TAILQ_NEXT((struct cache_lfu_policy_item_ *)item, entries);
480*ed5d5720SPeter Avalos if (lfu_item == NULL)
481*ed5d5720SPeter Avalos {
482*ed5d5720SPeter Avalos for (i = ((struct cache_lfu_policy_item_ *)item)->frequency + 1;
483*ed5d5720SPeter Avalos i < CACHELIB_MAX_FREQUENCY; ++i) {
484*ed5d5720SPeter Avalos if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
485*ed5d5720SPeter Avalos lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
486*ed5d5720SPeter Avalos break;
487*ed5d5720SPeter Avalos }
488*ed5d5720SPeter Avalos }
489*ed5d5720SPeter Avalos }
490*ed5d5720SPeter Avalos
491*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_get_next_item);
492*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)lfu_item);
493*ed5d5720SPeter Avalos }
494*ed5d5720SPeter Avalos
495*ed5d5720SPeter Avalos static struct cache_policy_item_ *
cache_lfu_policy_get_prev_item(struct cache_policy_ * policy,struct cache_policy_item_ * item)496*ed5d5720SPeter Avalos cache_lfu_policy_get_prev_item(struct cache_policy_ *policy,
497*ed5d5720SPeter Avalos struct cache_policy_item_ *item)
498*ed5d5720SPeter Avalos {
499*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
500*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
501*ed5d5720SPeter Avalos int i;
502*ed5d5720SPeter Avalos
503*ed5d5720SPeter Avalos TRACE_IN(cache_lfu_policy_get_prev_item);
504*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
505*ed5d5720SPeter Avalos lfu_item = TAILQ_PREV((struct cache_lfu_policy_item_ *)item,
506*ed5d5720SPeter Avalos cache_lfu_policy_group_, entries);
507*ed5d5720SPeter Avalos if (lfu_item == NULL)
508*ed5d5720SPeter Avalos {
509*ed5d5720SPeter Avalos for (i = ((struct cache_lfu_policy_item_ *)item)->frequency - 1;
510*ed5d5720SPeter Avalos i >= 0; --i)
511*ed5d5720SPeter Avalos if (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
512*ed5d5720SPeter Avalos lfu_item = TAILQ_LAST(&(lfu_policy->groups[i]),
513*ed5d5720SPeter Avalos cache_lfu_policy_group_);
514*ed5d5720SPeter Avalos break;
515*ed5d5720SPeter Avalos }
516*ed5d5720SPeter Avalos }
517*ed5d5720SPeter Avalos
518*ed5d5720SPeter Avalos TRACE_OUT(cache_lfu_policy_get_prev_item);
519*ed5d5720SPeter Avalos return ((struct cache_policy_item_ *)lfu_item);
520*ed5d5720SPeter Avalos }
521*ed5d5720SPeter Avalos
522*ed5d5720SPeter Avalos /*
523*ed5d5720SPeter Avalos * Initializes the cache_policy_ structure by filling it with appropriate
524*ed5d5720SPeter Avalos * functions pointers
525*ed5d5720SPeter Avalos */
526*ed5d5720SPeter Avalos struct cache_policy_ *
init_cache_lfu_policy(void)527*ed5d5720SPeter Avalos init_cache_lfu_policy(void)
528*ed5d5720SPeter Avalos {
529*ed5d5720SPeter Avalos int i;
530*ed5d5720SPeter Avalos struct cache_lfu_policy_ *retval;
531*ed5d5720SPeter Avalos
532*ed5d5720SPeter Avalos TRACE_IN(init_cache_lfu_policy);
533*ed5d5720SPeter Avalos retval = (struct cache_lfu_policy_ *)calloc(1,
534*ed5d5720SPeter Avalos sizeof(struct cache_lfu_policy_));
535*ed5d5720SPeter Avalos assert(retval != NULL);
536*ed5d5720SPeter Avalos
537*ed5d5720SPeter Avalos retval->parent_data.create_item_func = cache_lfu_policy_create_item;
538*ed5d5720SPeter Avalos retval->parent_data.destroy_item_func = cache_lfu_policy_destroy_item;
539*ed5d5720SPeter Avalos
540*ed5d5720SPeter Avalos retval->parent_data.add_item_func = cache_lfu_policy_add_item;
541*ed5d5720SPeter Avalos retval->parent_data.update_item_func = cache_lfu_policy_update_item;
542*ed5d5720SPeter Avalos retval->parent_data.remove_item_func = cache_lfu_policy_remove_item;
543*ed5d5720SPeter Avalos
544*ed5d5720SPeter Avalos retval->parent_data.get_first_item_func =
545*ed5d5720SPeter Avalos cache_lfu_policy_get_first_item;
546*ed5d5720SPeter Avalos retval->parent_data.get_last_item_func =
547*ed5d5720SPeter Avalos cache_lfu_policy_get_last_item;
548*ed5d5720SPeter Avalos retval->parent_data.get_next_item_func =
549*ed5d5720SPeter Avalos cache_lfu_policy_get_next_item;
550*ed5d5720SPeter Avalos retval->parent_data.get_prev_item_func =
551*ed5d5720SPeter Avalos cache_lfu_policy_get_prev_item;
552*ed5d5720SPeter Avalos
553*ed5d5720SPeter Avalos for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i)
554*ed5d5720SPeter Avalos TAILQ_INIT(&(retval->groups[i]));
555*ed5d5720SPeter Avalos
556*ed5d5720SPeter Avalos TRACE_OUT(init_cache_lfu_policy);
557*ed5d5720SPeter Avalos return ((struct cache_policy_ *)retval);
558*ed5d5720SPeter Avalos }
559*ed5d5720SPeter Avalos
560*ed5d5720SPeter Avalos void
destroy_cache_lfu_policy(struct cache_policy_ * policy)561*ed5d5720SPeter Avalos destroy_cache_lfu_policy(struct cache_policy_ *policy)
562*ed5d5720SPeter Avalos {
563*ed5d5720SPeter Avalos int i;
564*ed5d5720SPeter Avalos struct cache_lfu_policy_ *lfu_policy;
565*ed5d5720SPeter Avalos struct cache_lfu_policy_item_ *lfu_item;
566*ed5d5720SPeter Avalos
567*ed5d5720SPeter Avalos TRACE_IN(destroy_cache_lfu_policy);
568*ed5d5720SPeter Avalos lfu_policy = (struct cache_lfu_policy_ *)policy;
569*ed5d5720SPeter Avalos for (i = 0; i < CACHELIB_MAX_FREQUENCY; ++i) {
570*ed5d5720SPeter Avalos while (!TAILQ_EMPTY(&(lfu_policy->groups[i]))) {
571*ed5d5720SPeter Avalos lfu_item = TAILQ_FIRST(&(lfu_policy->groups[i]));
572*ed5d5720SPeter Avalos TAILQ_REMOVE(&(lfu_policy->groups[i]), lfu_item,
573*ed5d5720SPeter Avalos entries);
574*ed5d5720SPeter Avalos cache_lfu_policy_destroy_item(
575*ed5d5720SPeter Avalos (struct cache_policy_item_ *)lfu_item);
576*ed5d5720SPeter Avalos }
577*ed5d5720SPeter Avalos }
578*ed5d5720SPeter Avalos free(policy);
579*ed5d5720SPeter Avalos TRACE_OUT(destroy_cache_lfu_policy);
580*ed5d5720SPeter Avalos }
581