3
* $Id: store_repl_heap.cc,v 1.21 2006/08/21 00:50:47 robertc Exp $
5
* DEBUG: section ? HEAP based 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;
57
void setPolicyNode (StoreEntry *, void *) const;
58
RemovalPolicy *policy;
60
heap_key_func *keyfunc;
63
enum heap_entry_type {
64
TYPE_UNKNOWN = 0, TYPE_STORE_ENTRY, TYPE_STORE_MEM
68
/* Hack to avoid having to remember the RemovalPolicyNode location.
69
* Needed by the purge walker.
71
static enum HeapPolicyData::heap_entry_type
72
heap_guessType(StoreEntry * entry, RemovalPolicyNode * node)
74
if (node == &entry->repl)
75
return HeapPolicyData::TYPE_STORE_ENTRY;
77
if (entry->mem_obj && node == &entry->mem_obj->repl)
78
return HeapPolicyData::TYPE_STORE_MEM;
80
fatal("Heap Replacement: Unknown StoreEntry node type");
82
return HeapPolicyData::TYPE_UNKNOWN;
86
HeapPolicyData::setPolicyNode (StoreEntry *entry, void *value) const
90
case TYPE_STORE_ENTRY:
91
entry->repl.data = value;
95
entry->mem_obj->repl.data = value ;
104
heap_add(RemovalPolicy * policy, StoreEntry * entry, RemovalPolicyNode * node)
106
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
109
if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
110
return; /* We won't manage these.. they messes things up */
112
node->data = heap_insert(heap->theHeap, entry);
117
heap->type = heap_guessType(entry, node);
119
/* Add a little more variance to the aging factor */
120
heap->theHeap->age += heap->theHeap->age / 100000000;
124
heap_remove(RemovalPolicy * policy, StoreEntry * entry,
125
RemovalPolicyNode * node)
127
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
128
heap_node *hnode = (heap_node *)node->data;
133
heap_delete(heap->theHeap, hnode);
141
heap_referenced(RemovalPolicy * policy, const StoreEntry * entry,
142
RemovalPolicyNode * node)
144
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
145
heap_node *hnode = (heap_node *)node->data;
150
heap_update(heap->theHeap, hnode, (StoreEntry *) entry);
153
/** RemovalPolicyWalker **/
155
typedef struct _HeapWalkData HeapWalkData;
162
static const StoreEntry *
163
heap_walkNext(RemovalPolicyWalker * walker)
165
HeapWalkData *heap_walk = (HeapWalkData *)walker->_data;
166
RemovalPolicy *policy = walker->_policy;
167
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
170
if (heap_walk->current >= heap_nodes(heap->theHeap))
171
return NULL; /* done */
173
entry = (StoreEntry *) heap_peep(heap->theHeap, heap_walk->current++);
179
heap_walkDone(RemovalPolicyWalker * walker)
181
RemovalPolicy *policy = walker->_policy;
182
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
183
assert(strcmp(policy->_type, "heap") == 0);
184
assert(heap->nwalkers > 0);
186
safe_free(walker->_data);
190
static RemovalPolicyWalker *
191
heap_walkInit(RemovalPolicy * policy)
193
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
194
RemovalPolicyWalker *walker;
195
HeapWalkData *heap_walk;
197
walker = new RemovalPolicyWalker;
198
heap_walk = (HeapWalkData *)xcalloc(1, sizeof(*heap_walk));
199
heap_walk->current = 0;
200
walker->_policy = policy;
201
walker->_data = heap_walk;
202
walker->Next = heap_walkNext;
203
walker->Done = heap_walkDone;
207
/** RemovalPurgeWalker **/
209
typedef struct _HeapPurgeData HeapPurgeData;
211
struct _HeapPurgeData
213
link_list *locked_entries;
218
heap_purgeNext(RemovalPurgeWalker * walker)
220
HeapPurgeData *heap_walker = (HeapPurgeData *)walker->_data;
221
RemovalPolicy *policy = walker->_policy;
222
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
228
if (!heap_nodes(heap->theHeap) > 0)
229
return NULL; /* done */
231
age = heap_peepminkey(heap->theHeap);
233
entry = (StoreEntry *)heap_extractmin(heap->theHeap);
235
if (storeEntryLocked(entry)) {
240
linklistPush(&heap_walker->locked_entries, entry);
245
heap_walker->min_age = age;
246
heap->setPolicyNode(entry, NULL);
251
heap_purgeDone(RemovalPurgeWalker * walker)
253
HeapPurgeData *heap_walker = (HeapPurgeData *)walker->_data;
254
RemovalPolicy *policy = walker->_policy;
255
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
257
assert(strcmp(policy->_type, "heap") == 0);
258
assert(heap->nwalkers > 0);
261
if (heap_walker->min_age > 0) {
262
heap->theHeap->age = heap_walker->min_age;
263
debug(81, 3) ("heap_purgeDone: Heap age set to %f\n",
264
(double) heap->theHeap->age);
268
* Reinsert the locked entries
270
while ((entry = (StoreEntry *)linklistShift(&heap_walker->locked_entries))) {
271
heap_node *node = heap_insert(heap->theHeap, entry);
272
heap->setPolicyNode(entry, node);
276
safe_free(walker->_data);
280
static RemovalPurgeWalker *
281
heap_purgeInit(RemovalPolicy * policy, int max_scan)
283
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
284
RemovalPurgeWalker *walker;
285
HeapPurgeData *heap_walk;
287
walker = new RemovalPurgeWalker;
288
heap_walk = (HeapPurgeData *)xcalloc(1, sizeof(*heap_walk));
289
heap_walk->min_age = 0.0;
290
heap_walk->locked_entries = NULL;
291
walker->_policy = policy;
292
walker->_data = heap_walk;
293
walker->max_scan = max_scan;
294
walker->Next = heap_purgeNext;
295
walker->Done = heap_purgeDone;
300
heap_free(RemovalPolicy * policy)
302
HeapPolicyData *heap = (HeapPolicyData *)policy->_data;
303
/* Make some verification of the policy state */
304
assert(strcmp(policy->_type, "heap") == 0);
305
assert(heap->nwalkers);
307
/* Ok, time to destroy this policy */
309
memset(policy, 0, sizeof(*policy));
314
createRemovalPolicy_heap(wordlist * args)
316
RemovalPolicy *policy;
317
HeapPolicyData *heap_data;
319
/* Allocate the needed structures */
320
policy = new RemovalPolicy;
321
heap_data = (HeapPolicyData *)xcalloc(1, sizeof(*heap_data));
322
/* Initialize the policy data */
323
heap_data->policy = policy;
329
debug(81, 1) ("createRemovalPolicy_heap: No key type specified. Using LRU\n");
333
if (!strcmp(keytype, "GDSF"))
334
heap_data->keyfunc = HeapKeyGen_StoreEntry_GDSF;
335
else if (!strcmp(keytype, "LFUDA"))
336
heap_data->keyfunc = HeapKeyGen_StoreEntry_LFUDA;
337
else if (!strcmp(keytype, "LRU"))
338
heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU;
340
debug(81, 0) ("createRemovalPolicy_heap: Unknown key type \"%s\". Using LRU\n",
342
heap_data->keyfunc = HeapKeyGen_StoreEntry_LRU;
345
/* No additional arguments expected */
348
heap_data->theHeap = new_heap(1000, heap_data->keyfunc);
350
heap_data->theHeap->age = 1.0;
352
/* Populate the policy structure */
353
policy->_type = "heap";
355
policy->_data = heap_data;
357
policy->Free = heap_free;
359
policy->Add = heap_add;
361
policy->Remove = heap_remove;
363
policy->Referenced = NULL;
365
policy->Dereferenced = heap_referenced;
367
policy->WalkInit = heap_walkInit;
369
policy->PurgeInit = heap_purgeInit;
371
/* Increase policy usage count */
372
nr_heap_policies += 0;