3 * $Id: store_repl_lru.cc,v 1.15 2003/09/06 12:47:39 robertc Exp $
5 * DEBUG: section ? LRU Removal policy
6 * AUTHOR: Henrik Nordstrom
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
38 #include "MemObject.h"
40 REMOVALPOLICYCREATE createRemovalPolicy_lru
;
44 void setPolicyNode (StoreEntry
*, void *) const;
45 RemovalPolicy
*policy
;
49 enum heap_entry_type
{
50 TYPE_UNKNOWN
= 0, TYPE_STORE_ENTRY
, TYPE_STORE_MEM
54 /* Hack to avoid having to remember the RemovalPolicyNode location.
55 * Needed by the purge walker to clear the policy information
57 static enum LruPolicyData::heap_entry_type
58 repl_guessType(StoreEntry
* entry
, RemovalPolicyNode
* node
)
60 if (node
== &entry
->repl
)
61 return LruPolicyData::TYPE_STORE_ENTRY
;
63 if (entry
->mem_obj
&& node
== &entry
->mem_obj
->repl
)
64 return LruPolicyData::TYPE_STORE_MEM
;
66 fatal("Heap Replacement: Unknown StoreEntry node type");
68 return LruPolicyData::TYPE_UNKNOWN
;
72 LruPolicyData::setPolicyNode (StoreEntry
*entry
, void *value
) const
76 case TYPE_STORE_ENTRY
:
77 entry
->repl
.data
= value
;
81 entry
->mem_obj
->repl
.data
= value
;
89 typedef struct _LruNode LruNode
;
93 /* Note: the dlink_node MUST be the first member of the LruNode
94 * structure. This member is later pointer typecasted to LruNode *.
99 static MemPool
*lru_node_pool
= NULL
;
100 static int nr_lru_policies
= 0;
103 lru_add(RemovalPolicy
* policy
, StoreEntry
* entry
, RemovalPolicyNode
* node
)
105 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
108 node
->data
= lru_node
= (LruNode
*)memPoolAlloc(lru_node_pool
);
109 dlinkAddTail(entry
, &lru_node
->node
, &lru
->list
);
113 lru
->type
= repl_guessType(entry
, node
);
117 lru_remove(RemovalPolicy
* policy
, StoreEntry
* entry
, RemovalPolicyNode
* node
)
119 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
120 LruNode
*lru_node
= (LruNode
*)node
->data
;
126 * It seems to be possible for an entry to exist in the hash
127 * but not be in the LRU list, so check for that case rather
128 * than suffer a NULL pointer access.
130 if (NULL
== lru_node
->node
.data
)
133 assert(lru_node
->node
.data
== entry
);
137 dlinkDelete(&lru_node
->node
, &lru
->list
);
139 memPoolFree(lru_node_pool
, lru_node
);
145 lru_referenced(RemovalPolicy
* policy
, const StoreEntry
* entry
,
146 RemovalPolicyNode
* node
)
148 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
149 LruNode
*lru_node
= (LruNode
*)node
->data
;
154 dlinkDelete(&lru_node
->node
, &lru
->list
);
156 dlinkAddTail((void *) entry
, &lru_node
->node
, &lru
->list
);
159 /** RemovalPolicyWalker **/
161 typedef struct _LruWalkData LruWalkData
;
168 static const StoreEntry
*
169 lru_walkNext(RemovalPolicyWalker
* walker
)
171 LruWalkData
*lru_walk
= (LruWalkData
*)walker
->_data
;
172 LruNode
*lru_node
= lru_walk
->current
;
177 lru_walk
->current
= (LruNode
*) lru_node
->node
.next
;
179 return (StoreEntry
*) lru_node
->node
.data
;
183 lru_walkDone(RemovalPolicyWalker
* walker
)
185 RemovalPolicy
*policy
= walker
->_policy
;
186 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
187 assert(strcmp(policy
->_type
, "lru") == 0);
188 assert(lru
->nwalkers
> 0);
190 safe_free(walker
->_data
);
194 static RemovalPolicyWalker
*
195 lru_walkInit(RemovalPolicy
* policy
)
197 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
198 RemovalPolicyWalker
*walker
;
199 LruWalkData
*lru_walk
;
201 walker
= cbdataAlloc(RemovalPolicyWalker
);
202 lru_walk
= (LruWalkData
*)xcalloc(1, sizeof(*lru_walk
));
203 walker
->_policy
= policy
;
204 walker
->_data
= lru_walk
;
205 walker
->Next
= lru_walkNext
;
206 walker
->Done
= lru_walkDone
;
207 lru_walk
->current
= (LruNode
*) lru
->list
.head
;
211 /** RemovalPurgeWalker **/
213 typedef struct _LruPurgeData LruPurgeData
;
222 lru_purgeNext(RemovalPurgeWalker
* walker
)
224 LruPurgeData
*lru_walker
= (LruPurgeData
*)walker
->_data
;
225 RemovalPolicy
*policy
= walker
->_policy
;
226 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
231 lru_node
= lru_walker
->current
;
233 if (!lru_node
|| walker
->scanned
>= walker
->max_scan
)
236 walker
->scanned
+= 1;
238 lru_walker
->current
= (LruNode
*) lru_node
->node
.next
;
240 if (lru_walker
->current
== lru_walker
->start
) {
241 /* Last node found */
242 lru_walker
->current
= NULL
;
245 entry
= (StoreEntry
*) lru_node
->node
.data
;
246 dlinkDelete(&lru_node
->node
, &lru
->list
);
248 if (storeEntryLocked(entry
)) {
249 /* Shit, it is locked. we can't return this one */
251 dlinkAddTail(entry
, &lru_node
->node
, &lru
->list
);
255 memPoolFree(lru_node_pool
, lru_node
);
257 lru
->setPolicyNode(entry
, NULL
);
262 lru_purgeDone(RemovalPurgeWalker
* walker
)
264 RemovalPolicy
*policy
= walker
->_policy
;
265 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
266 assert(strcmp(policy
->_type
, "lru") == 0);
267 assert(lru
->nwalkers
> 0);
269 safe_free(walker
->_data
);
273 static RemovalPurgeWalker
*
274 lru_purgeInit(RemovalPolicy
* policy
, int max_scan
)
276 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
277 RemovalPurgeWalker
*walker
;
278 LruPurgeData
*lru_walk
;
280 walker
= cbdataAlloc(RemovalPurgeWalker
);
281 lru_walk
= (LruPurgeData
*)xcalloc(1, sizeof(*lru_walk
));
282 walker
->_policy
= policy
;
283 walker
->_data
= lru_walk
;
284 walker
->max_scan
= max_scan
;
285 walker
->Next
= lru_purgeNext
;
286 walker
->Done
= lru_purgeDone
;
287 lru_walk
->start
= lru_walk
->current
= (LruNode
*) lru
->list
.head
;
292 lru_stats(RemovalPolicy
* policy
, StoreEntry
* sentry
)
294 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
295 LruNode
*lru_node
= (LruNode
*) lru
->list
.head
;
300 StoreEntry
*entry
= (StoreEntry
*) lru_node
->node
.data
;
302 if (storeEntryLocked(entry
)) {
303 lru_node
= (LruNode
*) lru_node
->node
.next
;
307 storeAppendPrintf(sentry
, "LRU reference age: %.2f days\n", (double) (squid_curtime
- entry
->lastref
) / (double) (24 * 60 * 60));
312 lru_free(RemovalPolicy
* policy
)
314 LruPolicyData
*lru
= (LruPolicyData
*)policy
->_data
;
315 /* Make some verification of the policy state */
316 assert(strcmp(policy
->_type
, "lru") == 0);
317 assert(lru
->nwalkers
);
319 /* Ok, time to destroy this policy */
321 memset(policy
, 0, sizeof(*policy
));
326 createRemovalPolicy_lru(wordlist
* args
)
328 RemovalPolicy
*policy
;
329 LruPolicyData
*lru_data
;
330 /* no arguments expected or understood */
334 if (!lru_node_pool
) {
335 lru_node_pool
= memPoolCreate("LRU policy node", sizeof(LruNode
));
336 memPoolSetChunkSize(lru_node_pool
, 512 * 1024);
339 /* Allocate the needed structures */
340 lru_data
= (LruPolicyData
*)xcalloc(1, sizeof(*lru_data
));
342 policy
= cbdataAlloc(RemovalPolicy
);
344 /* Initialize the URL data */
345 lru_data
->policy
= policy
;
347 /* Populate the policy structure */
348 policy
->_type
= "lru";
350 policy
->_data
= lru_data
;
352 policy
->Free
= lru_free
;
354 policy
->Add
= lru_add
;
356 policy
->Remove
= lru_remove
;
358 policy
->Referenced
= lru_referenced
;
360 policy
->Dereferenced
= lru_referenced
;
362 policy
->WalkInit
= lru_walkInit
;
364 policy
->PurgeInit
= lru_purgeInit
;
366 policy
->Stats
= lru_stats
;
368 /* Increase policy usage count */
369 nr_lru_policies
+= 0;