5
* DEBUG: section 81 Store HEAP Removal Policies
6
* AUTHOR: Henrik Nordstrom
8
* Based on the ideas of the heap policy implemented by John Dilley of
9
* Hewlett Packard. Rewritten from scratch when modularizing the removal
10
* policy implementation of Squid.
12
* For details on the original heap policy work and the thinking behind see
13
* http://www.hpl.hp.com/techreports/1999/HPL-1999-69.html
16
* SQUID Web Proxy Cache http://www.squid-cache.org/
17
* ----------------------------------------------------------
19
* Squid is the result of efforts by numerous individuals from
20
* the Internet community; see the CONTRIBUTORS file for full
21
* details. Many organizations have provided support for Squid's
22
* development; see the SPONSORS file for full details. Squid is
23
* Copyrighted (C) 2001 by the Regents of the University of
24
* California; see the COPYRIGHT file for full details. Squid
25
* incorporates software developed and/or copyrighted by other
26
* sources; see the CREDITS file for full details.
28
* This program is free software; you can redistribute it and/or modify
29
* it under the terms of the GNU General Public License as published by
30
* the Free Software Foundation; either version 2 of the License, or
31
* (at your option) any later version.
33
* This program is distributed in the hope that it will be useful,
34
* but WITHOUT ANY WARRANTY; without even the implied warranty of
35
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36
* GNU General Public License for more details.
38
* You should have received a copy of the GNU General Public License
39
* along with this program; if not, write to the Free Software
40
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
46
#include "store_heap_replacement.h"
48
#include "MemObject.h"
51
REMOVALPOLICYCREATE createRemovalPolicy_heap;
53
static int nr_heap_policies = 0;
55
struct HeapPolicyData {
56
void setPolicyNode (StoreEntry *, void *) const;
57
RemovalPolicy *policy;
59
heap_key_func *keyfunc;
62
enum heap_entry_type {
63
TYPE_UNKNOWN = 0, TYPE_STORE_ENTRY, TYPE_STORE_MEM
67
/* Hack to avoid having to remember the RemovalPolicyNode location.
68
* Needed by the purge walker.
70
static enum HeapPolicyData::heap_entry_type
71
heap_guessType(StoreEntry * entry, RemovalPolicyNode * node)
73
if (node == &entry->repl)
74
return HeapPolicyData::TYPE_STORE_ENTRY;
76
if (entry->mem_obj && node == &entry->mem_obj->repl)
77
return HeapPolicyData::TYPE_STORE_MEM;
79
fatal("Heap Replacement: Unknown StoreEntry node type");
81
return HeapPolicyData::TYPE_UNKNOWN;
85
HeapPolicyData::setPolicyNode (StoreEntry *entry, void *value) const
89
case TYPE_STORE_ENTRY:
90
entry->repl.data = value;
94
entry->mem_obj->repl.data = value ;
103
heap_add(RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node)
105
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
108
if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
109
return; /* We won't manage these.. they messes things up */
111
node->data = heap_insert(heap->theHeap, entry);
116
heap->type = heap_guessType(entry, node);
118
/* Add a little more variance to the aging factor */
119
heap->theHeap->age += heap->theHeap->age / 100000000;
123
heap_remove(RemovalPolicy * policy, StoreEntry * entry,
124
RemovalPolicyNode * node)
126
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
127
heap_node *hnode = (heap_node *)node->data;
132
heap_delete(heap->theHeap, hnode);
140
heap_referenced(RemovalPolicy * policy, const StoreEntry * entry,
141
RemovalPolicyNode * node)
143
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
144
heap_node *hnode = (heap_node *)node->data;
149
heap_update(heap->theHeap, hnode, (StoreEntry *) entry);
152
/** RemovalPolicyWalker **/
154
typedef struct _HeapWalkData HeapWalkData;
156
struct _HeapWalkData {
160
static const StoreEntry *
161
heap_walkNext(RemovalPolicyWalker * walker)
163
HeapWalkData *heap_walk = (HeapWalkData *)walker->_data;
164
RemovalPolicy *policy = walker->_policy;
165
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
168
if (heap_walk->current >= heap_nodes(heap->theHeap))
169
return NULL; /* done */
171
entry = (StoreEntry *) heap_peep(heap->theHeap, heap_walk->current++);
177
heap_walkDone(RemovalPolicyWalker * walker)
179
RemovalPolicy *policy = walker->_policy;
180
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
181
assert(strcmp(policy->_type, "heap") == 0);
182
assert(heap->nwalkers > 0);
184
safe_free(walker->_data);
188
static RemovalPolicyWalker *
189
heap_walkInit(RemovalPolicy * policy)
191
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
192
RemovalPolicyWalker *walker;
193
HeapWalkData *heap_walk;
195
walker = new RemovalPolicyWalker;
196
heap_walk = (HeapWalkData *)xcalloc(1, sizeof(*heap_walk));
197
heap_walk->current = 0;
198
walker->_policy = policy;
199
walker->_data = heap_walk;
200
walker->Next = heap_walkNext;
201
walker->Done = heap_walkDone;
205
/** RemovalPurgeWalker **/
207
typedef struct _HeapPurgeData HeapPurgeData;
209
struct _HeapPurgeData {
210
link_list *locked_entries;
215
heap_purgeNext(RemovalPurgeWalker * walker)
217
HeapPurgeData *heap_walker = (HeapPurgeData *)walker->_data;
218
RemovalPolicy *policy = walker->_policy;
219
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
225
if (!heap_nodes(heap->theHeap) > 0)
226
return NULL; /* done */
228
age = heap_peepminkey(heap->theHeap);
230
entry = (StoreEntry *)heap_extractmin(heap->theHeap);
232
if (entry->locked()) {
235
linklistPush(&heap_walker->locked_entries, entry);
240
heap_walker->min_age = age;
241
heap->setPolicyNode(entry, NULL);
246
heap_purgeDone(RemovalPurgeWalker * walker)
248
HeapPurgeData *heap_walker = (HeapPurgeData *)walker->_data;
249
RemovalPolicy *policy = walker->_policy;
250
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
252
assert(strcmp(policy->_type, "heap") == 0);
253
assert(heap->nwalkers > 0);
256
if (heap_walker->min_age > 0) {
257
heap->theHeap->age = heap_walker->min_age;
258
debugs(81, 3, "heap_purgeDone: Heap age set to " << heap->theHeap->age );
262
* Reinsert the locked entries
264
while ((entry = (StoreEntry *)linklistShift(&heap_walker->locked_entries))) {
265
heap_node *node = heap_insert(heap->theHeap, entry);
266
heap->setPolicyNode(entry, node);
270
safe_free(walker->_data);
274
static RemovalPurgeWalker *
275
heap_purgeInit(RemovalPolicy * policy, int max_scan)
277
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
278
RemovalPurgeWalker *walker;
279
HeapPurgeData *heap_walk;
281
walker = new RemovalPurgeWalker;
282
heap_walk = (HeapPurgeData *)xcalloc(1, sizeof(*heap_walk));
283
heap_walk->min_age = 0.0;
284
heap_walk->locked_entries = NULL;
285
walker->_policy = policy;
286
walker->_data = heap_walk;
287
walker->max_scan = max_scan;
288
walker->Next = heap_purgeNext;
289
walker->Done = heap_purgeDone;
294
heap_free(RemovalPolicy * policy)
296
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
297
/* Make some verification of the policy state */
298
assert(strcmp(policy->_type, "heap") == 0);
299
assert(heap->nwalkers);
301
/* Ok, time to destroy this policy */
303
memset(policy, 0, sizeof(*policy));
308
createRemovalPolicy_heap(wordlist * args)
310
RemovalPolicy *policy;
311
HeapPolicyData *heap_data;
313
/* Allocate the needed structures */
314
policy = new RemovalPolicy;
315
heap_data = (HeapPolicyData *)xcalloc(1, sizeof(*heap_data));
316
/* Initialize the policy data */
317
heap_data->policy = policy;
323
debugs(81, 1, "createRemovalPolicy_heap: No key type specified. Using LRU");
327
if (!strcmp(keytype, "GDSF"))
328
heap_data->keyfunc = HeapKeyGen_StoreEntry_GDSF;
329
else if (!strcmp(keytype, "LFUDA"))
330
heap_data->keyfunc = HeapKeyGen_StoreEntry_LFUDA;
331
else if (!strcmp(keytype, "LRU"))
332
heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU;
334
debugs(81, 0, "createRemovalPolicy_heap: Unknown key type \"" << keytype << "\". Using LRU");
335
heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU;
338
/* No additional arguments expected */
340
debugs(81, DBG_IMPORTANT, "WARNING: discarding unknown removal policy '" << args->key << "'");
344
heap_data->theHeap = new_heap(1000, heap_data->keyfunc);
346
heap_data->theHeap->age = 1.0;
348
/* Populate the policy structure */
349
policy->_type = "heap";
351
policy->_data = heap_data;
353
policy->Free = heap_free;
355
policy->Add = heap_add;
357
policy->Remove = heap_remove;
359
policy->Referenced = NULL;
361
policy->Dereferenced = heap_referenced;
363
policy->WalkInit = heap_walkInit;
365
policy->PurgeInit = heap_purgeInit;
367
/* Increase policy usage count */
368
nr_heap_policies += 0;