This patch is generated from the bugless-2_2 branch of s2_2 in squid
Fri Jan 30 10:15:11 2004 GMT
See http://devel.squid-cache.org/

Index: squid/makefile.in
diff -u squid/makefile.in:1.1.1.2 squid/makefile.in:1.1.1.2.12.1
--- squid/makefile.in:1.1.1.2	Tue Jan 25 19:23:09 2000
+++ squid/makefile.in	Fri Nov 10 10:44:50 2000
@@ -8,6 +8,7 @@
 INSTALL		= @INSTALL@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
 INSTALL_DATA	= @INSTALL_DATA@
+CFLAGS		= @CFLAGS@ -DHPL_REPL
 SHELL		= /bin/sh
 
 # Where to install
Index: squid/icons/Makefile.in
diff -u squid/icons/Makefile.in:1.1.1.2 squid/icons/Makefile.in:1.1.1.2.12.1
--- squid/icons/Makefile.in:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/icons/Makefile.in	Fri Nov 10 10:44:51 2000
@@ -43,7 +43,9 @@
 		  anthony-text.gif \
 		  anthony-unknown.gif \
 		  anthony-xbm.gif \
-		  anthony-xpm.gif
+		  anthony-xpm.gif \
+		  closeme.html \
+		  tiny.gif
 
 all:
 
Index: squid/include/hash.h
diff -u squid/include/hash.h:1.1.1.1 squid/include/hash.h:1.1.1.1.38.1
--- squid/include/hash.h:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/include/hash.h	Fri Nov 10 10:44:51 2000
@@ -24,8 +24,8 @@
 };
 
 extern hash_table *hash_create(HASHCMP *, int, HASHHASH *);
-extern void hash_join(hash_table *, hash_link *);
-extern void hash_remove_link(hash_table *, hash_link *);
+extern unsigned hash_join(hash_table *, hash_link *);
+extern unsigned hash_remove_link(hash_table *, hash_link *);
 extern int hashPrime(int n);
 extern void *hash_lookup(hash_table *, const void *);
 extern void hash_first(hash_table *);
Index: squid/include/heap.h
diff -u /dev/null squid/include/heap.h:1.3.6.1
--- /dev/null	Fri Jan 30 02:14:14 2004
+++ squid/include/heap.h	Fri Nov 10 10:44:51 2000
@@ -0,0 +1,156 @@
+/****************************************************************************
+ * Heap data structure.  Used to store objects for cache replacement.  The
+ * heap is implemented as a contiguous array in memory.  Heap sort and heap
+ * update are done in-place.  The heap is ordered with the smallest value at
+ * the top of the heap (as in the smallest object key value).  Child nodes
+ * are larger than their parent.
+ ****************************************************************************/
+
+#ifndef	_heap_h_INCLUDED
+#define	_heap_h_INCLUDED
+
+/* 
+ * Typdefs for non-synchronized heap implementation.
+ */
+typedef unsigned long	mutex_t;
+# define	mutex_lock(m)		(void)0
+# define	mutex_unlock(m)		(void)0
+# define	mutex_trylock(m)	(void)0
+# define	mutex_init(m)		((m)=123456)
+
+/*
+ * Function for generating heap keys.  The first argument will typically be
+ * a dws_md_p passed in as a void *.  Should find a way to get type safety
+ * without having heap know all about metadata objects...  The second arg is
+ * the current aging factor for the heap.
+ */
+# define	_HEAPTYPE	void *
+# define	_HEAPKEY	double
+# define	_HEAPKEYSTORED	float		/* no need to store doubles */
+
+typedef _HEAPKEY (*key_func) (_HEAPTYPE, _HEAPKEY);
+
+
+/*
+ * Heap node.  Has a key value generated by a key_func, id (array index) so
+ * it can be quickly found in its heap, and a pointer to a data object that
+ * key_func can generate a key from.
+ */
+typedef struct _heap_node {
+  _HEAPKEYSTORED	key;
+  long	id;
+} heap_node, *heap_node_p;
+
+
+/*
+ * Heap object.  Holds an array of heap_node objects along with a heap size
+ * (array length), the index of the last heap element, and a key generation
+ * function.  Also stores aging factor for this heap.
+ */
+typedef struct _heap {
+  mutex_t	lock;
+  unsigned long	size;
+  unsigned long	last;
+  size_t	nodeoffset;	/* offset from start of data to node struct */
+  key_func	gen_key;			/* key generator for heap */
+  _HEAPKEY	age;				/* aging factor for heap */
+  heap_node **	nodes;
+} heap, *heap_p;
+
+/****************************************************************************
+ * Public functions
+ ****************************************************************************/
+
+#define heap_DATA(hp,elm)	((_HEAPTYPE)((char*)(elm)-(hp)->nodeoffset))
+#define heap_ELM(hp,data)	((heap_node_p)((char*)(data)+(hp)->nodeoffset))
+
+/* 
+ * Create and initialize a new heap.
+ */
+extern	heap_p	new_heap(int init_size, key_func gen_key, size_t nodeoffset);
+
+/* 
+ * Delete a heap and clean up its memory.  Does not delete what the heap
+ * nodes are pointing to!
+ */
+extern	void	delete_heap(heap_p);
+
+/*
+ * Insert a new node into a heap, returning a pointer to it.  The heap_node
+ * object returned is used to update or delete a heap object.  Nothing else
+ * should be done with this data structure (especially modifying it!)  The
+ * heap does not assume ownership of the data passed to it.
+ */
+extern	heap_node_p 	heap_insert(heap_p, _HEAPTYPE dat);
+
+/*
+ * Delete a node out of a heap.  Returns the heap data from the deleted
+ * node.  The caller is responsible for freeing this data.
+ */
+extern	_HEAPTYPE	heap_delete(heap_p, heap_node_p elm);
+
+/*
+ * The semantics of this routine is the same as the followings:
+ *        heap_delete(hp, elm);
+ *        heap_insert(hp, dat);
+ * Returns the old data object from elm (the one being replaced).  The
+ * caller must free this as necessary.
+ */
+extern	void		heap_update(heap_p, heap_node* elm);
+
+/* 
+ * Generate a heap key for a given data object.  Alternative macro form:
+ */
+#ifdef	MACRO_DEBUG
+extern	_HEAPKEY	heap_gen_key(heap_p hp, _HEAPTYPE dat);
+#else
+# define	heap_gen_key(hp,md)	((hp)->gen_key((md),(hp)->age))
+#endif	/* MACRO_DEBUG */
+
+
+/* 
+ * Extract the minimum (root) element and maintain the heap property.
+ * Returns the data pointed to by the root node, which the caller must
+ * free as necessary.
+ */
+extern	_HEAPTYPE	heap_extractmin(heap_p);
+
+/* 
+ * Extract the last leaf node (does not change the heap property).
+ * Returns the data that had been in the heap which the caller must free if
+ * necessary.  Note that the last node is guaranteed to be less than its
+ * parent, but may not be less than any of the other (leaf or parent) notes
+ * in the tree.  This operation is fast but imprecise.
+ */
+extern	_HEAPTYPE	heap_extractlast(heap_p hp);
+
+/* 
+ * Get the root key, the nth key, the root (smallest) element, or the nth
+ * element.  None of these operations modify the heap.
+ */
+extern	_HEAPKEY	heap_peepminkey(heap_p);
+extern	_HEAPKEY	heap_peepkey(heap_p, int n);
+
+extern	_HEAPTYPE	heap_peepmin(heap_p);
+extern	_HEAPTYPE	heap_peep(heap_p, int n);
+
+/* 
+ * Is the heap empty?  How many nodes (data objects) are in it? 
+ */
+#ifdef	MACRO_DEBUG
+extern	int	heap_empty(heap_p);
+extern	int	heap_nodes(heap_p);
+#else	/* MACRO_DEBUG */
+# define	heap_nodes(heap)	((heap)->last)
+# define	heap_empty(heap)	(((heap)->last <= 0) ? 1 : 0)
+#endif	/* MACRO_DEBUG */
+
+/* 
+ * Print the heap or a node in the heap.
+ */
+extern	void	heap_print(heap_p);
+extern	void	heap_printnode(char *msg, heap_node_p elm);
+
+extern	int	verify_heap_property(heap_p);
+
+#endif	/* _heap_h_INCLUDED */
Index: squid/lib/Makefile.in
diff -u squid/lib/Makefile.in:1.1.1.1 squid/lib/Makefile.in:1.1.1.1.10.1
--- squid/lib/Makefile.in:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/lib/Makefile.in	Fri Nov 10 10:44:51 2000
@@ -37,6 +37,7 @@
 		  Array.o \
 		  Stack.o \
 		  hash.o \
+		  heap.o \
 		  $(LIBOBJS)
 REGEXOBJS	= GNUregex.o
 DLMALLOCOBJS	= dlmalloc.o
Index: squid/lib/hash.c
diff -u squid/lib/hash.c:1.1.1.2 squid/lib/hash.c:1.1.1.2.12.1
--- squid/lib/hash.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/lib/hash.c	Fri Nov 10 10:44:51 2000
@@ -163,14 +163,23 @@
  *
  *  It does not copy any data into the hash table, only links pointers.
  */
-void
+unsigned
 hash_join(hash_table * hid, hash_link * lnk)
 {
     int i;
     i = hid->hash(lnk->key, hid->size);
+#if 1
+    { /* srb */
+	hash_link * ol;
+	for (ol = hid->buckets[i]; ol; ol = ol->next)
+	    if (ol == lnk)
+		return 1;
+    }
+#endif
     lnk->next = hid->buckets[i];
     hid->buckets[i] = lnk;
     hid->count++;
+    return 0;
 }
 
 /*
@@ -252,7 +261,7 @@
  *  On success, it returns 0 and deletes the link; otherwise, 
  *  returns non-zero on error.
  */
-void
+unsigned
 hash_remove_link(hash_table * hid, hash_link * hl)
 {
     hash_link **P;
@@ -269,9 +278,12 @@
 		hash_next_bucket(hid);
 	}
 	hid->count--;
-	return;
+	return 0;
     }
+#if 0 /* srb */
     assert(0);
+#endif
+    return 1;
 }
 
 /*
Index: squid/lib/heap.c
diff -u /dev/null squid/lib/heap.c:1.3.6.1
--- /dev/null	Fri Jan 30 02:14:14 2004
+++ squid/lib/heap.c	Fri Nov 10 10:44:51 2000
@@ -0,0 +1,575 @@
+#define HPL_REPL	1
+/****************************************************************************
+ * Heap implementation
+ ****************************************************************************/
+
+#include <stdlib.h>
+#include "malloc.h"
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "heap.h"
+
+/* 
+ * Private function prototypes.
+ */
+static void _heap_ify_up(heap_p hp, heap_node_p elm);
+static void _heap_ify_down(heap_p hp, heap_node_p elm);
+static int _heap_should_grow(heap_p hp);
+static void _heap_grow(heap_p hp);
+static void _heap_swap_element(heap_p hp, heap_node_p elm1, heap_node_p elm2);
+static unsigned _heap_node_exist(heap_p hp, int id);
+
+#ifdef	HEAP_DEBUG
+void _heap_print_tree(heap_p hp, heap_node_p node);
+#endif	/* HEAP_DEBUG */
+
+#define Left(x) (2 * (size_t)(x) + 1)
+#define Right(x) (2 * (size_t)(x) + 2)
+#define Parent(x) (((size_t)(x)-1)/2)
+
+#define Threshold 10000
+#define NormalRate 2
+#define SlowRate 1.5
+#define MinSize 32
+
+/****************************************************************************
+ * Public functions
+ ****************************************************************************/
+
+/*
+ * Return a newly created heap. INITSIZE is the initial size of the heap.
+ */
+heap_p
+new_heap(int initSize, key_func gen_key, size_t nodeoffset)
+{
+  heap_p hp = (heap_p) malloc(sizeof(heap));
+  assert(hp != NULL);
+
+  if (initSize <= 0)
+    initSize = MinSize;
+
+  hp->nodes = (heap_node_p *)calloc(initSize, sizeof(heap_node_p));
+  assert(hp->nodes != NULL);
+
+  hp->size = initSize;
+  hp->last = 0;
+  hp->gen_key = gen_key;
+  hp->nodeoffset = nodeoffset;
+  hp->age = 0;
+
+  return hp;
+}
+
+
+/*
+ * Free memory used by a heap.  Does not free the metadata pointed to by the
+ * heap nodes, only the heap's internal memory.
+ */
+void
+delete_heap(heap_p hp)
+{
+  int i;
+  assert(hp);
+  free(hp->nodes);
+  free(hp);
+}
+
+/* 
+ * True if a node with ID exists in HP.
+ */
+static unsigned
+_heap_node_exist(heap_p hp, int id)
+{
+  if ((id >= hp->last) || (id < 0) || (hp->nodes[(size_t)id] == NULL) ||
+	hp->nodes[(size_t)id]->id != id)
+    return 0;
+  return 1;
+}
+
+/*
+ * Insert DAT based on KY into HP maintaining the heap property.  Return the
+ * newly inserted heap node. The fields of ELM other than ID are never
+ * changed until ELM is deleted from HP, i.e. caller can assume that the
+ * heap node always exist at the same place in memory unless heap_delete or
+ * heap_extractmin is called on that node.  This function exposes the heap's
+ * internal data structure to the caller.  This is required in order to do
+ * O(lgN) deletion.
+ */
+heap_node_p 
+heap_insert(heap_p hp, void * dat)
+{
+  heap_node* elm = heap_ELM(hp, dat);
+
+  elm->key = heap_gen_key(hp, dat);
+
+  if (_heap_should_grow(hp))
+    _heap_grow(hp);
+
+  hp->nodes[(size_t)hp->last] = elm;
+  elm->id = hp->last++;
+
+  _heap_ify_up(hp, elm);
+
+  /* 
+   * Set the pointer in the metadata to point to this heap node.
+   */
+  #ifdef	HPL_REPL
+  /* The following must be done immediately upon return! */
+  #else	/* HPL_REPL */
+  md_set_node(dat, elm);
+  #endif	/* HPL_REPL */
+
+  return elm;
+}
+
+static
+void _heap_order(heap_p hp, heap_node_p elm)
+{
+  if (elm->id > 0 &&
+	elm->key < hp->nodes[Parent(elm->id)]->key)
+      _heap_ify_up(hp, elm);			/* COOL! */
+  _heap_ify_down(hp, elm);
+}
+
+/*
+ * Delete ELM while maintaining the heap property. ELM may be modified.
+ * Assumes that ELM is not NULL and frees it.  Returns the data pointed to
+ * in, which the caller must free if necessary.
+ */
+_HEAPTYPE
+heap_delete(heap_p hp, heap_node_p elm)
+{
+  heap_node_p lastNode;
+  _HEAPTYPE data = heap_DATA(hp, elm);
+
+  assert(_heap_node_exist(hp, hp->last-1));
+
+  if (elm->id != --hp->last) {
+    lastNode = hp->nodes[(size_t)hp->last];
+    hp->nodes[(size_t)elm->id] = lastNode;
+    lastNode->id = elm->id;
+
+    _heap_order(hp, lastNode);
+  }
+
+  /* 
+   * Remove the pointer back to the heap from the metadata.
+   * Then free the element that was just deleted.
+   */
+  #ifdef	HPL_REPL
+  /* The following must be done immediately upon return! */
+  #else	/* HPL_REPL */
+  md_set_node(data, NULL);
+  #endif	/* HPL_REPL */
+
+  return data;
+}
+
+/* 
+ * Delete the last element (leaf) out of the heap.  Does not require a
+ * heapify operation.
+ */
+
+#ifndef	heap_gen_key
+/*
+ * Function to generate keys.  See macro definition in heap.h.
+ */
+_HEAPKEY
+heap_gen_key(heap_p hp, _HEAPTYPE dat)
+{
+  return hp->gen_key(dat, hp->age);
+}
+#endif	/* heap_gen_key */
+
+
+/* 
+ * Returns the data of the node with the largest KEY value and removes that
+ * node from the heap.  Returns NULL if the heap was empty.
+ */
+_HEAPTYPE
+heap_extractmin(heap_p hp)
+{
+  if (hp->last <= 0)
+    return NULL;
+
+  return heap_delete(hp, hp->nodes[0]);		/* Delete the root */
+}
+
+
+/* 
+ * Remove the last node in HP.  Frees the heap internal structure and
+ * returns the data pointes to by the last node.
+ */
+_HEAPTYPE
+heap_extractlast(heap_p hp)
+{
+  _HEAPTYPE data;
+  assert (_heap_node_exist(hp, hp->last-1));
+  data = heap_DATA(hp, hp->nodes[(size_t)--hp->last]);
+  return data;
+}
+
+
+/* 
+ * The semantics of this routine is the same as the followings:
+ *        heap_delete(hp, elm);
+ *        heap_insert(hp, dat);
+ * Returns the old data object from elm (the one being replaced).  The
+ * caller must free this as necessary.
+ */
+void
+heap_update(heap_p hp, heap_node* elm)
+{
+  _HEAPTYPE dat = heap_DATA(hp, elm);
+  _HEAPKEY ky = heap_gen_key(hp, dat);
+  assert (_heap_node_exist(hp, elm->id));
+
+  elm->key = ky;
+
+  _heap_order(hp, elm);
+}
+
+
+/* 
+ * A pointer to the root node's DATA.
+ */
+void*
+heap_peepmin(heap_p hp)
+{
+  assert(_heap_node_exist(hp, 0));
+  return heap_DATA(hp, hp->nodes[0]);
+}
+
+
+/* 
+ * The KEY of the root node.
+ */
+_HEAPKEY
+heap_peepminkey(heap_p hp)
+{
+  assert(_heap_node_exist(hp, 0));
+  return hp->nodes[0]->key;
+}
+
+
+/* 
+ * Same as heap_peep except that this return the KEY of the node.
+ * Only meant for iteration.
+ */
+_HEAPKEY
+heap_peepkey(heap_p hp, int n)
+{
+  assert(_heap_node_exist(hp, n));
+  return hp->nodes[(size_t)n]->key;
+}
+
+
+/* 
+ * A pointer to Nth node's DATA. The caller can iterate through HP by
+ * calling this routine.  eg. Caller can execute the following code:
+ *   for(i = 0; i < heap_nodes(hp); i++)
+ *      data = heap_peep(hp, i);
+ */
+void*
+heap_peep(heap_p hp, int n)
+{
+  assert(_heap_node_exist(hp, n));
+  return heap_DATA(hp, hp->nodes[(size_t)n]);
+}
+
+
+#ifndef	heap_nodes
+/* 
+ * Current number of nodes in HP.
+ */
+int
+heap_nodes(heap_p hp)
+{
+  return hp->last;
+}
+#endif	/* heap_nodes */
+
+
+#ifndef	heap_empty
+/* 
+ * Determine if the heap is empty.  Returns 1 if HP has no elements and 0
+ * otherwise.
+ */
+int
+heap_empty(heap_p hp)
+{
+  return (hp->last <= 0) ? 1 : 0;
+}
+#endif	/* heap_empty */
+
+/****************** Private Functions *******************/
+
+/* 
+ * Maintain the heap order property (parent is smaller than children) which
+ * may only be violated at ELM downwards.  Assumes caller has locked the heap.
+ */
+static void
+_heap_ify_down(heap_p hp, heap_node_p elm)
+{
+  heap_node* kid;
+  int left, right;
+  for(;;) {
+    assert(_heap_node_exist(hp, elm->id));
+    left = Left(elm->id);
+    right = Right(elm->id);
+    if (hp->last <= left)               // At the bottom of the heap (no child).
+      break;
+    else if (hp->last <= right) {       // Only left child exists.
+      assert(_heap_node_exist(hp, left));
+      kid = hp->nodes[(size_t)left];
+    } else {
+      assert(_heap_node_exist(hp, left));
+      assert(_heap_node_exist(hp, right));
+      if (hp->nodes[(size_t)right]->key < hp->nodes[(size_t)left]->key)
+	kid = hp->nodes[(size_t)right];
+      else
+	kid = hp->nodes[(size_t)left];
+    }
+    if (elm->key <= kid->key)
+      break;
+    _heap_swap_element(hp, kid, elm);
+  }
+}
+
+
+/* 
+ * Maintain the heap property above ELM.  Caller has locked the heap.
+ */
+static void
+_heap_ify_up(heap_p hp, heap_node_p elm)
+{
+  heap_node_p parentNode;
+  assert(_heap_node_exist(hp, elm->id));
+  while (elm->id > 0) {
+    assert(_heap_node_exist(hp, elm->id));
+    parentNode = hp->nodes[Parent(elm->id)];
+    assert(_heap_node_exist(hp, parentNode->id));
+    if (parentNode->key <= elm->key)
+      break;
+    _heap_swap_element(hp, parentNode, elm);  /* Demote the parent. */
+  }
+}
+
+
+/* 
+ * Swap the position of ELM1 and ELM2 in heap structure. Their IDs are also
+ * swapped. 
+ */
+static void
+_heap_swap_element(heap_p hp, heap_node_p elm1, heap_node_p elm2)
+{
+  int elm1Id = elm1->id;
+  elm1->id = elm2->id;
+  elm2->id = elm1Id;
+  hp->nodes[(size_t)elm1->id] = elm1;
+  hp->nodes[(size_t)elm2->id] = elm2;
+}
+
+
+
+#ifdef	NOTDEF
+/* 
+ * Copy KEY and DATA fields of SRC to DEST. ID field is NOT copied.
+ */
+static void
+_heap_copy_element(heap_node_p src, heap_node_p dest)
+{
+  dest->key = src->key;
+}
+#endif	/* NOTDEF */
+
+
+/* 
+ * True if HP needs to be grown in size.
+ */
+static int
+_heap_should_grow(heap_p hp)
+{
+  if (hp->size <= hp->last)
+    return 1;
+  return 0;
+}
+
+
+/* 
+ * Grow HP.
+ */
+static void
+_heap_grow(heap_p hp)
+{
+  int newSize;
+  //heap_node_p * newNodes;
+
+  if (hp->size > Threshold)
+    newSize = hp->size * SlowRate;
+  else
+    newSize = hp->size * NormalRate;
+
+  hp->nodes = (heap_node_p *)realloc(hp->nodes, newSize * sizeof(heap_node_p));
+  //for(i = 0; i < hp->size; i++)
+    //newNodes[i] = hp->nodes[i];
+  //free(hp->nodes);
+  //hp->nodes = newNodes;
+  hp->size = newSize;
+}
+
+
+/****************************************************************************
+ * Printing and debug functions
+ ****************************************************************************/
+
+/* 
+ * Print the heap in element order, id..last. 
+ */
+void
+heap_print_inorder(heap_p hp, int id)
+{
+  while (id < hp->last) {
+    printf("%d <- %d -> %d\tKey = %.04f\n", Parent(id), id, Left(id), hp->nodes[id]->key);
+    id++;
+  }
+}
+
+/*
+ * Returns 1 if HP maintians the heap property and 0 otherwise.
+ */
+int
+verify_heap_property(heap_p hp)
+{
+  int i = 0;
+  int correct = 1;
+  for(i = 0; i < hp->last / 2; i++) {
+    correct = 1;
+    if (_heap_node_exist(hp, Left(i)))
+      if (hp->nodes[i]->key > hp->nodes[Left(i)]->key)
+	correct = 0;
+    if (_heap_node_exist(hp, Right(i)))
+      if (hp->nodes[i]->key > hp->nodes[Right(i)]->key)
+	correct = 0;
+    if (!correct) {
+      printf("verifyHeap: violated at %d", i);
+      heap_print_inorder(hp, 0);
+      break;
+    }
+  }
+  return correct;
+}
+
+#ifdef	MEASURE_HEAP_SKEW
+
+/****************************************************************************
+ * Heap skew computation
+ ****************************************************************************/
+
+int 
+compare_heap_keys(const void * a, const void * b)
+{
+  heap_node ** an = (heap_node**)a;
+  heap_node ** bn = (heap_node**)b;
+  float cmp = (*an)->key - (*bn)->key;
+  if (cmp < 0)
+    return -1;
+  else
+    return 1;
+}
+
+/*
+ * Compute the heap skew for HEAP, a measure of how out-of-order the
+ * elements in the heap are.  The skew of a heap node is the difference
+ * between its current position in the heap and where it would be if the
+ * heap were in sorted order.  To compute this we have to sort the heap.  At
+ * the end if the flag REPLACE is non-zero the heap will be returned in
+ * sorted order (with skew == 0).  Note: using REPLACE does not help the
+ * performance of the heap, so only do this if you really want to have a
+ * sorted heap.  It is faster not to replace.
+ */
+float
+calc_heap_skew(heap_p heap, int replace)
+{
+  heap_node ** nodes;
+  long id, diff, skew = 0;
+  #ifdef	HEAP_DEBUG_SKEW
+  long skewsq = 0;
+  #endif	/* HEAP_DEBUG_SKEW */
+  float norm = 0;
+  unsigned long max;
+
+  /* 
+   * Lock the heap to copy it.  If replacing it need to keep the heap locked
+   * until we are all done.
+   */
+  mutex_lock(hp->lock);
+
+  max = heap_nodes(heap);
+
+  /* 
+   * Copy the heap nodes to a new storage area for offline sorting.
+   */
+  nodes = (heap_node **)malloc(max * sizeof(heap_node *));
+  memcpy(nodes, heap->nodes, max * sizeof(heap_node *));
+
+  if (replace == 0) {
+    /* 
+     * Unlock the heap to allow updates from other threads before the sort.
+     * This allows other heap operations to proceed concurrently with the
+     * heap skew computation on the heap at the time of the call ...
+     */
+    mutex_unlock(hp->lock);
+  }
+
+  qsort(nodes, max, sizeof(heap_node *), compare_heap_keys);
+
+  for (id=0; id < max; id++) {
+    diff = id - nodes[id]->id;
+    skew += abs(diff);
+
+    #ifdef	HEAP_DEBUG_SKEW
+    skewsq += diff*diff;
+    #ifdef	HEAP_DEBUG_ALL
+    printf("%d\tKey = %f, diff = %d\n", id, nodes[id]->key, diff);
+    #endif	/* HEAP_DEBUG */
+    #endif	/* HEAP_DEBUG_SKEW */
+  }
+
+  if (replace != 0) {
+    /* 
+     * Replace the original heap with the newly sorted heap and let it
+     * continue.  Then compute the skew using the copy of the previous heap
+     * which we maintain as private data.
+     */
+    memcpy(heap->nodes, nodes, max * sizeof(heap_node *));
+
+    for (id = 0; id < max; id++) {
+      /* 
+       * Fix up all the ID values in the copied nodes.
+       */
+      heap->nodes[id]->id = id;
+    }
+
+    mutex_unlock(hp->lock);
+  }
+
+  /* 
+   * The skew value is normalized to a range of [0..1]; the distribution
+   * appears to be a skewed Gaussian distribution.  For random insertions
+   * into a heap the normalized skew will be slightly less than 0.5.  The
+   * maximum value of skew/N^2 (for any value of N) is about 0.39 and is
+   * fairly stable.
+   */
+  norm = skew*2.56/(max*max);
+
+  /* 
+   * Free the nodes array; note this is just an array of pointers, not data!
+   */
+  free(nodes);
+  return norm;
+}
+
+#endif	/* MEASURE_HEAP_SKEW */
Index: squid/src/HttpHdrRange.c
diff -u squid/src/HttpHdrRange.c:1.1.1.2 squid/src/HttpHdrRange.c:1.1.1.2.12.1
--- squid/src/HttpHdrRange.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/HttpHdrRange.c	Fri Nov 10 10:44:52 2000
@@ -462,7 +462,7 @@
     assert(http);
     stringAppend(&b, full_appname_string, strlen(full_appname_string));
     stringAppend(&b, ":", 1);
-    key = storeKeyText(http->entry->key);
+    key = storeKeyText(http->entry->Skey);
     stringAppend(&b, key, strlen(key));
     return b;
 }
Index: squid/src/MemPool.c
diff -u squid/src/MemPool.c:1.1.1.2 squid/src/MemPool.c:1.1.1.2.12.1
--- squid/src/MemPool.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/MemPool.c	Fri Nov 10 10:44:52 2000
@@ -204,7 +204,20 @@
     assert(label && obj_size);
     pool->label = label;
     pool->obj_size = obj_size;
-    stackInit(&pool->pstack);
+    pool->pstack = 0;
+    pool->ss = pool;
+#ifdef SSPOOLS
+    {
+	unsigned i;
+	for (i = 0; i < Pools.count; i++) {
+	    MemPool *np = Pools.items[i];
+	    if (np->obj_size == pool->obj_size && pool != np) {
+		pool->ss = np;
+		break;
+	    }
+	}
+    }
+#endif
     /* other members are set to 0 */
     stackPush(&Pools, pool);
     return pool;
@@ -218,56 +231,83 @@
 memPoolDestroy(MemPool * pool)
 {
     assert(pool);
-    stackClean(&pool->pstack);
     xfree(pool);
 }
 
 void *
 memPoolAlloc(MemPool * pool)
 {
+    void *obj;
     assert(pool);
     memMeterInc(pool->meter.inuse);
     gb_inc(&pool->meter.total, 1);
     gb_inc(&TheMeter.total, pool->obj_size);
     memMeterAdd(TheMeter.inuse, pool->obj_size);
     gb_inc(&mem_traffic_volume, pool->obj_size);
+#ifdef NEVERFREE
+    if (!(obj = pool->ss->pstack)) {
+	unsigned step = pool->meter.alloc.level/4+1;	/* 25% growth */
+	if (step*pool->obj_size>256*1024)
+	    step = 256*1024/pool->obj_size;   /* but at most 256KB at a time */
+	obj = xmalloc(step*pool->obj_size);
+	memMeterAdd(pool->meter.alloc, step);
+	memMeterAdd(TheMeter.alloc, step*pool->obj_size);
+	while(--step) {
+	    memPoolFree(pool, obj);
+	    obj=(char*)obj+pool->obj_size;
+            memMeterInc(pool->meter.inuse);
+            memMeterAdd(TheMeter.inuse, pool->obj_size);
+	}
+#else
     if (pool->pstack.count) {
-	assert(pool->meter.idle.level);
-	memMeterDec(pool->meter.idle);
+	assert(!pool->meter.idle.level);
+	return xcalloc(1, pool->obj_size);
+#endif
+    } else {
+	memMeterDec(pool->ss->meter.idle);
+        memMeterDec(pool->ss->meter.alloc);
+        memMeterInc(pool->meter.alloc);
 	memMeterDel(TheMeter.idle, pool->obj_size);
 	gb_inc(&pool->meter.saved, 1);
 	gb_inc(&TheMeter.saved, pool->obj_size);
-	return stackPop(&pool->pstack);
-    } else {
-	assert(!pool->meter.idle.level);
-	memMeterInc(pool->meter.alloc);
-	memMeterAdd(TheMeter.alloc, pool->obj_size);
-	return xcalloc(1, pool->obj_size);
+	pool->ss->pstack = *(void**)obj;
     }
+    memset(obj, 0, pool->obj_size);
+    return obj;
 }
 
 void
 memPoolFree(MemPool * pool, void *obj)
 {
     assert(pool && obj);
+    assert(pool->obj_size >= sizeof pool->pstack);
     memMeterDec(pool->meter.inuse);
+    memMeterDec(pool->meter.alloc);
+    memMeterInc(pool->ss->meter.alloc);
     memMeterDel(TheMeter.inuse, pool->obj_size);
+#ifdef NEVERFREE
+    if (1) {
+#else
     if (TheMeter.idle.level + pool->obj_size <= mem_idle_limit) {
-	memMeterInc(pool->meter.idle);
+#endif
+	memMeterInc(pool->ss->meter.idle);
 	memMeterAdd(TheMeter.idle, pool->obj_size);
-	memset(obj, 0, pool->obj_size);
-	stackPush(&pool->pstack, obj);
+	*(void**)obj = pool->ss->pstack;
+	pool->ss->pstack = obj;
     } else {
 	memMeterDec(pool->meter.alloc);
 	memMeterDel(TheMeter.alloc, pool->obj_size);
 	xfree(obj);
     }
+#if 0	/* bogus assertion? srb */
     assert(pool->meter.idle.level <= pool->meter.alloc.level);
+#endif
 }
 
 static void
 memPoolShrink(MemPool * pool, size_t new_limit)
 {
+#ifndef NEVERFREE
     assert(pool);
     assert(new_limit >= 0);
     while (pool->meter.idle.level > new_limit && pool->pstack.count > 0) {
@@ -278,13 +318,15 @@
 	xfree(stackPop(&pool->pstack));
     }
     assert(pool->meter.idle.level <= new_limit);	/* paranoid */
+#endif
 }
 
 int
 memPoolWasUsed(const MemPool * pool)
 {
     assert(pool);
-    return pool->meter.alloc.hwater_level > 0;
+    return pool->meter.inuse.hwater_level > 0 ||
+	pool->meter.idle.hwater_level > 0;
 }
 
 int
@@ -358,8 +400,7 @@
 	    idle_count += pool->meter.idle.level;
 	}
 	overhd_size += sizeof(MemPool) + sizeof(MemPool *) +
-	    strlen(pool->label) + 1 +
-	    pool->pstack.capacity * sizeof(void *);
+	    strlen(pool->label) + 1;
     }
     overhd_size += sizeof(Pools) + Pools.capacity * sizeof(MemPool *);
     /* totals */
Index: squid/src/aiops.c
diff -u squid/src/aiops.c:1.1.1.2 squid/src/aiops.c:1.1.1.2.10.1
--- squid/src/aiops.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/aiops.c	Fri Nov 10 10:44:52 2000
@@ -385,9 +385,14 @@
 	high_start = 0;
     }
     if (request_queue_len > RIDICULOUS_LENGTH) {
+	static unsigned warned;
+	if (!warned)
 	debug(43, 0) ("aio_queue_request: Async request queue growing uncontrollably!\n");
+	warned=1;
+#if 0
 	debug(43, 0) ("aio_queue_request: Possible infinite loop somewhere in squid. Restarting...\n");
 	abort();
+#endif
     }
 }				/* aio_queue_request */
 
@@ -577,7 +582,9 @@
 aio_do_read(aio_request_t * requestp)
 {
     lseek(requestp->fd, requestp->offset, requestp->whence);
-    requestp->ret = read(requestp->fd, requestp->tmpbufp, requestp->buflen);
+    while((requestp->ret =
+	read(requestp->fd, requestp->tmpbufp, requestp->buflen)) < 0 &&
+	errno == EAGAIN);
     requestp->err = errno;
 }
 
@@ -615,7 +622,9 @@
 static void
 aio_do_write(aio_request_t * requestp)
 {
-    requestp->ret = write(requestp->fd, requestp->tmpbufp, requestp->buflen);
+    while((requestp->ret =
+	write(requestp->fd, requestp->tmpbufp, requestp->buflen)) < 0 &&
+	errno == EAGAIN);
     requestp->err = errno;
 }
 
@@ -644,7 +653,10 @@
 static void
 aio_do_close(aio_request_t * requestp)
 {
-    requestp->ret = close(requestp->fd);
+    if((requestp->ret = close(requestp->fd))<0) {
+	debug(43, 0) ("aio_do_close: FD %d, errno %d\n", requestp->fd, errno);
+	close(requestp->fd);
+    }
     requestp->err = errno;
 }
 
Index: squid/src/asn.c
diff -u squid/src/asn.c:1.1.1.2 squid/src/asn.c:1.1.1.2.10.1
--- squid/src/asn.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/asn.c	Fri Nov 10 10:44:52 2000
@@ -221,7 +221,7 @@
     char *s;
     char *t;
     debug(53, 3) ("asHandleReply: Called with size=%d\n", size);
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(e->Sflag, ENTRY_ABORTED)) {
 	memFree(buf, MEM_4K_BUF);
 	asStateFree(asState);
 	return;
Index: squid/src/async_io.c
diff -u squid/src/async_io.c:1.1.1.2 squid/src/async_io.c:1.1.1.2.10.1
--- squid/src/async_io.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/async_io.c	Fri Nov 10 10:44:52 2000
@@ -132,7 +132,8 @@
     ctrlp->done_handler_data = NULL;
     ctrlp->operation = _AIO_CLOSE;
     if (aio_close(fd, &(ctrlp->result)) < 0) {
-	close(fd);		/* Can't create thread - do a normal close */
+	if(close(fd))		/* Can't create thread - do a normal close */
+	    debug(0,0) ("aioClose: FD %d, errno %d\n", fd, errno), close(fd);
 	memPoolFree(aio_ctrl_pool, ctrlp);
 	fd_was_closed(fd);
 	return;
Index: squid/src/cache_cf.c
diff -u squid/src/cache_cf.c:1.1.1.2 squid/src/cache_cf.c:1.1.1.2.10.1
--- squid/src/cache_cf.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/cache_cf.c	Fri Nov 10 10:44:52 2000
@@ -222,7 +222,7 @@
     /* calculate Config.Swap.maxSize */
     storeDirConfigure();
     if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
-	fatal("cache_swap is lower than cache_mem");
+	debug(3, 0) ("configDoConfigure: cache_swap is lower than cache_mem");
     if (Config.Announce.period > 0) {
 	Config.onoff.announce = 1;
     } else if (Config.Announce.period < 1) {
@@ -303,10 +303,14 @@
 	debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
 	Config.retry.maxtries = 1;
     }
+    #ifdef	HPL_REPL
+    /* The non-LRU policies do not use referenceAge */
+    #else	/* HPL_REPL */
     if (Config.referenceAge < 300) {
 	debug(3, 0) ("WARNING: resetting 'reference_age' to 1 week\n");
 	Config.referenceAge = 86400 * 7;
     }
+    #endif	/* HPL_REPL */
     requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
     requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
     requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
@@ -837,6 +841,9 @@
     tmp->l2 = l2;
     tmp->flags.read_only = read_only;
     tmp->swaplog_fd = -1;
+#ifdef MMAPSTORE
+    tmp->mi = 0;
+#endif
     swap->n_configured++;
 }
 
@@ -856,6 +863,7 @@
 	}
 	xfree(s->path);
 	filemapFreeMemory(s->map);
+	delete_heap(s->heap);
     }
     safe_free(swap->swapDirs);
     swap->swapDirs = NULL;
Index: squid/src/cache_manager.c
diff -u squid/src/cache_manager.c:1.1.1.2 squid/src/cache_manager.c:1.1.1.2.28.1
--- squid/src/cache_manager.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/cache_manager.c	Fri Nov 10 10:44:52 2000
@@ -201,12 +201,12 @@
 	err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND);
 	err->url = xstrdup(storeUrl(entry));
 	errorAppendEntry(entry, err);
-	entry->expires = squid_curtime;
+	entry->Sexpires = squid_curtime;
 	return;
     }
     mgr->entry = entry;
     storeLockObject(entry);
-    entry->expires = squid_curtime;
+    entry->Sexpires = squid_curtime;
     debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
 	fd_table[fd].ipaddr, mgr->action);
     /* get additional info from request headers */
@@ -238,7 +238,7 @@
 	httpReplyAbsorb(entry->mem_obj->reply, rep);
 	/* store the reply */
 	httpReplySwapOut(entry->mem_obj->reply, entry);
-	entry->expires = squid_curtime;
+	entry->Sexpires = squid_curtime;
 	storeComplete(entry);
 	cachemgrStateFree(mgr);
 	return;
Index: squid/src/cachemgr.c
diff -u squid/src/cachemgr.c:1.1.1.2 squid/src/cachemgr.c:1.1.1.2.12.1
--- squid/src/cachemgr.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/cachemgr.c	Fri Nov 10 10:44:52 2000
@@ -344,7 +344,7 @@
 {
     static const char *ttags[] =
     {"td", "th"};
-    static char html[4096];
+    static char html[4096*4];
     static int table_line_num = 0;
     static int next_is_header = 0;
     int is_header = 0;
@@ -358,7 +358,7 @@
 	snprintf(html, sizeof(html), "%s%s",
 	    table_line_num ? "</table>\n<pre>" : "", buf);
 	table_line_num = 0;
-	return html;
+	goto ret;
     }
     /* start html table */
     if (!table_line_num) {
@@ -391,6 +391,37 @@
     l += snprintf(html + l, sizeof(html) - l, "</tr>\n");
     next_is_header = is_header && strstr(buf, "\t\t");
     table_line_num++;
+ret:
+    {
+#define STRLEN(x)	(sizeof(x)-1)
+	char*pok, *found;
+	for(pok = html; pok = strstr(pok+4, "://"); )
+#define CHECKFOR(str)	(!memcmp(found=pok-STRLEN(str),str,STRLEN(str)))
+	    if(CHECKFOR("http")||CHECKFOR("ftp")||
+		CHECKFOR("gopher")||CHECKFOR("wais")) {
+		static const char prefix[]="<a href=\"", interfix[]="\">",
+		    postfix[]="</a>";
+		size_t len,restlen;
+		for(;;) {
+		    switch(*++pok) {
+			default:
+			    continue;
+			case ' ':case '\t':case '\n':case '\0':
+			    break;
+		    }
+		    break;
+		}
+		len=pok-found; restlen=strlen(pok)+1;
+		memmove(found+STRLEN(prefix)+len+STRLEN(interfix)+len+
+		    STRLEN(postfix),found+len,restlen);
+		memmove(found+STRLEN(prefix),found,len);
+		memcpy(found,prefix,STRLEN(prefix));
+		memcpy(pok = found+STRLEN(prefix)+len,
+		    interfix,STRLEN(interfix));
+		memcpy(pok += STRLEN(interfix),found+STRLEN(prefix),len);
+		memcpy(pok += len, postfix,STRLEN(postfix));
+	    }
+    }
     return html;
 }
 
@@ -440,6 +471,7 @@
 	case isHeaders:
 	    /* forward header field */
 	    if (!strcmp(buf, "\r\n")) {		/* end of headers */
+		fputs("Cache-Control: max-age=4\r\n", stdout);	/* add our type */
 		fputs("Content-Type: text/html\r\n", stdout);	/* add our type */
 		istate = isBodyStart;
 	    }
Index: squid/src/cf.data.pre
diff -u squid/src/cf.data.pre:1.1.1.2 squid/src/cf.data.pre:1.1.1.2.10.1
--- squid/src/cf.data.pre:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/cf.data.pre	Fri Nov 10 10:44:52 2000
@@ -69,6 +69,17 @@
 http_port 3128
 DOC_END
 
+NAME: bhttp_port ascii_port
+TYPE: ushort
+DEFAULT: none
+LOC: Config.Port.bhttp
+DOC_START
+	The port number where Squid uses the cuciwhirl junkfilter.
+	Note that you need another http_port directive to actually
+	bind the port.
+
+bhttp_port 3129
+DOC_END
 
 NAME: icp_port udp_port
 TYPE: ushort
@@ -494,12 +505,17 @@
 DEFAULT: 95
 LOC: Config.Swap.highWaterMark
 DOC_START
-	The low- and high-water marks for cache LRU replacement.  LRU
-	replacement begins when the high-water mark is reached and ends
-	when enough objects have been removed and the low-water mark is
-	reached. Defaults are 90% and 95%. If you have a large cache, 5%
-	could be hundreds of MB. If this is the case you may wish to
-	set these numbers closer together.
+
+	The low- and high-water marks for cache object replacement.
+	Replacement begins when the swap (disk) usage is above the
+	low-water mark and attempts to maintain utilization near the
+	low-water mark.  As swap utilization gets close to high-water
+	mark object eviction becomes more aggressive.  If utilization is
+	close to the low-water mark less replacement is done each time.
+	
+	Defaults are 90% and 95%. If you have a large cache, 5% could be
+	hundreds of MB. If this is the case you may wish to set these
+	numbers closer together.
 
 cache_swap_low  90
 cache_swap_high 95
@@ -518,6 +534,10 @@
 	hits).  If you wish to increase speed more than your want to
 	save bandwidth you should leave this low.
 
+	NOTE: if using the LFUDA replacement policy you should increase
+	this value to maximize the byte hit rate improvement of LFUDA!
+	See replacement_policy below for a discussion of this policy.
+
 maximum_object_size 4096 KB
 DOC_END
 
@@ -1092,6 +1112,49 @@
 DOC_END
 
 
+NAME: replacement_policy
+TYPE: string
+LOC: Config.replPolicy
+DEFAULT: LFUDA
+IFDEF: HPL_REPL
+DOC_START
+	The cache replacement policy parameter determines which objects
+	are evicted (replaced) when disk space is needed.  Squid used to
+	have only a single replacement policy, LRU.  But when built with
+	-DHPL_REPL you can choose between two new, enhanced policies:
+
+		   GDSF: Greedy-Dual Size Frequency
+		   LFUDA: Least Frequently Used with Dynamic Aging
+
+	Both of these policies are frequency based rather than recency
+	based, and perform better than LRU.
+
+	The GDSF policy optimizes object hit rate by keeping smaller
+	popular objects in cache so it has a better chance of getting a
+	hit.  It achieves a lower byte hit rate than LFUDA though since
+	it evicts larger (possibly popular) objects.
+
+	The LFUDA policy keeps popular objects in cache regardless of
+	their size and thus optimizes byte hit rate at the expense of
+	hit rate since one large, popular object will prevent many
+	smaller, slightly less popular objects from being cached.
+
+	Both policies utilize a dynamic aging mechanism that prevents
+	cache pollution that can otherwise occur with frequency-based
+	replacement policies.
+
+	NOTE: if using the LFUDA replacement policy you should increase
+	the value of maximum_object_size above its default of 4096 KB to
+	to maximize the potential byte hit rate improvement of LFUDA.  
+
+	For more information about these cache replacement policies see
+	http://www.hpl.hp.com/personal/John_Dilley/caching/wcw.html and
+	http://fog.hpl.external.hp.com/techreports/98/HPL-98-173.html.
+
+replacement_policy LFUDA
+DOC_END
+
+
 NAME: reference_age
 TYPE: time_t
 LOC: Config.referenceAge
@@ -1114,6 +1177,9 @@
 		4 months
 		2.2 hours
 
+	NOTE: this parameter is not used when using the enhanced
+	replacement policies, GDSH or LFUDA.
+
 reference_age 1 month
 DOC_END
 
Index: squid/src/client_side.c
diff -u squid/src/client_side.c:1.1.1.2 squid/src/client_side.c:1.1.1.2.10.1
--- squid/src/client_side.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/client_side.c	Fri Nov 10 10:44:52 2000
@@ -58,6 +58,9 @@
 #endif
 #endif
 
+#ifdef	HPL_REPL
+#include "heap.h"
+#endif	/* HPL_REPL */
 
 
 #if LINGERING_CLOSE
@@ -284,6 +287,9 @@
 	    new_request->body_sz = old_request->body_sz;
 	}
 	requestUnlink(old_request);
+	if (!*new_request->host)
+	    xstrncpy(new_request->host, internalHostname(),
+		SQUIDHOSTNAMELEN);
 	http->request = requestLink(new_request);
     }
     clientInterpretRequestHeaders(http);
@@ -298,7 +304,7 @@
     char *url = http->uri;
     StoreEntry *entry = NULL;
     debug(33, 3) ("clientProcessExpired: '%s'\n", http->uri);
-    assert(http->entry->lastmod >= 0);
+    assert(http->entry->Slastmod >= 0);
     /*
      * check if we are allowed to contact other servers
      * @?@: Instead of a 504 (Gateway Timeout) reply, we may want to return 
@@ -326,15 +332,26 @@
     /* delay_id is already set on original store client */
     delaySetStoreClient(entry, http, delayClient(http->request));
 #endif
-    entry->lastmod = http->old_entry->lastmod;
-    debug(33, 5) ("clientProcessExpired: lastmod %d\n", (int) entry->lastmod);
-    entry->refcount++;		/* EXPIRED CASE */
+    entry->Slastmod = http->old_entry->Slastmod;
+    debug(33, 5) ("clientProcessExpired: lastmod %d\n", (int) entry->Slastmod);
+    entry->Srefcount++;		/* EXPIRED CASE */
+#ifdef	HPL_REPL
+    /* 
+     * Update the position of this object in the store heap and memory
+     * heap.  The cache replacement policy uses refcount to determie the
+     * priority value of the object.
+     */
+    if (entry->n.ode.id >= 0)
+      heap_update(Store_Heap(entry), &entry->n.ode);
+    if (entry->mem_obj->n.ode.id >= 0)
+      heap_update(inmem_heap, &entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
     http->entry = entry;
     http->out.offset = 0;
     fwdStart(http->conn->fd, http->entry, http->request,
 	http->conn->peer.sin_addr, http->conn->me.sin_addr);
     /* Register with storage manager to receive updates when data comes in. */
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED))
 	debug(33, 0) ("clientProcessExpired: found ENTRY_ABORTED object\n");
     storeClientCopy(entry,
 	http->out.offset,
@@ -399,13 +416,13 @@
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
     }
-    if (size < 0 && !EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (size < 0 && !EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
     }
     mem = entry->mem_obj;
     status = mem->reply->sline.status;
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	debug(33, 3) ("clientHandleIMSReply: ABORTED '%s'\n", url);
 	/* We have an existing entry, but failed to validate it */
 	/* Its okay to send the old one anyway */
@@ -413,7 +430,14 @@
 	storeUnregister(entry, http);
 	storeUnlockObject(entry);
 	entry = http->entry = http->old_entry;
-	entry->refcount++;
+	entry->Srefcount++;
+#ifdef	HPL_REPL
+	/* Update the position of this object in the store and memory heaps. */
+	if (entry->n.ode.id >= 0)
+	  heap_update(Store_Heap(entry), &entry->n.ode);
+	if (entry->mem_obj->n.ode.id >= 0)
+	  heap_update(inmem_heap, &entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
     } else if (STORE_PENDING == entry->store_status && 0 == status) {
 	debug(33, 3) ("clientHandleIMSReply: Incomplete headers for '%s'\n", url);
 	if (size >= CLIENT_SOCK_SZ) {
@@ -424,7 +448,14 @@
 	    storeUnregister(entry, http);
 	    storeUnlockObject(entry);
 	    entry = http->entry = http->old_entry;
-	    entry->refcount++;
+	    entry->Srefcount++;
+#ifdef	HPL_REPL
+	    /* Update the position of this object in the store and memory heaps. */
+	    if (entry->n.ode.id >= 0)
+	      heap_update(Store_Heap(entry), &entry->n.ode);
+	    if (entry->mem_obj->n.ode.id >= 0)
+	      heap_update(inmem_heap, &entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
 	    /* continue */
 	} else {
 	    storeClientCopy(entry,
@@ -455,7 +486,7 @@
 	storeUnregister(entry, http);
 	storeUnlockObject(entry);
 	entry = http->entry = oldentry;
-	entry->timestamp = squid_curtime;
+	entry->Stimestamp = squid_curtime;
 	if (unlink_request) {
 	    requestUnlink(entry->mem_obj->request);
 	    entry->mem_obj->request = NULL;
@@ -464,8 +495,15 @@
 	/* the client can handle this reply, whatever it is */
 	http->log_type = LOG_TCP_REFRESH_MISS;
 	if (HTTP_NOT_MODIFIED == mem->reply->sline.status) {
-	    http->old_entry->timestamp = squid_curtime;
-	    http->old_entry->refcount++;
+	    http->old_entry->Stimestamp = squid_curtime;
+	    http->old_entry->Srefcount++;
+#ifdef	HPL_REPL
+	    /* Update the position of this object in the store and memory heaps. */
+	    if (http->old_entry->n.ode.id >= 0)
+	      heap_update(Store_Heap(http->old_entry), &http->old_entry->n.ode);
+	    if (http->old_entry->mem_obj->n.ode.id >= 0)
+	      heap_update(inmem_heap, &http->old_entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
 	    http->log_type = LOG_TCP_REFRESH_HIT;
 	}
 	storeUnregister(http->old_entry, http);
@@ -473,7 +511,7 @@
 	recopy = 0;
     }
     http->old_entry = NULL;	/* done with old_entry */
-    assert(!EBIT_TEST(entry->flags, ENTRY_ABORTED));
+    assert(!EBIT_TEST(entry->Sflag, ENTRY_ABORTED));
     if (recopy) {
 	storeClientCopy(entry,
 	    http->out.offset,
@@ -492,10 +530,10 @@
 {
     int object_length;
     MemObject *mem = entry->mem_obj;
-    time_t mod_time = entry->lastmod;
+    time_t mod_time = entry->Slastmod;
     debug(33, 3) ("modifiedSince: '%s'\n", storeUrl(entry));
     if (mod_time < 0)
-	mod_time = entry->timestamp;
+      mod_time = entry->Stimestamp;
     debug(33, 3) ("modifiedSince: mod_time = %d\n", (int) mod_time);
     if (mod_time < 0)
 	return 1;
@@ -560,9 +598,9 @@
 int
 checkNegativeHit(StoreEntry * e)
 {
-    if (!EBIT_TEST(e->flags, ENTRY_NEGCACHED))
+    if (!EBIT_TEST(e->Sflag, ENTRY_NEGCACHED))
 	return 0;
-    if (e->expires <= squid_curtime)
+    if (e->Sexpires <= squid_curtime)
 	return 0;
     if (e->store_status != STORE_OK)
 	return 0;
@@ -989,7 +1027,7 @@
     }
     /* got modification time? */
     if (spec.time >= 0) {
-	return http->entry->lastmod <= spec.time;
+	return http->entry->Slastmod <= spec.time;
     }
     assert(0);			/* should not happen */
     return 0;
@@ -1108,7 +1146,7 @@
      * Add Age header, not that our header must replace Age headers
      * from other caches if any
      */
-    if (http->entry->timestamp > 0) {
+    if (http->entry->Stimestamp > 0) {
 	httpHeaderDelById(hdr, HDR_AGE);
 	/*
 	 * we do not follow HTTP/1.1 precisely here becuase we rely
@@ -1117,8 +1155,8 @@
 	 * or if it is out of sync
 	 */
 	httpHeaderPutInt(hdr, HDR_AGE,
-	    http->entry->timestamp <= squid_curtime ?
-	    squid_curtime - http->entry->timestamp : 0);
+	    http->entry->Stimestamp <= squid_curtime ?
+	    squid_curtime - http->entry->Stimestamp : 0);
     }
     /* Append X-Cache */
     httpHeaderPutStrf(hdr, HDR_X_CACHE, "%s from %s",
@@ -1193,7 +1231,7 @@
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	debug(33, 3) ("clientCacheHit: request aborted\n");
 	return;
-    } else if (size < 0) {
+    } else if (size <= 0) {
 	/* swap in failure */
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	debug(33, 3) ("clientCacheHit: swapin failure for %s\n", http->uri);
@@ -1206,9 +1244,8 @@
 	clientProcessMiss(http);
 	return;
     }
-    assert(size > 0);
     mem = e->mem_obj;
-    assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
+    assert(!EBIT_TEST(e->Sflag, ENTRY_ABORTED));
     if (mem->reply->sline.status == 0) {
 	/*
 	 * we don't have full reply headers yet; either wait for more or
@@ -1261,7 +1298,7 @@
 	 * both have a stale version of the object.
 	 */
 	r->flags.need_validation = 1;
-	if (e->lastmod < 0) {
+	if (e->Slastmod < 0) {
 	    /*
 	     * Previous reply didn't have a Last-Modified header,
 	     * we cannot revalidate it.
@@ -1479,7 +1516,7 @@
 	debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry));
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
 	return;
-    } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    } else if (entry && EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	/* call clientWriteComplete so the client socket gets closed */
 	clientWriteComplete(fd, NULL, 0, COMM_OK, http);
 	memFree(buf, MEM_CLIENT_SOCK_BUF);
@@ -1591,12 +1628,12 @@
 	/*
 	 * Set the timeout BEFORE calling clientReadRequest().
 	 */
-	commSetTimeout(conn->fd, 15, requestTimeout, conn);
+	commSetTimeout(conn->fd, Config.Timeout.request, requestTimeout, conn);
 	clientReadRequest(conn->fd, conn);	/* Read next request */
 	/*
 	 * Note, the FD may be closed at this point.
 	 */
-    } else if ((entry = http->entry) == NULL) {
+    } else if (!(entry = http->entry)) {
 	/*
 	 * this request is in progress, maybe doing an ACL or a redirect,
 	 * execution will resume after the operation completes.
@@ -1604,9 +1641,8 @@
     } else {
 	debug(33, 1) ("clientKeepaliveNextRequest: FD %d Sending next\n",
 	    conn->fd);
-	assert(entry);
 	if (0 == storeClientCopyPending(entry, http)) {
-	    if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
+	    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED))
 		debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTED\n");
 	    storeClientCopy(entry,
 		http->out.offset,
@@ -1640,7 +1676,7 @@
 	comm_close(fd);
     } else if (NULL == entry) {
 	comm_close(fd);		/* yuk */
-    } else if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    } else if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(fd);
     } else if ((done = clientCheckTransferDone(http)) != 0 || size == 0) {
 	debug(33, 5) ("clientWriteComplete: FD %d transfer is DONE\n", fd);
@@ -1663,7 +1699,7 @@
     } else {
 	/* More data will be coming from primary server; register with 
 	 * storage manager. */
-	if (EBIT_TEST(entry->flags, ENTRY_ABORTED))
+	if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED))
 	    debug(33, 0) ("clientWriteComplete 2: ENTRY_ABORTED\n");
 	storeClientCopy(entry,
 	    http->out.offset,
@@ -1729,7 +1765,7 @@
 	http->entry = NULL;
 	return LOG_TCP_MISS;
     }
-    if (EBIT_TEST(e->flags, ENTRY_SPECIAL)) {
+    if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL)) {
 	/* Special entries are always hits, no matter what the client says */
 	debug(33, 3) ("clientProcessRequest2: ENTRY_SPECIAL HIT\n");
 	http->entry = e;
@@ -1824,7 +1860,14 @@
 #if DELAY_POOLS
 	delaySetStoreClient(http->entry, http, delayClient(r));
 #endif
-	http->entry->refcount++;
+	http->entry->Srefcount++;
+#ifdef	HPL_REPL
+	/* Update the position of this object in the store and memory heaps. */
+	if (http->entry->n.ode.id >= 0)
+	  heap_update(Store_Heap(http->entry), &http->entry->n.ode);
+	if (http->entry->mem_obj->n.ode.id >= 0)
+	  heap_update(inmem_heap, &http->entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
 	storeClientCopy(http->entry,
 	    http->out.offset,
 	    http->out.offset,
@@ -1855,7 +1898,7 @@
      * or IMS request.
      */
     if (http->entry) {
-	if (EBIT_TEST(http->entry->flags, ENTRY_SPECIAL))
+	if (EBIT_TEST(http->entry->Sflag, ENTRY_SPECIAL))
 	    debug(33, 0) ("clientProcessMiss: miss on a special object (%s).\n", url);
 	storeUnregister(http->entry, http);
 	storeUnlockObject(http->entry);
@@ -1879,7 +1922,14 @@
     }
     assert(http->out.offset == 0);
     http->entry = clientCreateStoreEntry(http, r->method, r->flags);
-    http->entry->refcount++;
+    http->entry->Srefcount++;
+#ifdef	HPL_REPL
+    /* Update the position of this object in the store and memory heaps. */
+    if (http->entry->n.ode.id >= 0)
+      heap_update(Store_Heap(http->entry), &http->entry->n.ode);
+    if (http->entry->mem_obj->n.ode.id >= 0)
+      heap_update(inmem_heap, &http->entry->mem_obj->n.ode);
+#endif	/* HPL_REPL */
     if (http->redirect.status) {
 	HttpReply *rep = httpReplyCreate();
 	storeReleaseRequest(http->entry);
@@ -2087,14 +2137,16 @@
 	    if (natfd < 0) {
 		debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n",
 		    xstrerror());
-		return parseHttpRequestAbort(conn, "error:nat-open-failed");
+		http = parseHttpRequestAbort(conn, "error:nat-open-failed");
+		goto ret;
 	    }
 	    if (ioctl(natfd, SIOCGNATL, &natLookup) < 0) {
 		if (errno != ESRCH) {
 		    debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n");
 		    close(natfd);
 		    natfd = -1;
-		    return parseHttpRequestAbort(conn, "error:nat-lookup-failed");
+		    http = parseHttpRequestAbort(conn, "error:nat-lookup-failed");
+		    goto ret;
 		} else
 		    snprintf(http->uri, url_sz, "http://%s:%d%s",
 			inet_ntoa(http->conn->me.sin_addr),
@@ -2133,8 +2185,9 @@
     debug(33, 5) ("parseHttpRequest: Complete request received\n");
     if (free_request)
 	safe_free(url);
-    xfree(inbuf);
     *status = 1;
+ret:
+    xfree(inbuf);
     return http;
 }
 
@@ -2249,7 +2302,7 @@
 	    conn->nrequests++;
 	    commSetTimeout(fd, Config.Timeout.lifetime, NULL, NULL);
 	    if (parser_return_code < 0) {
-		debug(33, 1) ("clientReadRequest: FD %d Invalid Request\n", fd);
+		debug(33, 1) ("clientReadRequest: FD %d Indecent proposal\n", fd);
 		err = errorCon(ERR_INVALID_REQ, HTTP_BAD_REQUEST);
 		err->request_hdrs = xstrdup(conn->in.buf);
 		http->entry = clientCreateStoreEntry(http, method, null_request_flags);
Index: squid/src/comm.c
diff -u squid/src/comm.c:1.1.1.2 squid/src/comm.c:1.1.1.2.10.1
--- squid/src/comm.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/comm.c	Fri Nov 10 10:44:52 2000
@@ -597,7 +597,8 @@
      * michael@metal.iinet.net.au sez close() on
      * network sockets never blocks.
      */
-    close(fd);
+    if(close(fd))
+	debug(50, 0) ("comm_close: FD %d, %s\n", fd, xstrerror()), close(fd);
 #elif USE_ASYNC_IO
     if (doaioclose)
 	aioClose(fd);
Index: squid/src/defines.h
diff -u squid/src/defines.h:1.1.1.2 squid/src/defines.h:1.1.1.2.10.1
--- squid/src/defines.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/defines.h	Fri Nov 10 10:44:52 2000
@@ -87,7 +87,7 @@
 
 #define DNS_INBUF_SZ 4096
 
-#define FD_DESC_SZ		64
+#define FD_DESC_SZ		128
 
 #define FQDN_LOOKUP_IF_MISS	0x01
 #define FQDN_MAX_NAMES 5
@@ -208,6 +208,15 @@
 #define STORE_SWAP_BUF		DISK_PAGE_SIZE
 #define VM_WINDOW_SZ		DISK_PAGE_SIZE
 
+#define SWAP_DIR_SHIFT 24
+#define SWAP_FILE_MASK ((1<<SWAP_DIR_SHIFT)-1)
+	
+#define STORE_GRAN_ORDER	10
+#define STORE_GRAN_MAX		(1<<STORE_GRAN_ORDER)
+	
+#define Store_Heap(e)	\
+  (assert((e)->Sswap_file_number>=0),getswapdir((e)->Sswap_file_number)->heap)
+
 #define SKIP_BASIC_SZ ((size_t) 6)
 
 #define PINGER_PAYLOAD_SZ 8192
Index: squid/src/disk.c
diff -u squid/src/disk.c:1.1.1.2 squid/src/disk.c:1.1.1.2.10.1
--- squid/src/disk.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/disk.c	Fri Nov 10 10:44:52 2000
@@ -242,6 +242,12 @@
 #endif
     debug(6, 3) ("diskHandleWrite: FD %d\n", fd);
     assert(fdd->write_q != NULL);
+    if (fdd->write_q->len == fdd->write_q->buf_offset) {
+        debug(6, 0) ("diskHandleWrite: nothing to write FD %d offset %d\n",
+		fd, fdd->write_q->buf_offset);
+	diskHandleWriteComplete(fd, fdd->write_q, 0, 0);
+	return;
+    }
     assert(fdd->write_q->len > fdd->write_q->buf_offset);
 #if USE_ASYNC_IO
     aioWrite(fd,
@@ -296,7 +302,7 @@
     }
 #endif
     if (q == NULL)		/* Someone aborted then write completed */
-	return;
+	goto ret;
 
     if (len == -2 && errcode == -2) {	/* Write cancelled - cleanup */
 	do {
@@ -333,6 +339,8 @@
 	     * repeated write failures for the same FD because of
 	     * the queued data.
 	     */
+	    if (data == q)
+		data = 0;
 	    do {
 		fdd->write_q = q->next;
 		if (q->free_func)
@@ -354,6 +362,8 @@
 	    fdd->write_q = q->next;
 	    if (q->free_func)
 		(q->free_func) (q->buf);
+	    if (data == q)
+		data = 0;
 	    safe_free(q);
 	}
     }
@@ -390,11 +400,13 @@
 #ifdef OPTIMISTIC_IO
 	    F->flags.calling_io_handler = 0;
 #endif
-	    return;
+	    goto ret;
 	}
     }
     if (do_close)
 	file_close(fd);
+ret:
+    safe_free(data);
 }
 
 
Index: squid/src/enums.h
diff -u squid/src/enums.h:1.1.1.2 squid/src/enums.h:1.1.1.2.10.1
--- squid/src/enums.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/enums.h	Fri Nov 10 10:44:52 2000
@@ -535,6 +535,7 @@
     MEM_MEM_NODE,
     MEM_NETDBENTRY,
     MEM_NET_DB_NAME,
+    MEM_STORESWAPLOGDATA,
     MEM_NET_DB_PEER,
     MEM_PEER,
 #if USE_CACHE_DIGESTS
Index: squid/src/errorpage.c
diff -u squid/src/errorpage.c:1.1.1.2 squid/src/errorpage.c:1.1.1.2.10.1
--- squid/src/errorpage.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/errorpage.c	Fri Nov 10 10:44:52 2000
@@ -270,7 +270,7 @@
 	 * care about it, and we don't need to generate an
 	 * error message
 	 */
-	assert(EBIT_TEST(entry->flags, ENTRY_ABORTED));
+	assert(EBIT_TEST(entry->Sflag, ENTRY_ABORTED));
 	assert(mem->nclients == 0);
 	errorStateFree(err);
 	return;
@@ -298,7 +298,7 @@
     httpReplyDestroy(rep);
     mem->reply->sline.status = err->http_status;
     mem->reply->content_length = -1;
-    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+    EBIT_CLR(entry->Sflag, ENTRY_FWD_HDR_WAIT);
     storeBufferFlush(entry);
     storeComplete(entry);
     storeNegativeCache(entry);
@@ -599,6 +599,9 @@
     }
     if (*m)
 	memBufPrintf(&content, "%s", m);	/* copy tail */
-    assert(content.size == strlen(content.buf));
+    if (content.size != strlen(content.buf)) {
+	debug(4,0) ("errorBuildContent: %d, %d != %d\n", err->page_id,
+		content.size, strlen(content.buf));
+    }
     return content;
 }
Index: squid/src/filemap.c
diff -u squid/src/filemap.c:1.1.1.1 squid/src/filemap.c:1.1.1.1.12.1
--- squid/src/filemap.c:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/src/filemap.c	Fri Nov 10 10:44:52 2000
@@ -115,7 +115,8 @@
     for (count = 0; count < fm->nwords; count++) {
 	if (fm->file_map[word] != ALL_ONES)
 	    break;
-	word = (word + 1) % fm->nwords;
+	if (++word == fm->nwords)
+	    word = 0;
     }
     for (bit = 0; bit < BITS_IN_A_LONG; bit++) {
 	suggestion = ((unsigned long) word << LONG_BIT_SHIFT) | bit;
Index: squid/src/ftp.c
diff -u squid/src/ftp.c:1.1.1.2 squid/src/ftp.c:1.1.1.2.10.1
--- squid/src/ftp.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/ftp.c	Fri Nov 10 10:44:52 2000
@@ -306,6 +306,7 @@
 static void
 ftpLoginParser(const char *login, FtpStateData * ftpState, int escaped)
 {
+    static unsigned long counter;
     char *s = NULL;
     xstrncpy(ftpState->user, login, MAX_URL);
     if ((s = strchr(ftpState->user, ':'))) {
@@ -320,8 +321,10 @@
 	rfc1738_unescape(ftpState->user);
     if (ftpState->user[0] || ftpState->password[0])
 	return;
+
     xstrncpy(ftpState->user, "anonymous", MAX_URL);
-    xstrncpy(ftpState->password, Config.Ftp.anon_user, MAX_URL);
+    snprintf(ftpState->password, MAX_URL, "%lx.%s", counter++,
+	Config.Ftp.anon_user);
 }
 
 static void
@@ -863,7 +866,7 @@
     delay_id delay_id = delayMostBytesAllowed(mem);
 #endif
     assert(fd == ftpState->data.fd);
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(ftpState->ctrl.fd);
 	return;
     }
@@ -1216,6 +1219,10 @@
     int len;
     ErrorState *err;
     debug(9, 5) ("ftpReadControlReply\n");
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
+	comm_close(ftpState->ctrl.fd);
+	return;
+    }
     assert(ftpState->ctrl.offset < ftpState->ctrl.size);
     Counter.syscalls.sock.reads++;
     len = read(fd,
@@ -1297,7 +1304,8 @@
     for (W = &ftpState->ctrl.message; (*W)->next; W = &(*W)->next);
     safe_free(ftpState->ctrl.last_reply);
     ftpState->ctrl.last_reply = (*W)->key;
-    safe_free(*W);
+    memFree(*W, MEM_WORDLIST);
+    *W = 0;
     debug(9, 8) ("ftpReadControlReply: state=%d, code=%d\n", ftpState->state,
 	ftpState->ctrl.replycode);
     FTP_SM_FUNCS[ftpState->state] (ftpState);
@@ -1467,7 +1475,7 @@
     w = ftpState->pathcomps;
     ftpState->filepath = w->key;
     ftpState->pathcomps = w->next;
-    xfree(w);
+    memFree(w, MEM_WORDLIST);
     /* Check if we are to CWD or RETR */
     if (ftpState->pathcomps != NULL || ftpState->flags.isdir) {
 	ftpSendCwd(ftpState);
@@ -2371,7 +2379,7 @@
 	return;
     ftpState->flags.http_header_sent = 1;
     assert(e->mem_obj->inmem_hi == 0);
-    EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT);
+    EBIT_CLR(e->Sflag, ENTRY_FWD_HDR_WAIT);
     filename = (t = strRChr(urlpath, '/')) ? t + 1 : strBuf(urlpath);
     if (ftpState->flags.isdir) {
 	mime_type = "text/html";
@@ -2422,7 +2430,7 @@
 	if (pe)
 	    storeRelease(pe);
 	storeRelease(e);
-    } else if (EBIT_TEST(e->flags, ENTRY_CACHABLE) && !ftpState->restarted_offset) {
+    } else if (EBIT_TEST(e->Sflag, ENTRY_CACHABLE) && !ftpState->restarted_offset) {
 	storeSetPublicKey(e);
     } else {
 	storeRelease(e);
Index: squid/src/globals.h
diff -u squid/src/globals.h:1.1.1.2 squid/src/globals.h:1.1.1.2.12.1
--- squid/src/globals.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/globals.h	Fri Nov 10 10:44:52 2000
@@ -30,6 +30,9 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
+#ifdef	HPL_REPL
+#include "heap.h"
+#endif	/* HPL_REPL */
 
 extern FILE *debug_log;		/* NULL */
 extern FILE *cache_useragent_log;	/* NULL */
@@ -53,8 +56,8 @@
 extern const char *const dash_str;	/* "-" */
 extern const char *const localhost;	/* "127.0.0.1" */
 extern const char *const null_string;	/* "" */
-extern const char *const version_string;	/* SQUID_VERSION */
-extern const char *const full_appname_string;	/* "Squid/" SQUID_VERSION */
+extern const char *const version_string;	/* SQUID_VERSION "BuGless" */
+extern const char *const full_appname_string;	/* "Squid/" SQUID_VERSION "BuGless"*/
 extern const char *const w_space;	/* " \t\n\r" */
 extern const char *fdTypeStr[];
 extern const char *hier_strings[];
@@ -124,7 +127,13 @@
 extern double current_dtime;
 extern int store_hash_buckets;	/* 0 */
 extern hash_table *store_table;	/* NULL */
+#ifdef	HPL_REPL
+extern heap_p store_heap;
+extern heap_p inmem_heap;
+extern key_func store_policy;
+#else	/* HPL_REPL */
 extern dlink_list store_list;
+#endif	/* HPL_REPL */
 extern dlink_list ClientActiveRequests;
 extern const String StringNull;	/* { 0, 0, NULL } */
 extern const MemBuf MemBufNull;	/* MemBufNULL */
Index: squid/src/gopher.c
diff -u squid/src/gopher.c:1.1.1.2 squid/src/gopher.c:1.1.1.2.10.1
--- squid/src/gopher.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/gopher.c	Fri Nov 10 10:44:52 2000
@@ -187,7 +187,7 @@
 	break;
     }
     memBufPrintf(&mb, "\r\n");
-    EBIT_CLR(gopherState->entry->flags, ENTRY_FWD_HDR_WAIT);
+    EBIT_CLR(gopherState->entry->Sflag, ENTRY_FWD_HDR_WAIT);
     storeAppend(gopherState->entry, mb.buf, mb.size);
     memBufClean(&mb);
 }
@@ -600,7 +600,7 @@
 #if DELAY_POOLS
     delay_id delay_id = delayMostBytesAllowed(entry->mem_obj);
 #endif
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(fd);
 	return;
     }
@@ -761,7 +761,7 @@
 	gopherSendComplete,
 	data,
 	memFree4K);
-    if (EBIT_TEST(gopherState->entry->flags, ENTRY_CACHABLE))
+    if (EBIT_TEST(gopherState->entry->Sflag, ENTRY_CACHABLE))
 	storeSetPublicKey(gopherState->entry);	/* Make it public */
 }
 
Index: squid/src/helper.c
diff -u squid/src/helper.c:1.1.1.2 squid/src/helper.c:1.1.1.2.10.1
--- squid/src/helper.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/helper.c	Fri Nov 10 10:44:52 2000
@@ -255,8 +255,11 @@
     debug(29, 5) ("helperHandleRead: %d bytes from %s #%d.\n",
 	len, hlp->id_name, srv->index + 1);
     if (len <= 0) {
-	if (len < 0)
+	if (len < 0) {
+	    if (errno == EAGAIN)
+		goto again;
 	    debug(50, 1) ("helperHandleRead: FD %d read: %s\n", fd, xstrerror());
+	}
 	comm_close(fd);
 	return;
     }
@@ -288,7 +291,7 @@
 	else
 	    helperKickQueue(hlp);
     } else {
-	commSetSelect(srv->rfd, COMM_SELECT_READ, helperHandleRead, srv, 0);
+again:	commSetSelect(srv->rfd, COMM_SELECT_READ, helperHandleRead, srv, 0);
     }
 }
 
@@ -308,7 +311,7 @@
     debug(14, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
     debug(14, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
     if (hlp->stats.queue_size > hlp->n_running * 2)
-	fatalf("Too many queued %s requests", hlp->id_name);
+	debug(14, 0) ("Too many queued %s requests", hlp->id_name);
     debug(14, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
 }
 
Index: squid/src/http.c
diff -u squid/src/http.c:1.1.1.2 squid/src/http.c:1.1.1.2.10.1
--- squid/src/http.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/http.c	Fri Nov 10 10:44:52 2000
@@ -106,7 +106,7 @@
 static void
 httpMakePublic(StoreEntry * entry)
 {
-    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+    if (EBIT_TEST(entry->Sflag, ENTRY_CACHABLE))
 	storeSetPublicKey(entry);
 }
 
@@ -124,7 +124,7 @@
 httpCacheNegatively(StoreEntry * entry)
 {
     storeNegativeCache(entry);
-    if (EBIT_TEST(entry->flags, ENTRY_CACHABLE))
+    if (EBIT_TEST(entry->Sflag, ENTRY_CACHABLE))
 	storeSetPublicKey(entry);
 }
 
@@ -133,7 +133,7 @@
 {
     int remove = 0;
     StoreEntry *pe;
-    if (!EBIT_TEST(e->flags, KEY_PRIVATE))
+    if (!EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	return;
     switch (status) {
     case HTTP_OK:
@@ -294,7 +294,7 @@
     int hdr_len;
     HttpReply *reply = entry->mem_obj->reply;
     debug(11, 3) ("httpProcessReplyHeader: key '%s'\n",
-	storeKeyText(entry->key));
+	storeKeyText(entry->Skey));
     if (httpState->reply_hdr == NULL)
 	httpState->reply_hdr = memAllocate(MEM_8K_BUF);
     if (httpState->reply_hdr_state == 0) {
@@ -348,9 +348,9 @@
 	}
 	if (reply->cache_control) {
 	    if (EBIT_TEST(reply->cache_control->mask, CC_PROXY_REVALIDATE))
-		EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+		EBIT_SET(entry->Sflag, ENTRY_REVALIDATE);
 	    else if (EBIT_TEST(reply->cache_control->mask, CC_MUST_REVALIDATE))
-		EBIT_SET(entry->flags, ENTRY_REVALIDATE);
+		EBIT_SET(entry->Sflag, ENTRY_REVALIDATE);
 	}
 	if (httpState->flags.keepalive)
 	    if (httpState->peer)
@@ -456,7 +456,7 @@
     else
 	delay_id = delayMostBytesAllowed(entry->mem_obj);
 #endif
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(fd);
 	return;
     }
@@ -536,11 +536,11 @@
 		 * allow the client to get it.
 		 */
 		if (!fwdReforwardableStatus(s))
-		    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+		    EBIT_CLR(entry->Sflag, ENTRY_FWD_HDR_WAIT);
 	    }
 	}
 	storeAppend(entry, buf, len);
-	if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+	if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	    /*
 	     * the above storeAppend() call could ABORT this entry,
 	     * in that case, the server FD should already be closed.
@@ -631,8 +631,8 @@
     HttpHeaderPos pos = HttpHeaderInitPos;
     httpHeaderInit(hdr_out, hoRequest);
     /* append our IMS header */
-    if (entry && entry->lastmod > -1 && request->method == METHOD_GET)
-	httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, entry->lastmod);
+    if (entry && entry->Slastmod > -1 && request->method == METHOD_GET)
+	httpHeaderPutTime(hdr_out, HDR_IF_MODIFIED_SINCE, entry->Slastmod);
 
     /* decide if we want to do Ranges ourselves 
      * (and fetch the whole object now)
@@ -935,7 +935,7 @@
 	comm_close(fd);
 	return;
     }
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(fd);
 	return;
     }
Index: squid/src/main.c
diff -u squid/src/main.c:1.1.1.2 squid/src/main.c:1.1.1.2.10.1
--- squid/src/main.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/main.c	Fri Nov 10 10:44:52 2000
@@ -516,8 +516,10 @@
     time_t loop_delay;
 
     debug_log = stderr;
+#if !HAVE_POLL
     if (FD_SETSIZE < Squid_MaxFD)
 	Squid_MaxFD = FD_SETSIZE;
+#endif
 
     /* call mallopt() before anything else */
 #if HAVE_MALLOPT
@@ -691,6 +693,7 @@
     if (*(argv[0]) == '(')
 	return;
     openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
+    if (getppid() != 1)
     if ((pid = fork()) < 0)
 	syslog(LOG_ALERT, "fork failed: %s", xstrerror());
     else if (pid > 0)
@@ -741,9 +744,12 @@
 	    failcount++;
 	else
 	    failcount = 0;
-	if (failcount == 5) {
-	    syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
-	    exit(1);
+	if (failcount >= 5) {
+	    extern char **environ;
+	    if (failcount == 5)
+		syslog(LOG_ALERT, "Repeated frequent failures!");
+	    sleep(1);
+	    execve(argv[0], argv, environ);
 	}
 	if (WIFEXITED(status))
 	    if (WEXITSTATUS(status) == 0)
@@ -806,6 +812,7 @@
     if (opt_no_daemon) {
 	file_close(0);
 	file_close(1);
+	if (opt_debug_stderr < 0)
 	file_close(2);
     }
 #endif
Index: squid/src/mem.c
diff -u squid/src/mem.c:1.1.1.2 squid/src/mem.c:1.1.1.2.12.1
--- squid/src/mem.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/mem.c	Fri Nov 10 10:44:52 2000
@@ -280,6 +280,8 @@
     memDataInit(MEM_STMEM_BUF, "Store Mem Buffer", SM_PAGE_SIZE,
 	Config.memMaxSize / SM_PAGE_SIZE);
     memDataInit(MEM_STOREENTRY, "StoreEntry", sizeof(StoreEntry), 0);
+    memDataInit(MEM_STORESWAPLOGDATA, "storeSwapLogData",
+	sizeof(storeSwapLogData), 0);
     memDataInit(MEM_STORE_CLIENT, "store_client", sizeof(store_client), 0);
     memDataInit(MEM_SWAPDIR, "SwapDir", sizeof(SwapDir), 0);
     memDataInit(MEM_USHORTLIST, "ushort_list", sizeof(ushortlist), 0);
Index: squid/src/mime.c
diff -u squid/src/mime.c:1.1.1.2 squid/src/mime.c:1.1.1.2.12.1
--- squid/src/mime.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/mime.c	Fri Nov 10 10:44:52 2000
@@ -431,9 +431,9 @@
     while ((n = read(fd, buf, 4096)) > 0)
 	storeAppend(e, buf, n);
     file_close(fd);
+    EBIT_SET(e->Sflag, ENTRY_SPECIAL);
     storeComplete(e);
     storeTimestampsSet(e);
-    EBIT_SET(e->flags, ENTRY_SPECIAL);
     debug(25, 3) ("Loaded icon %s\n", url);
     storeUnlockObject(e);
     memFree(buf, MEM_4K_BUF);
Index: squid/src/mime.conf
diff -u squid/src/mime.conf:1.1.1.2 squid/src/mime.conf:1.1.1.2.12.1
--- squid/src/mime.conf:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/mime.conf	Fri Nov 10 10:44:52 2000
@@ -30,6 +30,8 @@
 ^internal-unknown$	-			anthony-unknown.gif	-	ascii
 ^internal-view$		-			anthony-text.gif	-	ascii
 ^internal-download$	-			anthony-box.gif		-	ascii
+^internal-closeme$	-			closeme.html		-	ascii
+^internal-tiny$		-			tiny.gif		-	ascii
 \.bin$		application/macbinary		anthony-unknown.gif		-		image
 \.oda$		application/oda			anthony-unknown.gif		-		image
 \.exe$		application/octet-stream	anthony-unknown.gif		-		image
Index: squid/src/neighbors.c
diff -u squid/src/neighbors.c:1.1.1.2 squid/src/neighbors.c:1.1.1.2.10.1
--- squid/src/neighbors.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/neighbors.c	Fri Nov 10 10:44:52 2000
@@ -381,7 +381,7 @@
     mem->ping_reply_callback = callback;
     mem->ircb_data = callback_data;
     *timeout = 0.0;
-    reqnum = icpSetCacheKey(entry->key);
+    reqnum = icpSetCacheKey(entry->Skey);
     for (i = 0, p = first_ping; i++ < Config.npeers; p = p->next) {
 	if (p == NULL)
 	    p = Config.peers;
@@ -393,7 +393,7 @@
 	    p->host, url);
 	if (p->type == PEER_MULTICAST)
 	    mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
-	debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry->key));
+	debug(15, 3) ("neighborsUdpPing: key = '%s'\n", storeKeyText(entry->Skey));
 	debug(15, 3) ("neighborsUdpPing: reqnum = %d\n", reqnum);
 
 #if USE_HTCP
@@ -551,7 +551,8 @@
 #endif
     return LOOKUP_NONE;
 }
-
+    if (!request->flags.hierarchical)
+	return NULL;
 /* select best peer based on cache digests */
 peer *
 neighborsDigestSelect(request_t * request, StoreEntry * entry)
@@ -578,8 +579,10 @@
 	if (lookup == LOOKUP_NONE)
 	    continue;
 	choice_count++;
-	if (lookup == LOOKUP_MISS)
+	if (lookup == LOOKUP_MISS) {
+	    cacheDigestGuessStatsUpdate(&p->digest->stats.guess, 0, 0);
 	    continue;
+	}
 	p_rtt = netdbHostRtt(p->host);
 	debug(15, 5) ("neighborsDigestSelect: peer %s rtt: %d\n",
 	    p->host, p_rtt);
@@ -760,7 +763,7 @@
 	return;
     }
     /* check if someone is already fetching it */
-    if (EBIT_TEST(entry->flags, ENTRY_DISPATCHED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_DISPATCHED)) {
 	debug(15, 3) ("neighborsUdpAck: '%s' already being fetched.\n",
 	    storeKeyText(key));
 	neighborCountIgnored(p);
@@ -1067,7 +1070,7 @@
     mem->ircb_data = psstate;
     mcastSetTtl(theOutIcpConnection, p->mcast.ttl);
     p->mcast.id = mem->id;
-    reqnum = icpSetCacheKey(fake->key);
+    reqnum = icpSetCacheKey(fake->Skey);
     query = icpCreateMessage(ICP_QUERY, 0, url, reqnum, 0);
     icpUdpSend(theOutIcpConnection,
 	&p->in_addr,
@@ -1100,7 +1103,7 @@
 	p->mcast.avg_n_members,
 	p->stats.rtt);
     p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
-    EBIT_SET(fake->flags, ENTRY_ABORTED);
+    EBIT_SET(fake->Sflag, ENTRY_ABORTED);
     requestUnlink(fake->mem_obj->request);
     fake->mem_obj->request = NULL;
     storeReleaseRequest(fake);
Index: squid/src/net_db.c
diff -u squid/src/net_db.c:1.1.1.2 squid/src/net_db.c:1.1.1.2.10.1
--- squid/src/net_db.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/net_db.c	Fri Nov 10 10:44:52 2000
@@ -587,7 +587,7 @@
     debug(38, 3) ("netdbExchangeHandleReply: used %d entries, (x %d bytes) == %d bytes total\n",
 	nused, rec_sz, nused * rec_sz);
     debug(38, 3) ("netdbExchangeHandleReply: seen %d, used %d\n", ex->seen, ex->used);
-    if (EBIT_TEST(ex->e->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(ex->e->Sflag, ENTRY_ABORTED)) {
 	debug(38, 3) ("netdbExchangeHandleReply: ENTRY_ABORTED\n");
 	netdbExchangeDone(ex);
     } else if (ex->e->store_status == STORE_PENDING) {
Index: squid/src/pconn.c
diff -u squid/src/pconn.c:1.1.1.2 squid/src/pconn.c:1.1.1.2.28.1
--- squid/src/pconn.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/pconn.c	Fri Nov 10 10:44:52 2000
@@ -205,7 +205,7 @@
     p->fds[p->nfds++] = fd;
     commSetSelect(fd, COMM_SELECT_READ, pconnRead, p, 0);
     commSetTimeout(fd, Config.Timeout.pconn, pconnTimeout, p);
-    snprintf(desc, FD_DESC_SZ, "%s idle connection", host);
+    snprintf(desc, FD_DESC_SZ, "http://%s/ idle connection", host);
     fd_note(fd, desc);
     debug(48, 3) ("pconnPush: pushed FD %d for %s\n", fd, key);
 }
Index: squid/src/peer_digest.c
diff -u squid/src/peer_digest.c:1.1.1.2 squid/src/peer_digest.c:1.1.1.2.10.1
--- squid/src/peer_digest.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/peer_digest.c	Fri Nov 10 10:44:52 2000
@@ -179,8 +179,8 @@
 peerDigestNewDelay(const StoreEntry * e)
 {
     assert(e);
-    if (e->expires > 0)
-	return e->expires + PeerDigestReqMinGap - squid_curtime;
+    if (e->Sexpires > 0)
+	return e->Sexpires + PeerDigestReqMinGap - squid_curtime;
     return PeerDigestReqMinGap;
 }
 
@@ -309,11 +309,11 @@
 	storeClientListAdd(old_e, fetch);
     }
     e = fetch->entry = storeCreateEntry(url, url, req->flags, req->method);
-    assert(EBIT_TEST(e->flags, KEY_PRIVATE));
+    assert(EBIT_TEST(e->Sflag, KEY_PRIVATE));
     storeClientListAdd(e, fetch);
     /* set lastmod to trigger IMS request if possible */
     if (old_e)
-	e->lastmod = old_e->lastmod;
+	e->Slastmod = old_e->Slastmod;
 
     /* push towards peer cache */
     debug(72, 3) ("peerDigestRequest: forwarding to fwdStart...\n");
@@ -540,7 +540,7 @@
 	    reason = "swap failure";
 	else if (!fetch->entry)
 	    reason = "swap aborted?!";
-	else if (EBIT_TEST(fetch->entry->flags, ENTRY_ABORTED))
+	else if (EBIT_TEST(fetch->entry->Sflag, ENTRY_ABORTED))
 	    reason = "swap aborted";
     }
     /* continue checking (maybe-successful eof case) */
@@ -715,14 +715,14 @@
     fetch->recv.bytes = fetch->entry->store_status == STORE_PENDING ?
 	mem->inmem_hi : mem->object_sz;
     fetch->sent.msg = fetch->recv.msg = 1;
-    fetch->expires = fetch->entry->expires;
+    fetch->expires = fetch->entry->Sexpires;
     fetch->resp_time = squid_curtime - fetch->start_time;
 
     debug(72, 3) ("peerDigestFetchFinish: recv %d bytes in %d secs\n",
 	fetch->recv.bytes, fetch->resp_time);
     debug(72, 3) ("peerDigestFetchFinish: expires: %d (%+d), lmt: %d (%+d)\n",
 	fetch->expires, fetch->expires - squid_curtime,
-	fetch->entry->lastmod, fetch->entry->lastmod - squid_curtime);
+	fetch->entry->Slastmod, fetch->entry->Slastmod - squid_curtime);
 }
 
 
Index: squid/src/peer_select.c
diff -u squid/src/peer_select.c:1.1.1.2 squid/src/peer_select.c:1.1.1.2.10.1
--- squid/src/peer_select.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/peer_select.c	Fri Nov 10 10:44:52 2000
@@ -117,7 +117,7 @@
     debug(44, 3) ("peerSelectIcpPing: %s\n", storeUrl(entry));
     if (!request->flags.hierarchical && direct != DIRECT_NO)
 	return 0;
-    if (EBIT_TEST(entry->flags, KEY_PRIVATE) && !neighbors_do_private_keys)
+    if (EBIT_TEST(entry->Sflag, KEY_PRIVATE) && !neighbors_do_private_keys)
 	if (direct != DIRECT_NO)
 	    return 0;
     n = neighborsCount(request);
@@ -609,3 +609,22 @@
 	FS = &(*FS)->next;
     *FS = fs;
 }
+
+void
+freeFwdServer(FwdServer *fs)
+{
+    if (fs->peer)
+	cbdataUnlock(fs->peer);
+    memFree(fs, MEM_FWD_SERVER);
+}
+
+void
+freeFwdServers(FwdServer ** FS)
+{
+    FwdServer *fs;
+    while ((fs = *FS)) {
+	*FS = fs->next;
+	freeFwdServer(fs);
+    }
+}
+
Index: squid/src/protos.h
diff -u squid/src/protos.h:1.1.1.2 squid/src/protos.h:1.1.1.2.10.1
--- squid/src/protos.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/protos.h	Fri Nov 10 10:44:52 2000
@@ -620,6 +620,8 @@
 #if USE_HTCP
 extern void neighborsHtcpReply(const cache_key *, htcpReplyData *, const struct sockaddr_in *);
 #endif
+extern void freeFwdServer(FwdServer *);
+extern void freeFwdServers(FwdServer **);
 
 extern void netdbInit(void);
 extern void netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt);
@@ -773,6 +775,7 @@
  */
 extern StoreEntry *new_StoreEntry(int, const char *, const char *);
 extern StoreEntry *storeGet(const cache_key *);
+extern void storeHashDelete(StoreEntry *);
 extern StoreEntry *storeGetPublic(const char *uri, const method_t method);
 extern StoreEntry *storeCreateEntry(const char *, const char *, request_flags, method_t);
 extern void storeSetPublicKey(StoreEntry *);
@@ -826,7 +829,7 @@
 extern void storeAppendVPrintf(StoreEntry *, const char *, va_list ap);
 extern int storeCheckCachable(StoreEntry * e);
 extern void storeUnlinkFileno(int fileno);
-extern void storeSetPrivateKey(StoreEntry *);
+extern void storeSetPrivateKey(StoreEntry *, unsigned);
 extern int objectLen(const StoreEntry * e);
 extern int contentLen(const StoreEntry * e);
 extern HttpReply *storeEntryReply(StoreEntry *);
@@ -873,6 +876,7 @@
 /*
  * store_dir.c
  */
+extern SwapDir*getswapdir(int);
 extern char *storeSwapFullPath(int, char *);
 extern char *storeSwapSubSubDir(int, char *);
 extern int storeVerifySwapDirs(void);
@@ -886,8 +890,8 @@
 extern void storeDirCloseTmpSwapLog(int dirn);
 extern void storeDirOpenSwapLogs(void);
 extern void storeDirCloseSwapLogs(void);
-extern char *storeDirSwapLogFile(int, const char *);
-extern void storeDirSwapLog(const StoreEntry *, int op);
+extern void storeDirSwapLog(StoreEntry *, int op);
+extern storeSwapLogData *storeSwapAppendList(SwapDir*, storeSwapLogData*);
 extern int storeDirNumber(int fileno);
 extern void storeDirUpdateSwapSize(int fn, size_t size, int sign);
 extern int storeDirProperFileno(int dirn, int fn);
Index: squid/src/pump.c
diff -u squid/src/pump.c:1.1.1.2 squid/src/pump.c:1.1.1.2.10.1
--- squid/src/pump.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/pump.c	Fri Nov 10 10:44:52 2000
@@ -120,7 +120,7 @@
     request_t *r = fwd->request;
     size_t copy_sz;
     debug(61, 3) ("pumpStart: FD %d, key %s\n",
-	s_fd, storeKeyText(fwd->entry->key));
+	s_fd, storeKeyText(fwd->entry->Skey));
     /*
      * find state data generated by pumpInit in linked list
      */
@@ -205,7 +205,7 @@
 	pumpClose(p);
 	return;
     }
-    if (EBIT_TEST(p->request_entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(p->request_entry->Sflag, ENTRY_ABORTED)) {
 	debug(61, 5) ("pumpServerCopyComplete: ENTRY_ABORTED\n");
 	pumpClose(p);
 	return;
Index: squid/src/redirect.c
diff -u squid/src/redirect.c:1.1.1.2 squid/src/redirect.c:1.1.1.2.10.1
--- squid/src/redirect.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/redirect.c	Fri Nov 10 10:44:52 2000
@@ -103,7 +103,9 @@
     cbdataAdd(r, cbdataXfree, 0);
     r->orig_url = xstrdup(http->uri);
     r->client_addr = conn->log_addr;
-    if (conn->ident == NULL || *conn->ident == '\0') {
+    if (ntohs(conn->me.sin_port) == Config.Port.bhttp) {
+	r->client_ident = "B";
+    } else if (conn->ident == NULL || *conn->ident == '\0') {
 	r->client_ident = dash_str;
     } else {
 	r->client_ident = conn->ident;
@@ -114,11 +116,11 @@
     cbdataLock(r->data);
     if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL)
 	fqdn = dash_str;
-    snprintf(buf, 8192, "%s %s/%s %s %s\n",
+    snprintf(buf, 8192, "%s %s %s/%s %s\n\n",
+	r->client_ident,
 	r->orig_url,
 	inet_ntoa(r->client_addr),
 	fqdn,
-	r->client_ident,
 	r->method_s);
     helperSubmit(redirectors, buf, redirectHandleReply, r);
 }
Index: squid/src/refresh.c
diff -u squid/src/refresh.c:1.1.1.2 squid/src/refresh.c:1.1.1.2.12.1
--- squid/src/refresh.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/refresh.c	Fri Nov 10 10:44:52 2000
@@ -133,7 +133,7 @@
 
     debug(22, 3) ("refreshCheck(%s): '%s'\n", rc->proto, uri ? uri : "<none>");
     rc->total++;
-    if (EBIT_TEST(entry->flags, ENTRY_REVALIDATE)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_REVALIDATE)) {
 	debug(22, 3) ("refreshCheck: YES: Required Authorization\n");
 	rc->revalidate_stale++;
 	return 1;
@@ -156,10 +156,10 @@
 #endif
     debug(22, 3) ("refreshCheck: Matched '%s %d %d%% %d'\n",
 	pattern, (int) min, (int) (100.0 * pct), (int) max);
-    age = check_time - entry->timestamp;
+    age = check_time - entry->Stimestamp;
     debug(22, 3) ("refreshCheck: age = %d\n", (int) age);
     debug(22, 3) ("\tcheck_time:\t%s\n", mkrfc1123(check_time));
-    debug(22, 3) ("\tentry->timestamp:\t%s\n", mkrfc1123(entry->timestamp));
+    debug(22, 3) ("\tentry->Stimestamp:\t%s\n", mkrfc1123(entry->Stimestamp));
     /* request-specific checks */
     if (request) {
 #if HTTP_VIOLATIONS
@@ -202,8 +202,8 @@
 	return 0;
     }
 #endif
-    if (entry->expires > -1) {
-	if (entry->expires <= check_time) {
+    if (entry->Sexpires > -1) {
+	if (entry->Sexpires <= check_time) {
 	    debug(22, 3) ("refreshCheck: YES: expires <= curtime\n");
 	    rc->response_expires_stale++;
 	    return 1;
@@ -225,8 +225,8 @@
 	return 0;
     }
 #endif
-    if (entry->lastmod > -1 && entry->timestamp > entry->lastmod) {
-	factor = (double) age / (double) (entry->timestamp - entry->lastmod);
+    if (entry->Slastmod > -1 && entry->Stimestamp > entry->Slastmod) {
+	factor = (double) age / (double) (entry->Stimestamp - entry->Slastmod);
 	debug(22, 3) ("refreshCheck: factor = %f\n", factor);
 	if (factor < pct) {
 	    debug(22, 3) ("refreshCheck: NO: factor < pct\n");
@@ -237,11 +237,11 @@
 	    rc->last_modified_factor_stale++;
 	    return 1;
 	}
-    } else if (entry->lastmod > -1 && entry->timestamp == entry->lastmod) {
+    } else if (entry->Slastmod > -1 && entry->Stimestamp == entry->Slastmod) {
 	debug(22, 3) ("refreshCheck: YES: last-modified 'now'\n");
 	rc->response_lmt_now_stale++;
 	return 1;
-    } else if (entry->lastmod > -1 && entry->timestamp < entry->lastmod) {
+    } else if (entry->Slastmod > -1 && entry->Stimestamp < entry->Slastmod) {
 	debug(22, 3) ("refreshCheck: MAYBE: last-modified in the future\n");
 	rc->response_lmt_future_maybe++;
     }
@@ -267,7 +267,7 @@
     if (!refreshCheck(entry, NULL, 60, &refreshCounts[rcStore]))
 	/* Does not need refresh. This is certainly cachable */
 	return 1;
-    if (entry->lastmod < 0)
+    if (entry->Slastmod < 0)
 	/* Last modified is needed to do a refresh */
 	return 0;
     if (entry->mem_obj == NULL)
Index: squid/src/snmp_agent.c
diff -u squid/src/snmp_agent.c:1.1.1.2 squid/src/snmp_agent.c:1.1.1.2.12.1
--- squid/src/snmp_agent.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/snmp_agent.c	Fri Nov 10 10:44:52 2000
@@ -312,7 +312,11 @@
 	break;
     case PERF_SYS_CURLRUEXP:
 	Answer->type = SMI_TIMETICKS;
+#if HPL_REPL
+	*(Answer->val.integer) = 0;
+#else
 	*(Answer->val.integer) = (snint) (storeExpiredReferenceAge() * 100);
+#endif
 	break;
     case PERF_SYS_CURUNLREQ:
 	*(Answer->val.integer) = (snint) Counter.unlink.requests;
Index: squid/src/squid.h
diff -u squid/src/squid.h:1.1.1.2 squid/src/squid.h:1.1.1.2.10.1
--- squid/src/squid.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/squid.h	Fri Nov 10 10:44:52 2000
@@ -82,6 +82,9 @@
 #if HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
 #if HAVE_STDIO_H
 #include <stdio.h>
 #endif
Index: squid/src/stat.c
diff -u squid/src/stat.c:1.1.1.2 squid/src/stat.c:1.1.1.2.10.1
--- squid/src/stat.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/stat.c	Fri Nov 10 10:44:52 2000
@@ -201,7 +201,7 @@
 storeEntryFlags(const StoreEntry * entry)
 {
     LOCAL_ARRAY(char, buf, 256);
-    int flags = (int) entry->flags;
+    int flags = (int) entry->Sflag;
     char *t;
     buf[0] = '\0';
     if (EBIT_TEST(flags, ENTRY_SPECIAL))
@@ -240,10 +240,10 @@
 {
     LOCAL_ARRAY(char, buf, 256);
     snprintf(buf, 256, "LV:%-9d LU:%-9d LM:%-9d EX:%-9d",
-	(int) entry->timestamp,
-	(int) entry->lastref,
-	(int) entry->lastmod,
-	(int) entry->expires);
+	(int) entry->Stimestamp,
+	(int) entry->Slastref,
+	(int) entry->Slastmod,
+	(int) entry->Sexpires);
     return buf;
 }
 
@@ -253,7 +253,7 @@
     MemObject *mem = e->mem_obj;
     int i;
     struct _store_client *sc;
-    storeAppendPrintf(s, "KEY %s\n", storeKeyText(e->key));
+    storeAppendPrintf(s, "KEY %s\n", storeKeyText(e->Skey));
     if (mem)
 	storeAppendPrintf(s, "\t%s %s\n",
 	    RequestMethodStr[mem->method], mem->log_url);
@@ -263,9 +263,9 @@
     storeAppendPrintf(s, "\t%d locks, %d clients, %d refs\n",
 	(int) e->lock_count,
 	storePendingNClients(e),
-	(int) e->refcount);
+	(int) e->Srefcount);
     storeAppendPrintf(s, "\tSwap File %#08X\n",
-	e->swap_file_number);
+	e->Sswap_file_number);
     if (mem != NULL) {
 	storeAppendPrintf(s, "\tinmem_lo: %d\n", (int) mem->inmem_lo);
 	storeAppendPrintf(s, "\tinmem_hi: %d\n", (int) mem->inmem_hi);
@@ -311,7 +311,7 @@
 	storeUnlockObject(state->sentry);
 	cbdataFree(state);
 	return;
-    } else if (EBIT_TEST(state->sentry->flags, ENTRY_ABORTED)) {
+    } else if (EBIT_TEST(state->sentry->Sflag, ENTRY_ABORTED)) {
 	storeUnlockObject(state->sentry);
 	cbdataFree(state);
 	return;
@@ -489,8 +489,12 @@
 	store_swap_size);
     storeAppendPrintf(sentry, "\tStorage Mem size:\t%d KB\n",
 	(int) (store_mem_size >> 10));
+    #ifdef	HPL_REPL
+    /* The non-LRU policies do not use referenceAge */
+    #else	/* HPL_REPL */
     storeAppendPrintf(sentry, "\tStorage LRU Expiration Age:\t%6.2f days\n",
 	(double) storeExpiredReferenceAge() / 86400.0);
+    #endif	/* HPL_REPL */
     storeAppendPrintf(sentry, "\tMean Object Size:\t%0.2f KB\n",
 	n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0);
     storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%d\n",
@@ -603,6 +607,8 @@
 	memInUse(MEM_STOREENTRY));
     storeAppendPrintf(sentry, "\t%6d StoreEntries with MemObjects\n",
 	memInUse(MEM_MEMOBJECT));
+    storeAppendPrintf(sentry, "\t%6d storeSwapLogData temporaries\n",
+	memInUse(MEM_STORESWAPLOGDATA));
     storeAppendPrintf(sentry, "\t%6d Hot Object Cache Items\n",
 	hot_obj_count);
     storeAppendPrintf(sentry, "\t%6d Filemap bits set\n",
@@ -824,9 +830,11 @@
     cachemgrRegister("filedescriptors",
 	"Process Filedescriptor Allocation",
 	statFiledescriptors, 0, 1);
+#ifdef DEBUG_ALLOBJECTS
     cachemgrRegister("objects",
 	"All Cache Objects",
 	stat_objects_get, 0, 0);
+#endif
     cachemgrRegister("vm_objects",
 	"In-Memory and In-Transit Objects",
 	stat_vmobjects_get, 0, 0);
@@ -1336,9 +1344,9 @@
 	    http->out.offset, http->out.size);
 	storeAppendPrintf(s, "req_sz %d\n", http->req_sz);
 	e = http->entry;
-	storeAppendPrintf(s, "entry %p/%s\n", e, e ? storeKeyText(e->key) : "N/A");
+	storeAppendPrintf(s, "entry %p/%s\n", e, e ? storeKeyText(e->Skey) : "N/A");
 	e = http->old_entry;
-	storeAppendPrintf(s, "old_entry %p/%s\n", e, e ? storeKeyText(e->key) : "N/A");
+	storeAppendPrintf(s, "old_entry %p/%s\n", e, e ? storeKeyText(e->Skey) : "N/A");
 	storeAppendPrintf(s, "start %d.%06d (%f seconds ago)\n", http->start.tv_sec,
 	    http->start.tv_usec,
 	    tvSubDsec(http->start, current_time));
Index: squid/src/store.c
diff -u squid/src/store.c:1.1.1.2 squid/src/store.c:1.1.1.2.10.1
--- squid/src/store.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store.c	Fri Nov 10 10:44:52 2000
@@ -35,6 +35,10 @@
 
 #include "squid.h"
 
+#ifdef	HPL_REPL
+#include "heap.h"
+#endif	/* HPL_REPL */
+
 #define REBUILD_TIMESTAMP_DELTA_MAX 2
 
 #define STORE_IN_MEM_BUCKETS		(229)
@@ -79,7 +83,6 @@
 static int storeEntryLocked(const StoreEntry *);
 static int storeEntryValidLength(const StoreEntry *);
 static void storeGetMemSpace(int);
-static void storeHashDelete(StoreEntry *);
 static MemObject *new_MemObject(const char *, const char *);
 static void destroy_MemObject(StoreEntry *);
 static FREE destroy_StoreEntry;
@@ -92,7 +95,14 @@
 /*
  * local variables
  */
+#ifdef	HPL_REPL
+/*
+ * The heap equivalent of inmem_list, inmem_heap, is in globals.c so other
+ * modules can access it when updating object metadata (e.g., refcount)
+ */
+#else	/* HPL_REPL */
 static dlink_list inmem_list;
+#endif	/* HPL_REPL */
 static int store_pages_max = 0;
 static int store_swap_high = 0;
 static int store_swap_low = 0;
@@ -110,6 +120,9 @@
     mem->swapout.fd = -1;
     mem->object_sz = -1;
     mem->fd = -1;
+#if HPL_REPL
+    mem->n.ode.id = -1;
+#endif
     /* XXX account log_url */
     debug(20, 3) ("new_MemObject: returning %p\n", mem);
     return mem;
@@ -120,10 +133,18 @@
 {
     StoreEntry *e = NULL;
     e = memAllocate(MEM_STOREENTRY);
-    if (mem_obj_flag)
+    if (mem_obj_flag) {
 	e->mem_obj = new_MemObject(url, log_url);
+#if HPL_REPL
+	e->mem_obj->entry = e;
+#endif
+        e->s = memAllocate(MEM_STORESWAPLOGDATA);
+        e->Sexpires = e->Slastmod = e->Slastref = e->Stimestamp = -1;
+    }
+#if HPL_REPL
+    e->n.ode.id = -1;
+#endif
     debug(20, 3) ("new_StoreEntry: returning %p\n", e);
-    e->expires = e->lastmod = e->lastref = e->timestamp = -1;
     return e;
 }
 
@@ -132,7 +153,7 @@
 {
     MemObject *mem = e->mem_obj;
     const Ctx ctx = ctx_enter(mem->url);
-    debug(20, 3) ("destroy_MemObject: destroying %p\n", mem);
+    debug(20, 4) ("destroy_MemObject: destroying %p\n", mem);
     e->mem_obj = NULL;
     if (!shutting_down)
 	assert(mem->swapout.fd == -1);
@@ -161,12 +182,16 @@
 destroy_StoreEntry(void *data)
 {
     StoreEntry *e = data;
-    debug(20, 3) ("destroy_StoreEntry: destroying %p\n", e);
+    debug(20, 4) ("destroy_StoreEntry: destroying %p\n", e);
     assert(e != NULL);
     if (e->mem_obj)
 	destroy_MemObject(e);
     storeHashDelete(e);
-    assert(e->key == NULL);
+    if (e->s)
+	destroy_storeSwapLogData(e->s);
+#ifndef MMAPSTORE
+    assert(e->Skey == NULL);
+#endif
     memFree(e, MEM_STOREENTRY);
 }
 
@@ -177,18 +202,33 @@
 {
     debug(20, 3) ("storeHashInsert: Inserting Entry %p key '%s'\n",
 	e, storeKeyText(key));
-    e->key = storeKeyDup(key);
-    hash_join(store_table, (hash_link *) e);
+#ifdef MMAPSTORE
+    if (key != e->s->key)
+	xmemcpy(e->s->key, key, MD5_DIGEST_CHARS);
+#else
+    e->Skey = storeKeyDup(key);
+#endif
+    if(hash_join(store_table, (hash_link *) e))
+	debug(20, 0) ("storeHashInsert: duplicate entry %p %s\n",e,storeUrl(e));
+    if (e->Sswap_file_number < 0)
+	return;
+    #if	!HPL_REPL
     dlinkAdd(e, &e->lru, &store_list);
+    #endif	/* HPL_REPL */
 }
 
-static void
+void
 storeHashDelete(StoreEntry * e)
 {
-    hash_remove_link(store_table, (hash_link *) e);
+    if(hash_remove_link(store_table, (hash_link *) e))
+	debug(20, 2) ("storeHashDelete: missing entry %p %s\n",e,storeUrl(e));
+    #if	!HPL_REPL
     dlinkDelete(&e->lru, &store_list);
-    storeKeyFree(e->key);
-    e->key = NULL;
+    #endif	/* HPL_REPL */
+#ifndef MMAPSTORE
+    storeKeyFree(e->Skey);
+    e->Skey = NULL;
+#endif
 }
 
 /* -------------------------------------------------------------------------- */
@@ -202,7 +242,7 @@
     if (e->mem_obj == NULL)
 	return;
     debug(20, 3) ("storePurgeMem: Freeing memory-copy of %s\n",
-	storeKeyText(e->key));
+	storeKeyText(e->Skey));
     storeSetMemStatus(e, NOT_IN_MEMORY);
     destroy_MemObject(e);
     if (e->swap_status != SWAPOUT_DONE)
@@ -213,28 +253,37 @@
 storeLockObject(StoreEntry * e)
 {
     if (e->lock_count++ == 0) {
+      #ifdef	HPL_REPL
+      /* there is no reason to take any action here.
+	 Squid by default is moving locked objects to the end of the LRU
+	 list to keep them from getting bumped into by the replacement
+	 algorithm.  We can't do that so we will just have to handle them.
+      */
+      debug(20, 4) ("storeLockObject: just locked node %d\n", e->n.ode.id);
+      #else	/* HPL_REPL */
 	dlinkDelete(&e->lru, &store_list);
 	dlinkAdd(e, &e->lru, &store_list);
+      #endif	/* HPL_REPL */
     }
-    debug(20, 3) ("storeLockObject: key '%s' count=%d\n",
-	storeKeyText(e->key), (int) e->lock_count);
-    e->lastref = squid_curtime;
+    debug(20, 4) ("storeLockObject: key '%s' count=%d\n",
+	storeKeyText(e->Skey), (int) e->lock_count);
+    e->Slastref = squid_curtime;
 }
 
 void
 storeReleaseRequest(StoreEntry * e)
 {
-    if (EBIT_TEST(e->flags, RELEASE_REQUEST))
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
 	return;
-    debug(20, 3) ("storeReleaseRequest: '%s'\n", storeKeyText(e->key));
-    EBIT_SET(e->flags, RELEASE_REQUEST);
+    debug(20, 3) ("storeReleaseRequest: '%s'\n", storeKeyText(e->Skey));
+    EBIT_SET(e->Sflag, RELEASE_REQUEST);
     /*
      * Clear cachable flag here because we might get called before
      * anyone else even looks at the cachability flag.  Also, this
      * prevents httpMakePublic from really setting a public key.
      */
-    EBIT_CLR(e->flags, ENTRY_CACHABLE);
-    storeSetPrivateKey(e);
+    EBIT_CLR(e->Sflag, ENTRY_CACHABLE);
+    storeSetPrivateKey(e, 1);
 }
 
 /* unlock object, return -1 if object get released after unlock
@@ -244,13 +293,13 @@
 {
     e->lock_count--;
     debug(20, 3) ("storeUnlockObject: key '%s' count=%d\n",
-	storeKeyText(e->key), e->lock_count);
+	storeKeyText(e->Skey), e->lock_count);
     if (e->lock_count)
 	return (int) e->lock_count;
     if (e->store_status == STORE_PENDING)
-	EBIT_SET(e->flags, RELEASE_REQUEST);
+	EBIT_SET(e->Sflag, RELEASE_REQUEST);
     assert(storePendingNClients(e) == 0);
-    if (EBIT_TEST(e->flags, RELEASE_REQUEST))
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
 	storeRelease(e);
     else if (storeKeepInMemory(e)) {
 	storeSetMemStatus(e, IN_MEMORY);
@@ -258,9 +307,17 @@
 	e->mem_obj->request = NULL;
     } else {
 	storePurgeMem(e);
-	if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
+	if (EBIT_TEST(e->Sflag, KEY_PRIVATE)) {
+        #ifdef	HPL_REPL
+        /*
+         * Squid/LRU is moving things around in the linked list in order
+         * to keep from bumping into them when purging from the LRU list.
+         */
+        debug(20, 4) ("storeUnlockObject: purged private node %d\n", e->n.ode.id);
+        #else	/* HPL_REPL */
 	    dlinkDelete(&e->lru, &store_list);
 	    dlinkAddTail(e, &e->lru, &store_list);
+        #endif	/* HPL_REPL */
 	}
     }
     return 0;
@@ -291,17 +348,16 @@
 }
 
 void
-storeSetPrivateKey(StoreEntry * e)
+storeSetPrivateKey(StoreEntry * e, unsigned hashed)
 {
     const cache_key *newkey;
     MemObject *mem = e->mem_obj;
-    if (e->key && EBIT_TEST(e->flags, KEY_PRIVATE))
+    if (EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	return;			/* is already private */
-    if (e->key) {
-	if (e->swap_file_number > -1)
+    if (e->Sswap_file_number > -1)
 	    storeDirSwapLog(e, SWAP_LOG_DEL);
+    if (hashed)
 	storeHashDelete(e);
-    }
     if (mem != NULL) {
 	mem->id = getKeyCounter();
 	newkey = storeKeyPrivate(mem->url, mem->method, mem->id);
@@ -309,7 +365,7 @@
 	newkey = storeKeyPrivate("JUNK", METHOD_NONE, getKeyCounter());
     }
     assert(hash_lookup(store_table, newkey) == NULL);
-    EBIT_SET(e->flags, KEY_PRIVATE);
+    EBIT_SET(e->Sflag, KEY_PRIVATE);
     storeHashInsert(e, newkey);
 }
 
@@ -319,7 +375,7 @@
     StoreEntry *e2 = NULL;
     const cache_key *newkey;
     MemObject *mem = e->mem_obj;
-    if (e->key && !EBIT_TEST(e->flags, KEY_PRIVATE))
+    if (!EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	return;			/* is already public */
     assert(mem);
     /*
@@ -332,19 +388,22 @@
      * If RELEASE_REQUEST is set, then ENTRY_CACHABLE should not
      * be set, and storeSetPublicKey() should not be called.
      */
-    assert(!EBIT_TEST(e->flags, RELEASE_REQUEST));
+#ifdef	HPL_REPL_DEBUG
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
+	    debug(20, 1) ("assertion failed: RELEASE key %s, url %s\n", e->Skey, mem->url);
+#endif	/* HPL_REPL */
+    assert(!EBIT_TEST(e->Sflag, RELEASE_REQUEST));
     newkey = storeKeyPublic(mem->url, mem->method);
     if ((e2 = (StoreEntry *) hash_lookup(store_table, newkey))) {
 	debug(20, 3) ("storeSetPublicKey: Making old '%s' private.\n", mem->url);
-	storeSetPrivateKey(e2);
+	storeSetPrivateKey(e2, 1);
 	storeRelease(e2);
 	newkey = storeKeyPublic(mem->url, mem->method);
     }
-    if (e->key)
 	storeHashDelete(e);
-    EBIT_CLR(e->flags, KEY_PRIVATE);
+    EBIT_CLR(e->Sflag, KEY_PRIVATE);
     storeHashInsert(e, newkey);
-    if (e->swap_file_number > -1)
+    if (e->Sswap_file_number > -1)
 	storeDirSwapLog(e, SWAP_LOG_ADD);
 }
 
@@ -359,26 +418,26 @@
     e->lock_count = 1;		/* Note lock here w/o calling storeLock() */
     mem = e->mem_obj;
     mem->method = method;
+    e->Sswap_file_number = -1;
     if (neighbors_do_private_keys || !flags.hierarchical)
-	storeSetPrivateKey(e);
+	storeSetPrivateKey(e, 0);
     else
 	storeSetPublicKey(e);
     if (flags.cachable) {
-	EBIT_SET(e->flags, ENTRY_CACHABLE);
-	EBIT_CLR(e->flags, RELEASE_REQUEST);
+	EBIT_SET(e->Sflag, ENTRY_CACHABLE);
+	EBIT_CLR(e->Sflag, RELEASE_REQUEST);
     } else {
-	EBIT_CLR(e->flags, ENTRY_CACHABLE);
+	EBIT_CLR(e->Sflag, ENTRY_CACHABLE);
 	storeReleaseRequest(e);
     }
     e->store_status = STORE_PENDING;
     storeSetMemStatus(e, NOT_IN_MEMORY);
     e->swap_status = SWAPOUT_NONE;
-    e->swap_file_number = -1;
-    e->refcount = 0;
-    e->lastref = squid_curtime;
-    e->timestamp = 0;		/* set in storeTimestampsSet() */
+    e->Srefcount = 0;
+    e->Slastref = squid_curtime;
+    e->Stimestamp = 0;		/* set in storeTimestampsSet() */
     e->ping_status = PING_NONE;
-    EBIT_SET(e->flags, ENTRY_VALIDATED);
+    EBIT_SET(e->Sflag, ENTRY_VALIDATED);
     return e;
 }
 
@@ -386,8 +445,8 @@
 void
 storeExpireNow(StoreEntry * e)
 {
-    debug(20, 3) ("storeExpireNow: '%s'\n", storeKeyText(e->key));
-    e->expires = squid_curtime;
+    debug(20, 3) ("storeExpireNow: '%s'\n", storeKeyText(e->Skey));
+    e->Sexpires = squid_curtime;
 }
 
 /* Append incoming data from a primary server to an entry. */
@@ -399,14 +458,14 @@
     assert(len >= 0);
     assert(e->store_status == STORE_PENDING);
     if (len) {
-	debug(20, 5) ("storeAppend: appending %d bytes for '%s'\n",
+	debug(20, 6) ("storeAppend: appending %d bytes for '%s'\n",
 	    len,
-	    storeKeyText(e->key));
+	    storeKeyText(e->Skey));
 	storeGetMemSpace(len);
 	stmemAppend(&mem->data_hdr, buf, len);
 	mem->inmem_hi += len;
     }
-    if (EBIT_TEST(e->flags, DELAY_SENDING))
+    if (EBIT_TEST(e->Sflag, DELAY_SENDING))
 	return;
 #ifdef OPTIMISTIC_IO
     storeLockObject(e);
@@ -488,23 +547,25 @@
 	store_check_cachable_hist.no.non_get++;
     } else
 #endif
-    if (!EBIT_TEST(e->flags, ENTRY_CACHABLE)) {
+    if (!EBIT_TEST(e->Sflag, ENTRY_CACHABLE)) {
 	debug(20, 2) ("storeCheckCachable: NO: not cachable\n");
 	store_check_cachable_hist.no.not_entry_cachable++;
-    } else if (EBIT_TEST(e->flags, RELEASE_REQUEST)) {
+    } else if (EBIT_TEST(e->Sflag, RELEASE_REQUEST)) {
 	debug(20, 2) ("storeCheckCachable: NO: release requested\n");
 	store_check_cachable_hist.no.release_request++;
-    } else if (e->store_status == STORE_OK && EBIT_TEST(e->flags, ENTRY_BAD_LENGTH)) {
+    } else if (e->store_status == STORE_OK && EBIT_TEST(e->Sflag, ENTRY_BAD_LENGTH)) {
 	debug(20, 2) ("storeCheckCachable: NO: wrong content-length\n");
 	store_check_cachable_hist.no.wrong_content_length++;
-    } else if (EBIT_TEST(e->flags, ENTRY_NEGCACHED)) {
+    } else if (EBIT_TEST(e->Sflag, ENTRY_NEGCACHED)) {
 	debug(20, 3) ("storeCheckCachable: NO: negative cached\n");
 	store_check_cachable_hist.no.negative_cached++;
 	return 0;		/* avoid release call below */
-    } else if (e->mem_obj->inmem_hi > Config.Store.maxObjectSize) {
+    } else if ((e->mem_obj->reply->content_length > 0 &&
+		e->mem_obj->reply->content_length > Config.Store.maxObjectSize) ||
+		e->mem_obj->inmem_hi > Config.Store.maxObjectSize) {
 	debug(20, 2) ("storeCheckCachable: NO: too big\n");
 	store_check_cachable_hist.no.too_big++;
-    } else if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
+    } else if (EBIT_TEST(e->Sflag, KEY_PRIVATE)) {
 	debug(20, 3) ("storeCheckCachable: NO: private key\n");
 	store_check_cachable_hist.no.private_key++;
     } else if (e->swap_status != SWAPOUT_NONE) {
@@ -515,21 +576,28 @@
 	 */
 	return 1;
     } else if (storeTooManyDiskFilesOpen()) {
-	debug(20, 2) ("storeCheckCachable: NO: too many disk files open\n");
+	debug(20, 3) ("storeCheckCachable: NO: too many disk files open\n");
 	store_check_cachable_hist.no.too_many_open_files++;
     } else if (fdNFree() < RESERVED_FD) {
-	debug(20, 2) ("storeCheckCachable: NO: too many FD's open\n");
+	debug(20, 3) ("storeCheckCachable: NO: too many FD's open\n");
 	store_check_cachable_hist.no.too_many_open_fds++;
+#ifdef	HPL_REPL
+    /*
+     * With the HPL replacement policies a low reference age should not
+     * prevent cacheability of an object.  We do not use LRU age at all.
+     */
+#else	/* HPL_REPL */
     } else if (storeExpiredReferenceAge() < 300) {
-	debug(20, 2) ("storeCheckCachable: NO: LRU Age = %d\n",
+	debug(20, 3) ("storeCheckCachable: NO: LRU Age = %d\n",
 	    storeExpiredReferenceAge());
 	store_check_cachable_hist.no.lru_age_too_low++;
+#endif	/* HPL_REPL */
     } else {
 	store_check_cachable_hist.yes.Default++;
 	return 1;
     }
     storeReleaseRequest(e);
-    EBIT_CLR(e->flags, ENTRY_CACHABLE);
+    EBIT_CLR(e->Sflag, ENTRY_CACHABLE);
     return 0;
 }
 
@@ -566,13 +634,13 @@
 void
 storeComplete(StoreEntry * e)
 {
-    debug(20, 3) ("storeComplete: '%s'\n", storeKeyText(e->key));
+    debug(20, 3) ("storeComplete: '%s'\n", storeKeyText(e->Skey));
     if (e->store_status != STORE_PENDING) {
 	/*
 	 * if we're not STORE_PENDING, then probably we got aborted
 	 * and there should be NO clients on this entry
 	 */
-	assert(EBIT_TEST(e->flags, ENTRY_ABORTED));
+	assert(EBIT_TEST(e->Sflag, ENTRY_ABORTED));
 	assert(e->mem_obj->nclients == 0);
 	return;
     }
@@ -580,7 +648,7 @@
     e->store_status = STORE_OK;
     assert(e->mem_status == NOT_IN_MEMORY);
     if (!storeEntryValidLength(e)) {
-	EBIT_SET(e->flags, ENTRY_BAD_LENGTH);
+	EBIT_SET(e->Sflag, ENTRY_BAD_LENGTH);
 	storeReleaseRequest(e);
     }
 #if USE_CACHE_DIGESTS
@@ -602,11 +670,11 @@
     MemObject *mem = e->mem_obj;
     assert(e->store_status == STORE_PENDING);
     assert(mem != NULL);
-    debug(20, 6) ("storeAbort: %s\n", storeKeyText(e->key));
+    debug(20, 6) ("storeAbort: %s\n", storeKeyText(e->Skey));
     storeLockObject(e);		/* lock while aborting */
     storeNegativeCache(e);
     storeReleaseRequest(e);
-    EBIT_SET(e->flags, ENTRY_ABORTED);
+    EBIT_SET(e->Sflag, ENTRY_ABORTED);
     storeSetMemStatus(e, NOT_IN_MEMORY);
     /* No DISK swap for negative cached object */
     e->swap_status = SWAPOUT_NONE;
@@ -634,7 +702,7 @@
 #if USE_ASYNC_IO
     aioCancel(-1, e);
 #endif
-    if (e->swap_file_number > -1) {
+    if (e->Sswap_file_number > -1) {
 #if USE_ASYNC_IO
 	/* Need to cancel any pending ASYNC writes right now */
 	if (mem->swapout.fd >= 0)
@@ -656,17 +724,63 @@
     static time_t last_check = 0;
     int pages_needed;
     dlink_node *m;
-    dlink_node *head;
     dlink_node *prev = NULL;
+    int locked = 0;
+    #ifdef	HPL_REPL
+    heap_p heap = inmem_heap;
+    _HEAPKEY age, min_age = 0;
+    MemObject *locked_entries = NULL;
+    MemObject *mo;
+    #else	/* HPL_REPL */
+    dlink_node *head;
+    #endif	/* HPL_REPL */
+
     if (squid_curtime == last_check)
 	return;
     last_check = squid_curtime;
     pages_needed = (size / SM_PAGE_SIZE) + 1;
+    debug(20, 3) ("storeGetMemSpace: inuse %d, need %d, have %d\n",
+		  memInUse(MEM_STMEM_BUF), pages_needed, store_pages_max);
     if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max)
 	return;
     if (store_rebuilding)
 	return;
     debug(20, 2) ("storeGetMemSpace: Starting, need %d pages\n", pages_needed);
+    #ifdef	HPL_REPL
+    while (heap_nodes(heap) > 0) {
+        age = heap_peepminkey(heap);
+	mo = heap_extractmin(heap);
+	e = mo->entry;
+	if (storeEntryLocked(e)) {
+	  locked++;
+	  debug(20, 5) ("storeGetMemSpace: locked key %s\n", storeKeyText(e->Skey));
+	  mo->n.ext = locked_entries;
+	  locked_entries = mo;
+	  continue;
+	}
+	mo->n.ode.id = -1;		/* no longer in the heap */
+	released++;
+	debug(20, 3) ("Released memory object with key %f size %d refs %d url %s\n",
+		age, e->Sswap_file_sz, e->Srefcount, e->mem_obj->url);
+	min_age = age;
+	storePurgeMem(e);
+	if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max)
+	    break;
+    }
+    /*
+     * Increase the heap age factor.
+     */
+    if (min_age > 0)
+      heap->age = min_age;
+    /*
+     * Reinsert all bumped locked entries back into heap...
+     */
+    while (mo = locked_entries) {
+      locked_entries = mo->n.ext;
+      heap_insert(heap, mo);
+    }
+
+    #else	/* HPL_REPL */
     head = inmem_list.head;
     for (m = inmem_list.tail; m; m = prev) {
 	if (m == head)
@@ -674,6 +788,7 @@
 	prev = m->prev;
 	e = m->data;
 	if (storeEntryLocked(e)) {
+	    locked++;
 	    dlinkDelete(m, &inmem_list);
 	    dlinkAdd(e, m, &inmem_list);
 	    continue;
@@ -683,9 +798,12 @@
 	if (memInUse(MEM_STMEM_BUF) + pages_needed < store_pages_max)
 	    break;
     }
-    debug(20, 3) ("storeGetMemSpace stats:\n");
-    debug(20, 3) ("  %6d HOT objects\n", hot_obj_count);
-    debug(20, 3) ("  %6d were released\n", released);
+    #endif	/* HPL_REPL */
+    debug(20, 3) ("storeGetMemSpace: released %d/%d locked %d\n",
+		  released, hot_obj_count, locked);
+    debug(20, 4) ("storeGetMemSpace stats:\n");
+    debug(20, 4) ("  %6d HOT objects\n", hot_obj_count);
+    debug(20, 4) ("  %6d were released\n", released);
 }
 
 /* The maximum objects to scan for maintain storage space */
@@ -709,26 +827,150 @@
     int locked = 0;
     int expired = 0;
     int max_scan;
-    int max_remove;
-    double f;
     static time_t last_warn_time = 0;
+    SwapDir *SD;
+    unsigned i;
+    #ifdef	HPL_REPL
+
+    #ifdef	HPL_REPL_DEBUG
+    if (!verify_heap_property(store_heap)) {
+	debug(20, 1) ("Heap property violated!\n");
+    }
+    #endif	/* HPL_REPL_DEBUG */
+    #endif	/* HPL_REPL */
+
     /* We can't delete objects while rebuilding swap */
     if (store_rebuilding) {
 	eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0, 1);
 	return;
     } else {
-	f = (double) (store_swap_size - store_swap_low) / (store_swap_high - store_swap_low);
+        double f;
+	f = ((double) (store_swap_size - store_swap_low) /
+	     (store_swap_high - store_swap_low));
 	f = f < 0.0 ? 0.0 : f > 1.0 ? 1.0 : f;
 	max_scan = (int) (f * 400.0 + 100.0);
-	max_remove = (int) (f * 70.0 + 10.0);
-	eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 1.0 - f, 1);
+	eventAdd("MaintainSwapSpace", storeMaintainSwapSpace, NULL, 10*(1.0 - f), 1);
+    }
+
+#if 0
+    if (store_swap_size < store_swap_low) {
+        /* Just return since we still have enougy memory */
+        return; 
     }
-    debug(20, 3) ("storeMaintainSwapSpace: f=%f, max_scan=%d, max_remove=%d\n",
-	f, max_scan, max_remove);
+#endif
+    {
+        int dirmax = -1;
+	unsigned long dirmaxval = 0;
+
+	for (SD = Config.cacheSwap.swapDirs +
+	     (i = Config.cacheSwap.n_configured); i--; ) {
+	    (--SD)->riddance = 0;
+	    if (!SD->flags.read_only && SD->cur_size >= SD->low_size) {
+		unsigned long tval;
+		tval = (SD->cur_size - SD->low_size) / SD->win_size;
+		if (tval > dirmaxval)
+		    dirmaxval = tval, dirmax = i;
+		SD->riddance = (40 * tval) >> STORE_GRAN_ORDER;
+	        debug(20, 4) ("storeMaintainSwapSpace: Remove %d in swapdir %s\n",
+		 SD->riddance, SD->path);
+	    }
+	}
+	if (dirmax >= 0) {
+	    SD[dirmax].riddance += 10;
+	    debug(20, 3) ("storeMaintainSwapSpace: Aggressive reduction for swapdir %s\n",
+		Config.cacheSwap.swapDirs[dirmax].path);
+	}
+    }
+
+    debug(20, 2) ("storeMaintainSwapSpace: Starting, max_scan=%d\n",
+	max_scan);
+
+#ifdef	HPL_REPL
+
+    for (i = Config.cacheSwap.n_configured; i--; SD++) {
+        heap_p heap = SD->heap;
+        _HEAPKEY age, min_age;
+        StoreEntry *locked_entries;
+	if (!SD->riddance)
+	   continue;
+	min_age = 0; locked_entries = 0;
+    while (heap_nodes(heap) > 0) {
+        age = heap_peepminkey(heap);
+	e = heap_extractmin(heap);
+	e->n.ode.id = -1;				/* no longer in the heap */
+	scanned++;
+	if (storeEntryLocked(e)) {
+	    /*
+	     * Entry is in use ... put it in a linked list to ignore it.
+	     */
+#if 0	/* we're never inserting specials, so don't check for it */
+	    if (!EBIT_TEST(e->Sflag, ENTRY_SPECIAL))
+#else
+	    assert(!EBIT_TEST(e->Sflag, ENTRY_SPECIAL));
+#endif
+	    {
+		/*
+		 * If this was a "SPECIAL" do not add it back into the heap.
+		 * It will always be "SPECIAL" and therefore never removed.
+		 */
+		debug(20, 4) ("storeMaintainSwapSpace: locked url %s\n",
+			      (e->mem_obj && e->mem_obj->url) ? e->mem_obj->url : storeKeyText(e->Skey));
+		e->n.ext = locked_entries;
+		locked_entries = e;
+	    }
+	    locked++;
+	    continue;
+	} else if (storeCheckExpired(e)) {
+	    /*
+	     * Note: This will not check the reference age ifdef HPL_REPL,
+	     * but it does some other useful checks...
+	     */
+	    expired++;
+	    debug(20, 3) ("Released store object age %f size %d refs %d key %s\n",
+			  age, e->Sswap_file_sz, e->Srefcount, storeKeyText(e->Skey));
+	    min_age = age;
+	    storeRelease(e);
+	} else {
+	    /*
+	     * Did not expire the object so we need to add it back into the heap!
+	     */
+	    debug(20, 5) ("storeMaintainSwapSpace: non-expired %s\n", storeKeyText(e->Skey));
+	    e->n.ext = locked_entries;
+	    locked_entries = e;
+	    continue;
+	}
+	if (SD->cur_size <= SD->low_size
+	    || expired >= SD->riddance
+	    || scanned >= max_scan)
+	    break;
+    }
+    /*
+     * Bump the heap age factor.
+     */
+    if (min_age > 0)
+	heap->age = min_age;
+
+    /*
+     * Reinsert all bumped locked entries back into heap...
+     */
+    while (e = locked_entries) {
+      locked_entries = e->n.ext;
+      heap_insert(heap, e);
+    }
+    }
+
+#else	/* HPL_REPL */
+
     for (m = store_list.tail; m; m = prev) {
+	unsigned dirn;
 	prev = m->prev;
 	e = m->data;
-	scanned++;
+	dirn = e->Sswap_file_number >> SWAP_DIR_SHIFT;
+	if (dirn == dirmax) {
+	    if (ext_max_scan-- < 0)
+		break;
+	} else if (++scanned >= max_scan)
+	    goto enough;
 	if (storeEntryLocked(e)) {
 	    /*
 	     * If there is a locked entry at the tail of the LRU list,
@@ -743,19 +985,27 @@
 	    }
 	    locked++;
 	} else if (storeCheckExpired(e)) {
+	    if (dirn == dirmax)
+		min_removehigh--;
 	    expired++;
 	    storeRelease(e);
 	}
 	if (expired >= max_remove)
-	    break;
+	    goto enough;
 	if (scanned >= max_scan)
+enough:	   if (min_removehigh <= 0)
 	    break;
     }
-    debug(20, 3) ("storeMaintainSwapSpace stats:\n");
-    debug(20, 3) ("  %6d objects\n", memInUse(MEM_STOREENTRY));
-    debug(20, 3) ("  %6d were scanned\n", scanned);
-    debug(20, 3) ("  %6d were locked\n", locked);
-    debug(20, 3) ("  %6d were expired\n", expired);
+
+#endif	/* HPL_REPL */
+
+    debug(20, (expired?2:3)) ("storeMaintainSwapSpace: scanned %d/%d removed %d locked %d\n",
+		  scanned, max_scan, expired, locked);
+    debug(20, 4) ("storeMaintainSwapSpace stats:\n");
+    debug(20, 4) ("  %6d objects\n", memInUse(MEM_STOREENTRY));
+    debug(20, 4) ("  %6d were scanned\n", scanned);
+    debug(20, 4) ("  %6d were locked\n", locked);
+    debug(20, 4) ("  %6d were expired\n", expired);
     if (store_swap_size < Config.Swap.maxSize)
 	return;
     if (squid_curtime - last_warn_time < 10)
@@ -771,7 +1021,7 @@
 void
 storeRelease(StoreEntry * e)
 {
-    debug(20, 3) ("storeRelease: Releasing: '%s'\n", storeKeyText(e->key));
+    debug(20, 3) ("storeRelease: Releasing: '%s'\n", storeKeyText(e->Skey));
     /* If, for any reason we can't discard this object because of an
      * outstanding request, mark it for pending release */
     if (storeEntryLocked(e)) {
@@ -787,7 +1037,7 @@
     aioCancel(-1, e);
 #endif
     if (store_rebuilding) {
-	storeSetPrivateKey(e);
+	storeSetPrivateKey(e, 1);
 	if (e->mem_obj) {
 	    storeSetMemStatus(e, NOT_IN_MEMORY);
 	    destroy_MemObject(e);
@@ -801,14 +1051,15 @@
 	return;
     }
     storeLog(STORE_LOG_RELEASE, e);
-    if (e->swap_file_number > -1) {
-	storeUnlinkFileno(e->swap_file_number);
-	storeDirMapBitReset(e->swap_file_number);
+    if (e->Sswap_file_number > -1) {
+	storeUnlinkFileno(e->Sswap_file_number);
+	storeDirMapBitReset(e->Sswap_file_number);
 	if (e->swap_status == SWAPOUT_DONE)
-	    if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
-		storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, -1);
-	if (!EBIT_TEST(e->flags, KEY_PRIVATE))
+	    if (EBIT_TEST(e->Sflag, ENTRY_VALIDATED))
+		storeDirUpdateSwapSize(e->Sswap_file_number, e->Sswap_file_sz, -1);
+	if (!EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	    storeDirSwapLog(e, SWAP_LOG_DEL);
+	set_swap_file_number(e, -1);
     }
     storeSetMemStatus(e, NOT_IN_MEMORY);
     destroy_StoreEntry(e);
@@ -852,8 +1103,8 @@
     /*
      * SPECIAL, PUBLIC entries should be "locked"
      */
-    if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
-	if (!EBIT_TEST(e->flags, KEY_PRIVATE))
+    if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL))
+	if (!EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	    return 1;
     return 0;
 }
@@ -865,7 +1116,7 @@
     const HttpReply *reply;
     assert(e->mem_obj != NULL);
     reply = e->mem_obj->reply;
-    debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->key));
+    debug(20, 3) ("storeEntryValidLength: Checking '%s'\n", storeKeyText(e->Skey));
     debug(20, 5) ("storeEntryValidLength:     object_len = %d\n",
 	objectLen(e));
     debug(20, 5) ("storeEntryValidLength:         hdr_sz = %d\n",
@@ -874,17 +1125,17 @@
 	reply->content_length);
     if (reply->content_length < 0) {
 	debug(20, 5) ("storeEntryValidLength: Unspecified content length: %s\n",
-	    storeKeyText(e->key));
+	    storeKeyText(e->Skey));
 	return 1;
     }
     if (reply->hdr_sz == 0) {
 	debug(20, 5) ("storeEntryValidLength: Zero header size: %s\n",
-	    storeKeyText(e->key));
+	    storeKeyText(e->Skey));
 	return 1;
     }
     if (e->mem_obj->method == METHOD_HEAD) {
 	debug(20, 5) ("storeEntryValidLength: HEAD request: %s\n",
-	    storeKeyText(e->key));
+	    storeKeyText(e->Skey));
 	return 1;
     }
     if (reply->sline.status == HTTP_NOT_MODIFIED)
@@ -894,10 +1145,10 @@
     diff = reply->hdr_sz + reply->content_length - objectLen(e);
     if (diff == 0)
 	return 1;
-    debug(20, 3) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
+    debug(20, 4) ("storeEntryValidLength: %d bytes too %s; '%s'\n",
 	diff < 0 ? -diff : diff,
 	diff < 0 ? "big" : "small",
-	storeKeyText(e->key));
+	storeKeyText(e->Skey));
     return 0;
 }
 
@@ -924,6 +1175,72 @@
     debug(20, 1) ("Max Swap size: %d KB\n", Config.Swap.maxSize);
 }
 
+#ifdef	HPL_REPL
+
+/*
+ * For a description of these cache replacement policies see --
+ http://www.hpl.hp.com/personal/John_Dilley/caching/wcw.html
+ */
+
+
+/*
+ * Key generation function to implement the LFU-DA policy (Least Frequently
+ * Used with Dynamic Aging).  Similar to classical LFU but with aging to
+ * handle turnover of the popular document set.  Maximizes byte hit rate by
+ * keeping more currently popular objects in cache regardless of size.
+ * Achieves lower hit rate than GDS because there are more large objects in
+ * cache (so less room for smaller popular objects).
+ * 
+ * This version implements a tie-breaker based upon recency (e->lastref):
+ * for objects that have the same reference count the most recent object
+ * wins (gets a higher key value).
+ */
+double
+HeapKeyGen_StoreEntry_LFUDA(void * entry, double age)
+{
+  StoreEntry * e = entry;
+  /* dangerous arithmetic after the year 2038 */
+  double tie = (e->Slastref>1)?(1.0/e->Slastref):1;
+  return age + e->Srefcount - tie;
+}
+
+
+/*
+ * Key generation function to implement the GDS-Frequency policy.
+ * Similar to Greedy Dual-Size Hits policy, but adds aging of documents to
+ * prevent pollution.  Maximizes object hit rate by keeping more small,
+ * popular objects in cache.  Achieves lower byte hit rate than LFUDA
+ * because there are fewer large objects in cache.
+ * 
+ * This version implements a tie-breaker based upon recency (e->lastref):
+ * for objects that have the same reference count the most recent object
+ * wins (gets a higher key value).
+ */
+double
+HeapKeyGen_StoreEntry_GDSF(void * entry, double age)
+{
+  StoreEntry * e = entry;
+  double size = e->Sswap_file_sz ? e->Sswap_file_sz : 1.0;
+  /* dangerous arithmetic after the year 2038 */
+  double tie = (e->Slastref>1)?(1.0/e->Slastref):1;
+  return age + ((double)e->Srefcount / size) - tie;
+}
+
+/* 
+ * Key generation function to implement the LRU policy.  Normally one would
+ * not do this with a heap -- use the linked list instead.  For testing and
+ * performance characterization it was useful.  Don't use it unless you are
+ * trying to compare performance among heap-based replacement policies...
+ */
+double
+HeapKeyGen_StoreEntry_LRU(void * entry, double age)
+{
+  StoreEntry * e = entry;
+  return e->Slastref;
+}
+
+#endif	/* HPL_REPL */
+
 void
 storeInit(void)
 {
@@ -941,9 +1258,43 @@
 	    ERROR_BUF_SZ);
 	fatal(tmp_error_buf);
     }
-    storeDirOpenSwapLogs();
+    #ifdef	HPL_REPL
+    /*
+     * Create new heaps with cache replacement policies attached to them.
+     * The cache replacement policy is specified as either GDSF or LFUDA in
+     * the squid.conf configuration file.  Note that the replacement policy
+     * applies only to the disk replacement algorithm.  Memory replacement
+     * always uses GDSF since we want to maximize object hit rate.
+     */
+    inmem_heap = new_heap(1000, HeapKeyGen_StoreEntry_GDSF,
+		    offsetof(MemObject, n.ode));
+
+    store_policy = HeapKeyGen_StoreEntry_GDSF;
+
+    if (Config.replPolicy)
+      if (tolower(Config.replPolicy[0]) == 'g')
+	debug(20, 1) ("Using GDSF disk replacement policy\n");
+      else if (tolower(Config.replPolicy[0]) == 'l') {
+	if (tolower(Config.replPolicy[1]) == 'f') {
+	  debug(20, 1) ("Using LFUDA disk replacement policy\n");
+	  store_policy = HeapKeyGen_StoreEntry_LFUDA;
+	} else if (tolower(Config.replPolicy[1]) == 'r') {
+	  debug(20, 1) ("Using LRU heap disk replacement policy\n");
+	  store_policy = HeapKeyGen_StoreEntry_LRU;
+	}
+      } else
+	  debug(20, 1) ("Unrecognized replacement_policy; using GDSF\n");
+    else
+	debug(20, 1) ("Using default disk replacement policy (GDSF)\n");
+
+    #else	/* HPL_REPL */
+
     store_list.head = store_list.tail = NULL;
     inmem_list.head = inmem_list.tail = NULL;
+
+    #endif	/* HPL_REPL */
+
+    storeDirOpenSwapLogs();
     stackInit(&LateReleaseStack);
     eventAdd("storeLateRelease", storeLateRelease, NULL, 1.0, 1);
     storeRebuildStart();
@@ -982,15 +1333,28 @@
 {
     if (storeEntryLocked(e))
 	return 0;
-    if (EBIT_TEST(e->flags, RELEASE_REQUEST))
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
 	return 1;
-    if (EBIT_TEST(e->flags, ENTRY_NEGCACHED) && squid_curtime >= e->expires)
+    if (EBIT_TEST(e->Sflag, ENTRY_NEGCACHED) && squid_curtime >= e->Sexpires)
 	return 1;
-    if (squid_curtime - e->lastref > storeExpiredReferenceAge())
+#ifdef	HPL_REPL
+    /*
+     * With HPL_REPL we are not using the LRU reference age, the heap
+     * controls the replacement of objects.
+     */
+    return 1;
+#else	/* HPL_REPL */
+    if (squid_curtime - e->Slastref > storeExpiredReferenceAge())
 	return 1;
     return 0;
+#endif	/* HPL_REPL */
 }
 
+#ifdef	HPL_REPL
+/*
+ * The non-LRU cache replacement policies do not use LRU referenceAge
+ */
+#else	/* HPL_REPL */
 /* 
  * storeExpiredReferenceAge
  *
@@ -1018,12 +1382,13 @@
 	age = 31536000;
     return age;
 }
+#endif	/* HPL_REPL */
 
 void
 storeNegativeCache(StoreEntry * e)
 {
-    e->expires = squid_curtime + Config.negativeTtl;
-    EBIT_SET(e->flags, ENTRY_NEGCACHED);
+    e->Sexpires = squid_curtime + Config.negativeTtl;
+    EBIT_SET(e->Sflag, ENTRY_NEGCACHED);
 }
 
 void
@@ -1050,12 +1415,12 @@
 int
 storeEntryValidToSend(StoreEntry * e)
 {
-    if (EBIT_TEST(e->flags, RELEASE_REQUEST))
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
 	return 0;
-    if (EBIT_TEST(e->flags, ENTRY_NEGCACHED))
-	if (e->expires <= squid_curtime)
+    if (EBIT_TEST(e->Sflag, ENTRY_NEGCACHED))
+	if (e->Sexpires <= squid_curtime)
 	    return 0;
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED))
+    if (EBIT_TEST(e->Sflag, ENTRY_ABORTED))
 	return 0;
     return 1;
 }
@@ -1068,9 +1433,9 @@
     served_date = reply->date;
     if (served_date < 0)
 	served_date = squid_curtime;
-    entry->expires = reply->expires;
-    entry->lastmod = reply->last_modified;
-    entry->timestamp = served_date;
+    entry->Sexpires = reply->expires;
+    entry->Slastmod = reply->last_modified;
+    entry->Stimestamp = served_date;
 }
 
 void
@@ -1125,17 +1490,16 @@
 void
 storeEntryDump(StoreEntry * e, int l)
 {
-    debug(20, l) ("StoreEntry->key: %s\n", storeKeyText(e->key));
-    debug(20, l) ("StoreEntry->next: %p\n", e->next);
+    debug(20, l) ("StoreEntry->key: %s\n", storeKeyText(e->Skey));
     debug(20, l) ("StoreEntry->mem_obj: %p\n", e->mem_obj);
-    debug(20, l) ("StoreEntry->timestamp: %d\n", (int) e->timestamp);
-    debug(20, l) ("StoreEntry->lastref: %d\n", (int) e->lastref);
-    debug(20, l) ("StoreEntry->expires: %d\n", (int) e->expires);
-    debug(20, l) ("StoreEntry->lastmod: %d\n", (int) e->lastmod);
-    debug(20, l) ("StoreEntry->swap_file_sz: %d\n", (int) e->swap_file_sz);
-    debug(20, l) ("StoreEntry->refcount: %d\n", e->refcount);
-    debug(20, l) ("StoreEntry->flags: %s\n", storeEntryFlags(e));
-    debug(20, l) ("StoreEntry->swap_file_number: %d\n", (int) e->swap_file_number);
+    debug(20, l) ("StoreEntry->Stimestamp: %d\n", (int) e->Stimestamp);
+    debug(20, l) ("StoreEntry->Slastref: %d\n", (int) e->Slastref);
+    debug(20, l) ("StoreEntry->Sexpires: %d\n", (int) e->Sexpires);
+    debug(20, l) ("StoreEntry->Slastmod: %d\n", (int) e->Slastmod);
+    debug(20, l) ("StoreEntry->Sswap_file_sz: %d\n", (int) e->Sswap_file_sz);
+    debug(20, l) ("StoreEntry->Srefcount: %d\n", e->Srefcount);
+    debug(20, l) ("StoreEntry->flag: %X %s\n", e->Sflag, storeEntryFlags(e));
+    debug(20, l) ("StoreEntry->Sswap_file_number: %d\n", (int) e->Sswap_file_number);
     debug(20, l) ("StoreEntry->lock_count: %d\n", (int) e->lock_count);
     debug(20, l) ("StoreEntry->mem_status: %d\n", (int) e->mem_status);
     debug(20, l) ("StoreEntry->ping_status: %d\n", (int) e->ping_status);
@@ -1153,10 +1517,33 @@
     assert(mem != NULL);
     if (new_status == IN_MEMORY) {
 	assert(mem->inmem_lo == 0);
+	#ifdef	HPL_REPL
+	if (mem->n.ode.id < 0) {
+	  if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL)) {
+	    debug(20, 4) ("storeSetMemStatus: not inserting special %s\n", mem->url);
+	  } else {
+	    heap_insert(inmem_heap, mem);
+	    debug(20, 4) ("storeSetMemStatus: inserted mem node %d\n", mem->n.ode.id);
+	  }
+	}
+	#else	/* HPL_REPL */
 	dlinkAdd(e, &mem->lru, &inmem_list);
+	#endif	/* HPL_REPL */
 	hot_obj_count++;
     } else {
+      #ifdef	HPL_REPL
+      /*
+       * It's being removed from the memory heap; is it already gone?
+       */
+      if (mem->n.ode.id >= 0) {
+	heap_delete(inmem_heap, &mem->n.ode);
+	debug(20, 4) ("storeSetMemStatus: deleted mem node %d\n",
+		      mem->n.ode.id);
+	mem->n.ode.id = -1;
+      }
+      #else	/* HPL_REPL */
 	dlinkDelete(&mem->lru, &inmem_list);
+      #endif	/* HPL_REPL */
 	hot_obj_count--;
     }
     e->mem_status = new_status;
@@ -1179,20 +1566,23 @@
     if (e->mem_obj)
 	return;
     e->mem_obj = new_MemObject(url, log_url);
+#if HPL_REPL
+    e->mem_obj->entry = e;
+#endif
 }
 
 /* this just sets DELAY_SENDING */
 void
 storeBuffer(StoreEntry * e)
 {
-    EBIT_SET(e->flags, DELAY_SENDING);
+    EBIT_SET(e->Sflag, DELAY_SENDING);
 }
 
 /* this just clears DELAY_SENDING and Invokes the handlers */
 void
 storeBufferFlush(StoreEntry * e)
 {
-    EBIT_CLR(e->flags, DELAY_SENDING);
+    EBIT_CLR(e->Sflag, DELAY_SENDING);
     InvokeHandlers(e);
     storeCheckSwapOut(e);
 }
@@ -1200,7 +1590,7 @@
 void
 storeUnlinkFileno(int fileno)
 {
-    debug(20, 5) ("storeUnlinkFileno: %08X\n", fileno);
+    debug(20, 6) ("storeUnlinkFileno: %08X\n", fileno);
 #if USE_ASYNC_IO
     safeunlink(storeSwapFullPath(fileno, NULL), 1);
 #else
@@ -1237,7 +1627,7 @@
 storeEntryReset(StoreEntry * e)
 {
     MemObject *mem = e->mem_obj;
-    debug(20, 3) ("storeEntryReset: %s\n", storeUrl(e));
+    debug(20, 4) ("storeEntryReset: %s\n", storeUrl(e));
     assert(mem->swapout.fd == -1);
     stmemFree(&mem->data_hdr);
     mem->inmem_hi = mem->inmem_lo = 0;
Index: squid/src/store_client.c
diff -u squid/src/store_client.c:1.1.1.2 squid/src/store_client.c:1.1.1.2.10.1
--- squid/src/store_client.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_client.c	Fri Nov 10 10:44:52 2000
@@ -81,7 +81,7 @@
     MemObject *mem = e->mem_obj;
     if (mem->inmem_lo)
 	return STORE_DISK_CLIENT;
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(e->Sflag, ENTRY_ABORTED)) {
 	/* I don't think we should be adding clients to aborted entries */
 	debug(20, 1) ("storeClientType: adding to ENTRY_ABORTED entry\n");
 	return STORE_MEM_CLIENT;
@@ -129,7 +129,7 @@
     if (sc->type == STORE_DISK_CLIENT)
 	/* assert we'll be able to get the data we want */
 	/* maybe we should open swapin_fd here */
-	assert(e->swap_file_number > -1 || storeSwapOutAble(e));
+	assert(e->Sswap_file_number > -1 || storeSwapOutAble(e));
     for (T = &mem->clients; *T; T = &(*T)->next);
     *T = sc;
 #if DELAY_POOLS
@@ -141,7 +141,7 @@
 storeClientCopyEvent(void *data)
 {
     store_client *sc = data;
-    debug(20, 3) ("storeClientCopyEvent: Running\n");
+    debug(20, 4) ("storeClientCopyEvent: Running\n");
     sc->flags.copy_event_pending = 0;
     if (!sc->callback)
 	return;
@@ -159,9 +159,9 @@
     void *data)
 {
     store_client *sc;
-    assert(!EBIT_TEST(e->flags, ENTRY_ABORTED));
+    assert(!EBIT_TEST(e->Sflag, ENTRY_ABORTED));
     debug(20, 3) ("storeClientCopy: %s, seen %d, want %d, size %d, cb %p, cbdata %p\n",
-	storeKeyText(e->key),
+	storeKeyText(e->Skey),
 	(int) seen_offset,
 	(int) copy_offset,
 	(int) size,
@@ -209,7 +209,7 @@
     size_t sz;
     if (sc->flags.copy_event_pending)
 	return;
-    if (EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
+    if (EBIT_TEST(e->Sflag, ENTRY_FWD_HDR_WAIT)) {
 	debug(20, 5) ("storeClientCopy2: returning because ENTRY_FWD_HDR_WAIT set\n");
 	return;
     }
@@ -221,7 +221,7 @@
     }
     cbdataLock(sc);		/* ick, prevent sc from getting freed */
     sc->flags.store_copying = 1;
-    debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->key));
+    debug(20, 3) ("storeClientCopy2: %s\n", storeKeyText(e->Skey));
     assert(callback != NULL);
     /*
      * We used to check for ENTRY_ABORTED here.  But there were some
@@ -245,10 +245,10 @@
 	callback(sc->callback_data, sc->copy_buf, 0);
     } else if (e->store_status == STORE_PENDING && sc->seen_offset >= mem->inmem_hi) {
 	/* client has already seen this, wait for more */
-	debug(20, 3) ("storeClientCopy2: Waiting for more\n");
+	debug(20, 4) ("storeClientCopy2: Waiting for more\n");
     } else if (sc->copy_offset >= mem->inmem_lo && sc->copy_offset < mem->inmem_hi) {
 	/* What the client wants is in memory */
-	debug(20, 3) ("storeClientCopy2: Copying from memory\n");
+	debug(20, 4) ("storeClientCopy2: Copying from memory\n");
 	sz = stmemCopy(&mem->data_hdr, sc->copy_offset, sc->copy_buf, sc->copy_size);
 #if USE_ASYNC_IO
 	if (sc->flags.disk_io_pending) {
@@ -262,7 +262,7 @@
 	sc->callback = NULL;
 	callback(sc->callback_data, sc->copy_buf, sz);
     } else if (sc->swapin_fd < 0) {
-	debug(20, 3) ("storeClientCopy2: Need to open swap in file\n");
+	debug(20, 4) ("storeClientCopy2: Need to open swap in file\n");
 	assert(sc->type == STORE_DISK_CLIENT);
 	/* gotta open the swapin file */
 	if (storeTooManyDiskFilesOpen()) {
@@ -276,7 +276,7 @@
 	    debug(20, 2) ("storeClientCopy2: Averted multiple fd operation\n");
 	}
     } else {
-	debug(20, 3) ("storeClientCopy: reading from disk FD %d\n",
+	debug(20, 4) ("storeClientCopy: reading from disk FD %d\n",
 	    sc->swapin_fd);
 	assert(sc->type == STORE_DISK_CLIENT);
 	if (!sc->flags.disk_io_pending) {
@@ -295,7 +295,7 @@
     store_client *sc = data;
     STCB *callback = sc->callback;
     if (fd < 0) {
-	debug(20, 3) ("storeClientFileOpened: failed\n");
+	debug(20, 4) ("storeClientFileOpened: failed\n");
 	sc->flags.disk_io_pending = 0;
 	sc->callback = NULL;
 	callback(sc->callback_data, sc->copy_buf, -1);
@@ -344,7 +344,7 @@
     assert(sc->flags.disk_io_pending);
     sc->flags.disk_io_pending = 0;
     assert(sc->callback != NULL);
-    debug(20, 3) ("storeClientReadBody: FD %d, len %d\n", fd, len);
+    debug(20, 4) ("storeClientReadBody: FD %d, len %d\n", fd, len);
     if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
 	httpReplyParse(mem->reply, sc->copy_buf);
     sc->callback = NULL;
@@ -365,9 +365,9 @@
     assert(sc->flags.disk_io_pending);
     sc->flags.disk_io_pending = 0;
     assert(sc->callback != NULL);
-    debug(20, 3) ("storeClientReadHeader: FD %d, len %d\n", fd, len);
+    debug(20, 4) ("storeClientReadHeader: FD %d, len %d\n", fd, len);
     if (len < 0) {
-	debug(20, 3) ("storeClientReadHeader: FD %d: %s\n", fd, xstrerror());
+	debug(20, 4) ("storeClientReadHeader: FD %d: %s\n", fd, xstrerror());
 	sc->callback = NULL;
 	callback(sc->callback_data, sc->copy_buf, len);
 	return;
@@ -380,12 +380,44 @@
 	return;
     }
     /*
-     * XXX Here we should check the meta data and make sure we got
+     * Check the meta data and make sure we got
      * the right object.
      */
+    {
+	tlv *tlv_cur;
+	char *skey = 0;
+	for (tlv_cur = tlv_list; tlv_cur; tlv_cur = tlv_cur->next)
+	    switch (tlv_cur->type)
+	    {
+		case STORE_META_KEY:
+		    if (memcmp(e->Skey, skey = (char*)tlv_cur->value, MD5_DIGEST_CHARS))
+		    {
+			debug(20, 0) ("storeClientReadHeader: MD5 mismatch %x %s\n",
+			    e->Sswap_file_number, storeUrl(e));
+badstore:		debug(20, 0) ("storeClientReadHeader: MD5 match? %x %s %s\n",
+			    e->Sswap_file_number,
+			    skey ? storeKeyText(skey) : "-", storeKeyText(e->Skey));
+			storeSwapTLVFree(tlv_list);
+			sc->callback = NULL;
+			callback(sc->callback_data, sc->copy_buf, -1);
+			return;
+		    }
+#if 0				/* optimisation possible */
+		    tlv_cur = 0;
+#endif
+		    break;
+		case STORE_META_URL:
+		    if (memcmp((char*)tlv_cur->value, storeUrl(e), tlv_cur->length))
+		    {
+			debug(20, 0) ("storeClientReadHeader: URL mismatch %x %s %s\n",
+			    e->Sswap_file_number, (char*)tlv_cur->value, storeUrl(e));
+			goto badstore;
+		    }
+	    }
+    }
     storeSwapTLVFree(tlv_list);
     mem->swap_hdr_sz = swap_hdr_sz;
-    mem->object_sz = e->swap_file_sz - swap_hdr_sz;
+    mem->object_sz = e->Sswap_file_sz - swap_hdr_sz;
     /*
      * If our last read got some data the client wants, then give
      * it to them, otherwise schedule another read.
@@ -396,7 +428,7 @@
 	 * we have (part of) what they want
 	 */
 	copy_sz = XMIN(sc->copy_size, body_sz);
-	debug(20, 3) ("storeClientReadHeader: copying %d bytes of body\n",
+	debug(20, 4) ("storeClientReadHeader: copying %d bytes of body\n",
 	    copy_sz);
 	xmemmove(sc->copy_buf, sc->copy_buf + swap_hdr_sz, copy_sz);
 	if (sc->copy_offset == 0 && len > 0 && mem->reply->sline.status == 0)
@@ -433,7 +465,7 @@
     STCB *callback;
     if (mem == NULL)
 	return 0;
-    debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->key));
+    debug(20, 3) ("storeUnregister: called for '%s'\n", storeKeyText(e->Skey));
     for (S = &mem->clients; (sc = *S) != NULL; S = &(*S)->next) {
 	if (sc->callback_data == data)
 	    break;
@@ -462,7 +494,7 @@
 #endif
     if ((callback = sc->callback) != NULL) {
 	/* callback with ssize = -1 to indicate unexpected termination */
-	debug(20, 3) ("storeUnregister: store_client for %s has a callback\n",
+	debug(20, 4) ("storeUnregister: store_client for %s has a callback\n",
 	    mem->url);
 	sc->callback = NULL;
 	callback(sc->callback_data, sc->copy_buf, -1);
@@ -505,7 +537,7 @@
     store_client *sc;
     store_client *nx = NULL;
     assert(mem->clients != NULL || mem->nclients == 0);
-    debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->key));
+    debug(20, 3) ("InvokeHandlers: %s\n", storeKeyText(e->Skey));
     /* walk the entire list looking for valid callbacks */
     for (sc = mem->clients; sc; sc = nx) {
 	nx = sc->next;
@@ -523,7 +555,7 @@
 {
     MemObject *mem = e->mem_obj;
     int npend = NULL == mem ? 0 : mem->nclients;
-    debug(20, 3) ("storePendingNClients: returning %d\n", npend);
+    debug(20, 4) ("storePendingNClients: returning %d\n", npend);
     return npend;
 }
 
@@ -541,7 +573,7 @@
 	debug(20, 3) ("CheckQuickAbort2: YES !mem->request->flags.cachable\n");
 	return 1;
     }
-    if (EBIT_TEST(entry->flags, KEY_PRIVATE)) {
+    if (EBIT_TEST(entry->Sflag, KEY_PRIVATE)) {
 	debug(20, 3) ("CheckQuickAbort2: YES KEY_PRIVATE\n");
 	return 1;
     }
@@ -585,7 +617,7 @@
 	return;
     if (entry->store_status != STORE_PENDING)
 	return;
-    if (EBIT_TEST(entry->flags, ENTRY_SPECIAL))
+    if (EBIT_TEST(entry->Sflag, ENTRY_SPECIAL))
 	return;
     if (CheckQuickAbort2(entry) == 0)
 	return;
Index: squid/src/store_digest.c
diff -u squid/src/store_digest.c:1.1.1.2 squid/src/store_digest.c:1.1.1.2.12.1
--- squid/src/store_digest.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_digest.c	Fri Nov 10 10:44:53 2000
@@ -138,17 +138,17 @@
 #if USE_CACHE_DIGESTS
     assert(entry && store_digest);
     debug(71, 6) ("storeDigestDel: checking entry, key: %s\n",
-	storeKeyText(entry->key));
-    if (!EBIT_TEST(entry->flags, KEY_PRIVATE)) {
-	if (!cacheDigestTest(store_digest, entry->key)) {
+	storeKeyText(entry->Skey));
+    if (!EBIT_TEST(entry->Sflag, KEY_PRIVATE)) {
+	if (!cacheDigestTest(store_digest, entry->Skey)) {
 	    sd_stats.del_lost_count++;
 	    debug(71, 6) ("storeDigestDel: lost entry, key: %s url: %s\n",
-		storeKeyText(entry->key), storeUrl(entry));
+		storeKeyText(entry->Skey), storeUrl(entry));
 	} else {
 	    sd_stats.del_count++;
-	    cacheDigestDel(store_digest, entry->key);
+	    cacheDigestDel(store_digest, entry->Skey);
 	    debug(71, 6) ("storeDigestDel: deled entry, key: %s\n",
-		storeKeyText(entry->key));
+		storeKeyText(entry->Skey));
 	}
     }
 #endif
@@ -187,31 +187,31 @@
     /* add some stats! XXX */
 
     debug(71, 6) ("storeDigestAddable: checking entry, key: %s\n",
-	storeKeyText(e->key));
+	storeKeyText(e->Skey));
 
     /* check various entry flags (mimics storeCheckCachable XXX) */
-    if (!EBIT_TEST(e->flags, ENTRY_CACHABLE)) {
+    if (!EBIT_TEST(e->Sflag, ENTRY_CACHABLE)) {
 	debug(71, 6) ("storeDigestAddable: NO: not cachable\n");
 	return 0;
     }
-    if (EBIT_TEST(e->flags, KEY_PRIVATE)) {
+    if (EBIT_TEST(e->Sflag, KEY_PRIVATE)) {
 	debug(71, 6) ("storeDigestAddable: NO: private key\n");
 	return 0;
     }
-    if (EBIT_TEST(e->flags, ENTRY_NEGCACHED)) {
+    if (EBIT_TEST(e->Sflag, ENTRY_NEGCACHED)) {
 	debug(71, 6) ("storeDigestAddable: NO: negative cached\n");
 	return 0;
     }
-    if (EBIT_TEST(e->flags, RELEASE_REQUEST)) {
+    if (EBIT_TEST(e->Sflag, RELEASE_REQUEST)) {
 	debug(71, 6) ("storeDigestAddable: NO: release requested\n");
 	return 0;
     }
-    if (e->store_status == STORE_OK && EBIT_TEST(e->flags, ENTRY_BAD_LENGTH)) {
+    if (e->store_status == STORE_OK && EBIT_TEST(e->Sflag, ENTRY_BAD_LENGTH)) {
 	debug(71, 6) ("storeDigestAddable: NO: wrong content-length\n");
 	return 0;
     }
     /* do not digest huge objects */
-    if (e->swap_file_sz > Config.Store.maxObjectSize) {
+    if (e->Sswap_file_sz > Config.Store.maxObjectSize) {
 	debug(71, 6) ("storeDigestAddable: NO: too big\n");
 	return 0;
     }
@@ -235,14 +235,14 @@
 
     if (storeDigestAddable(entry)) {
 	sd_stats.add_count++;
-	if (cacheDigestTest(store_digest, entry->key))
+	if (cacheDigestTest(store_digest, entry->Skey))
 	    sd_stats.add_coll_count++;
-	cacheDigestAdd(store_digest, entry->key);
+	cacheDigestAdd(store_digest, entry->Skey);
 	debug(71, 6) ("storeDigestAdd: added entry, key: %s\n",
-	    storeKeyText(entry->key));
+	    storeKeyText(entry->Skey));
     } else {
 	sd_stats.rej_count++;
-	if (cacheDigestTest(store_digest, entry->key))
+	if (cacheDigestTest(store_digest, entry->Skey))
 	    sd_stats.rej_coll_count++;
     }
 }
@@ -341,7 +341,7 @@
     sd_state.rewrite_lock = e = storeCreateEntry(url, url, flags, METHOD_GET);
     assert(sd_state.rewrite_lock);
     cbdataAdd(sd_state.rewrite_lock, NULL, 0);
-    debug(71, 3) ("storeDigestRewrite: url: %s key: %s\n", url, storeKeyText(e->key));
+    debug(71, 3) ("storeDigestRewrite: url: %s key: %s\n", url, storeKeyText(e->Skey));
     e->mem_obj->request = requestLink(urlParse(METHOD_GET, url));
     /* wait for rebuild (if any) to finish */
     if (sd_state.rebuild_lock) {
@@ -359,7 +359,7 @@
     assert(sd_state.rewrite_lock);
     assert(!sd_state.rebuild_lock);
     sd_state.rewrite_offset = 0;
-    EBIT_SET(e->flags, ENTRY_SPECIAL);
+    EBIT_SET(e->Sflag, ENTRY_SPECIAL);
     /* setting public key will purge old digest entry if any */
     storeSetPublicKey(e);
     /* fake reply */
@@ -384,7 +384,7 @@
     storeComplete(e);
     storeTimestampsSet(e);
     debug(71, 2) ("storeDigestRewriteFinish: digest expires at %d (%+d)\n",
-	e->expires, e->expires - squid_curtime);
+	e->Sexpires, e->Sexpires - squid_curtime);
     /* is this the write order? @?@ */
     requestUnlink(e->mem_obj->request);
     e->mem_obj->request = NULL;
Index: squid/src/store_dir.c
diff -u squid/src/store_dir.c:1.1.1.2 squid/src/store_dir.c:1.1.1.2.10.1
--- squid/src/store_dir.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_dir.c	Fri Nov 10 10:44:53 2000
@@ -39,9 +39,10 @@
 #include <sys/statvfs.h>
 #endif
 #endif
+#ifdef MMAPSTORE
+#include <sys/mman.h>
+#endif
 
-#define SWAP_DIR_SHIFT 24
-#define SWAP_FILE_MASK 0x00FFFFFF
 #define DefaultLevelOneDirs     16
 #define DefaultLevelTwoDirs     256
 
@@ -232,16 +233,20 @@
 static int
 storeDirSelectSwapDir(void)
 {
-    double least_used = 1.0;
-    double high = (double) Config.Swap.highWaterMark / 100.0;
-    double u;
-    int dirn;
     int i, j;
-    SwapDir *SD;
-    static int nleast = 0;
-    static int nconf = 0;
+    static unsigned nleast = 0;
+    static unsigned returnlast = 0;
+    static unsigned nconf = 0;
+    static unsigned lastdirn;
+    static unsigned relstoremax;
     static int *dirq = NULL;
-    static double *diru = NULL;
+    static unsigned long *diru = NULL;
+    unsigned long least_used;
+    /*
+     * Scan for a non-negative dirn in the dirq array and return that one
+     */
+    if (returnlast)
+	return dirq[--returnlast];
     /*
      * Handle simplest case of a single swap directory immediately
      */
@@ -256,45 +261,28 @@
 	safe_free(dirq);
 	dirq = (int *) xmalloc(sizeof(int) * nleast);
 	safe_free(diru);
-	diru = (double *) xmalloc(sizeof(double) * nconf);
+	diru = xmalloc(sizeof*diru * nconf);
 	for (j = 0; j < nleast; j++)
 	    dirq[j] = -1;
+	relstoremax = ((unsigned)Config.Swap.highWaterMark*2 + 1) *
+	 STORE_GRAN_MAX / 200 + 1;
     }
     /*
-     * Scan for a non-negative dirn in the dirq array and return that one
-     */
-    dirn = -1;
-    for (j = 0; j < nleast; j++) {
-	dirn = dirq[j];
-	if (dirn < 0)
-	    continue;
-	dirq[j] = -1;
-	break;
-    }
-    /*
-     * If we found a valid dirn return it
-     */
-    if (dirn >= 0)
-	return dirn;
-    /*
      * Now for the real guts of the algorithm - building the dirq array
      */
     for (i = 0; i < nconf; i++) {
-	diru[i] = 1.1;
-	SD = &Config.cacheSwap.swapDirs[i];
+        SwapDir *SD = &Config.cacheSwap.swapDirs[i];
+	diru[i] = STORE_GRAN_MAX+STORE_GRAN_MAX/2;
 	SD->flags.selected = 0;
 	if (SD->flags.read_only)
 	    continue;
-	u = (double) SD->cur_size / SD->max_size;
-	if (u > high)
-	    continue;
-	diru[i] = u;
+	diru[i] = SD->cur_size/
+	 (((unsigned long)SD->max_size+STORE_GRAN_MAX-1)>>STORE_GRAN_ORDER);
     }
     for (j = 0; j < nleast; j++) {
-	dirq[j] = -1;
-	least_used = 1.0;
-	dirn = -1;
-	for (i = 0; i < nconf; i++) {
+        int dirn = -1;
+	least_used = relstoremax;
+	for (i = lastdirn; (i = (i+1)%nconf) != lastdirn; ) {
 	    if (diru[i] < least_used) {
 		least_used = diru[i];
 		dirn = i;
@@ -302,19 +290,25 @@
 	}
 	if (dirn < 0)
 	    break;
-	dirq[j] = dirn;
-	diru[dirn] = 1.1;
+	dirq[j] = lastdirn = dirn;
+	diru[dirn] = STORE_GRAN_MAX+2;
 	/* set selected flag for debugging/cachemgr only */
 	Config.cacheSwap.swapDirs[dirn].flags.selected = 1;
     }
+    if (!j)
+	for (i = nconf; i--;)
+	    if (diru[i] == least_used) {
+		dirq[j] = i;
+		Config.cacheSwap.swapDirs[i].flags.selected = 1;
+		if (++j == nleast)
+		    break;
+    }
     /*
      * Setup default return of 0 if no least found
      */
-    if (dirq[0] < 0)
-	dirq[0] = 0;
-    dirn = dirq[0];
-    dirq[0] = -1;
-    return dirn;
+    if (!j)
+	return 0;
+    return dirq[returnlast = j-1];
 }
 
 int
@@ -386,6 +380,185 @@
     return (dirn << SWAP_DIR_SHIFT) | (fn & SWAP_FILE_MASK);
 }
 
+static struct mmapinfo *allmi;
+
+static void
+mapfdswap(SwapDir *sd)
+{
+#ifdef MMAPSTORE
+    struct stat stbuf;
+    struct mmapinfo *mi = sd->mi;
+    if (!mi) {
+	const char *path = sd->path;
+	for (mi = allmi; ; mi = mi->next) {
+	    if (!mi) {
+		mi = xmalloc(sizeof *mi);
+		mi->next = allmi;
+		allmi = mi;
+		mi->path = xstrdup(path);
+		mi->mmapbase = mi->mmapfreelist = 0;
+		break;
+	    }
+	    if (!strcmp(mi->path, path))
+		break;
+	}
+	sd->mi = mi;
+    }
+    if(mi->mmapbase)
+	munmap(mi->mmapbase, (char*)mi->mmapmax-(char*)mi->mmapbase);
+    if(!fstat(sd->swaplog_fd,&stbuf)) {
+	storeSwapLogData*oldbase = mi->mmapbase, *oldend = mi->mmapend;
+	size_t max=(((size_t)stbuf.st_size/16*17+32768)/sizeof*mi->mmapbase+1)*
+	    sizeof*mi->mmapbase;
+	if(MAP_FAILED != (mi->mmapbase = mmap(0, max, PROT_READ|PROT_WRITE,
+	    MAP_SHARED, sd->swaplog_fd, 0))) {
+	    mi->mmapend = mi->mmapbase + stbuf.st_size/sizeof*mi->mmapbase;
+	    mi->mmapmax = (storeSwapLogData*)((char*)mi->mmapbase + max);
+	    if (oldbase) {
+	        ptrdiff_t fix = (char*)mi->mmapbase-(char*)oldbase;
+#ifdef	HPL_REPL
+		int node;
+	        for (node=0; node < heap_nodes(sd->heap); node++) {
+	            StoreEntry *e = (StoreEntry*)heap_peep(sd->heap, node);
+#else	/* HPL_REPL */
+		dlink_node *m;
+	        for (m = store_list.tail; m; m = m->prev) {
+	            StoreEntry *e = m->data;
+	            if (oldbase <= e->s && e->s <oldend)
+#endif	/* HPL_REPL */
+		        e->s = (storeSwapLogData*)((char*)e->s+fix);
+	        }
+		if(mi->mmapfreelist)
+		    mi->mmapfreelist =
+			(storeSwapLogData*)((char*)mi->mmapfreelist+fix);
+	    }
+	    return;
+	}
+    } else
+	sd->mi = 0;
+    fatal_dump("mapfdswap: Couldn't mmap() the store swap logfiles\n");
+    return;
+#endif
+}
+
+void storeSwapToFreeList(SwapDir*sd, storeSwapLogData *s)
+{
+    struct mmapinfo *mi = sd->mi;
+    s->swap_file_number = -1;
+    if (mi->mmapend != s+1) {
+	s->swap_file_sz = mi->mmapfreelist ? mi->mmapfreelist - s : 0 ;
+	mi->mmapfreelist = s;
+    } else {
+	int ret;
+	ret = ftruncate (sd->swaplog_fd, (char*)s - (char*)mi->mmapbase);
+	lseek (sd->swaplog_fd, 0L, SEEK_END);
+	assert(!ret);
+	mi->mmapend--;
+    }
+}
+
+storeSwapLogData*storeSwapAppendList(SwapDir*sd, storeSwapLogData*s)
+{
+    struct mmapinfo *mi = sd->mi;
+    {
+        storeSwapLogData*ns;
+        if (ns = mi->mmapfreelist) {
+	    mi->mmapfreelist = ns->swap_file_sz ?
+		ns + (int)ns->swap_file_sz : 0;
+	    *ns = *s;
+	    return ns;
+        }
+    }
+    if(mi->mmapend == mi->mmapmax)
+	mapfdswap(sd);
+    {
+	int ret, todo=sizeof*s;
+	char*p = (char*)s;
+	do
+	    ret = write(sd->swaplog_fd, p, todo);
+	while (ret < 0 && (errno == EAGAIN || errno == EINTR) ||
+	    (p += ret, todo -= ret));
+	if ( ret <= 0 )
+            debug(20, 0) ("storeSwapAppendList: %d %d\n", ret, errno);
+	assert(ret > 0);
+    }
+    return mi->mmapend++;
+}
+
+SwapDir*
+getswapdir(int swapfilenumber)
+{
+    unsigned dirn = (swapfilenumber >> SWAP_DIR_SHIFT);
+    assert(dirn < Config.cacheSwap.n_configured);
+    return Config.cacheSwap.swapDirs + dirn;
+}
+
+void
+destroy_storeSwapLogData(storeSwapLogData*s)
+{
+#ifdef MMAPSTORE
+    int swf = s->swap_file_number;
+    if (swf < 0)
+#endif
+	memFree(s, MEM_STORESWAPLOGDATA);
+#ifdef MMAPSTORE
+    else
+	storeSwapToFreeList(getswapdir(swf), s);
+#endif
+}
+
+void
+set_swap_file_number(StoreEntry*e, int swf)
+{
+#ifdef MMAPSTORE
+    storeSwapLogData*s = e->s;
+    int oswf = s->swap_file_number;
+    if (oswf == swf)
+	return;
+    if (shutting_down) {
+	if (oswf >= 0) {
+            storeSwapLogData *ns = memAllocate(MEM_STORESWAPLOGDATA);
+	    *ns = *s;
+	    e->s = ns;
+	}
+        s->swap_file_number = swf;
+	return;
+    }
+    s->swap_file_number = swf;
+    if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL))
+	return;
+    if (oswf < 0) {
+        SwapDir*sd = getswapdir(swf);
+	e->s = storeSwapAppendList(sd, s);
+	memFree(s, MEM_STORESWAPLOGDATA);
+#if HPL_REPL
+	assert(e->n.ode.id < 0);
+	heap_insert(sd->heap, e);
+#endif
+    } else {
+        SwapDir*sd,*osd = getswapdir(oswf);
+        if (swf < 0) {
+            storeSwapLogData *ns = memAllocate(MEM_STORESWAPLOGDATA);
+	    *ns = *s;
+	    e->s = ns;
+	    goto takeout;
+        }
+	sd = getswapdir(swf);
+	if (sd != osd) {
+	    e->s = storeSwapAppendList(sd, s);
+takeout:
+#if HPL_REPL
+	    if (e->n.ode.id >= 0) {
+		heap_delete(osd->heap, &e->n.ode);
+		e->n.ode.id = -1;
+	    }
+#endif
+	    storeSwapToFreeList(osd, s);
+	}
+    }
+#endif
+}
+
 /*
  * An entry written to the swap log MUST have the following
  * properties.
@@ -396,42 +569,48 @@
  *   2.  It MUST have a valid (> -1) swap_file_number.
  */
 void
-storeDirSwapLog(const StoreEntry * e, int op)
+storeDirSwapLog(StoreEntry * e, int op)
 {
+#ifdef MMAPSTORE
+    return;
+#else
     storeSwapLogData *s;
     int dirn;
-    dirn = e->swap_file_number >> SWAP_DIR_SHIFT;
+    SwapDir*sd;
+    dirn = e->Sswap_file_number >> SWAP_DIR_SHIFT;
     assert(dirn < Config.cacheSwap.n_configured);
-    assert(!EBIT_TEST(e->flags, KEY_PRIVATE));
-    assert(e->swap_file_number >= 0);
+    assert(!EBIT_TEST(e->Sflag, KEY_PRIVATE));
+    assert(e->Sswap_file_number >= 0);
+    sd = &Config.cacheSwap.swapDirs[dirn];
     /*
      * icons and such; don't write them to the swap log
      */
-    if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
+    if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL))
 	return;
     assert(op > SWAP_LOG_NOP && op < SWAP_LOG_MAX);
     debug(20, 3) ("storeDirSwapLog: %s %s %08X\n",
 	swap_log_op_str[op],
-	storeKeyText(e->key),
-	e->swap_file_number);
+	storeKeyText(e->Skey),
+	e->Sswap_file_number);
     s = xcalloc(1, sizeof(storeSwapLogData));
     s->op = (char) op;
-    s->swap_file_number = e->swap_file_number;
-    s->timestamp = e->timestamp;
-    s->lastref = e->lastref;
-    s->expires = e->expires;
-    s->lastmod = e->lastmod;
-    s->swap_file_sz = e->swap_file_sz;
-    s->refcount = e->refcount;
-    s->flags = e->flags;
+    s->timestamp = e->Stimestamp;
+    s->lastref = e->Slastref;
+    s->expires = e->Sexpires;
+    s->lastmod = e->Slastmod;
+    s->swap_file_sz = e->Sswap_file_sz;
+    s->refcount = e->Srefcount;
+    s->flags = e->Sflag;
     xmemcpy(s->key, e->key, MD5_DIGEST_CHARS);
-    file_write(Config.cacheSwap.swapDirs[dirn].swaplog_fd,
+    s->swap_file_number = e->Sswap_file_number;
+    file_write(sd->swaplog_fd,
 	-1,
 	s,
 	sizeof(storeSwapLogData),
 	NULL,
 	NULL,
 	xfree);
+#endif
 }
 
 char *
@@ -463,14 +642,88 @@
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
 	SD = &Config.cacheSwap.swapDirs[i];
 	path = storeDirSwapLogFile(i, NULL);
-	fd = file_open(path, O_WRONLY | O_CREAT, NULL, NULL, NULL);
+	fd = file_open(path, O_RDWR | O_CREAT, NULL, NULL, NULL);
 	if (fd < 0) {
 	    debug(50, 1) ("%s: %s\n", path, xstrerror());
 	    fatal("storeDirOpenSwapLogs: Failed to open swap log.");
+#ifdef MMAPSTORE
+	    SD->mi = 0;
+#endif
 	}
 	debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", i, fd);
 	SD->swaplog_fd = fd;
+	lseek(fd, 0L, SEEK_END);
+	mapfdswap(SD);
+#if HPL_REPL
+	if (!SD->heap)
+	    SD->heap = new_heap(SD->max_size / Config.Store.avgObjectSize,
+			    store_policy,
+			    offsetof(StoreEntry, n.ode));
+#endif
     }
+#ifdef MMAPSTORE
+    {
+	struct mmapinfo *mi, **pmi;
+	for (pmi=&allmi; mi = *pmi; ) {
+	    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+		SD = &Config.cacheSwap.swapDirs[i];
+		if (SD->swaplog_fd < 0)	/* not open */
+		    continue;
+		if (SD->mi == mi) {
+		    pmi = &mi->next;
+		    goto next;
+		}
+	    }
+	    xfree(mi->path);
+	    *pmi = mi->next;
+	    {
+		storeSwapLogData*oldbase = mi->mmapbase, *oldend = mi->mmapend;
+#ifdef	HPL_REPL
+#if 1
+		assert(0); /* delete_heap, filebitmap */
+#else
+		heap_node_p tobefreed = 0;
+		int node;
+	        for (node=0; node < heap_nodes(store_heap); ) {
+	            StoreEntry *e = (StoreEntry*)heap_peep(store_heap, node);
+	            if (oldbase <= e->s && e->s <oldend) {
+		 	heap_node_p tp;
+			tp = tobefreed;
+			tobefreed = e->n.ode;
+			e->n.ode = tp;		/* collect'm */
+			continue;
+		    }
+		    node++;
+	        }
+		while (tobefreed) {		/* delete'm */
+		    heap_node_p next;
+		    StoreEntry *e;
+		    e = tobefreed->data;
+		    next = e->n.ode;
+		    e->n.ode = tobefreed;	/* put back node value */
+		    storeHashDelete(e);
+		    tobefreed = next;
+		}
+#endif
+#else	/* HPL_REPL */
+		dlink_node *m;
+	        for (m = store_list.tail; m; ) {
+	            StoreEntry *e = m->data;
+		    m = m->prev;
+	            if (oldbase <= e->s && e->s <oldend) {
+		        storeHashDelete(e);
+			continue;
+		    }
+    }
+#endif	/* HPL_REPL */
+	    }
+	    munmap(mi->mmapbase, (char*)mi->mmapmax-(char*)mi->mmapbase);
+	    xfree(mi);
+next:;
+	}
+    }
+#endif
+
 }
 
 void
@@ -482,6 +735,13 @@
 	SD = &Config.cacheSwap.swapDirs[i];
 	if (SD->swaplog_fd < 0)	/* not open */
 	    continue;
+#ifdef MMAPSTORE
+	{
+	    struct mmapinfo *mi = SD->mi;
+	    msync(mi->mmapbase, (char*)mi->mmapend-(char*)mi-> mmapbase, MS_ASYNC);
+	}
+	SD->mi = 0;
+#endif
 	file_close(SD->swaplog_fd);
 	debug(47, 3) ("Cache Dir #%d log closed on FD %d\n", i, SD->swaplog_fd);
 	SD->swaplog_fd = -1;
@@ -491,6 +751,10 @@
 FILE *
 storeDirOpenTmpSwapLog(int dirn, int *clean_flag, int *zero_flag)
 {
+#ifdef MMAPSTORE
+    *clean_flag = 1; *zero_flag = 0;
+    return stderr;
+#else
     char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
     char *clean_path = xstrdup(storeDirSwapLogFile(dirn, ".last-clean"));
     char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
@@ -535,11 +799,13 @@
     safe_free(clean_path);
     safe_free(new_path);
     return fp;
+#endif
 }
 
 void
 storeDirCloseTmpSwapLog(int dirn)
 {
+#ifndef MMAPSTORE
     char *swaplog_path = xstrdup(storeDirSwapLogFile(dirn, NULL));
     char *new_path = xstrdup(storeDirSwapLogFile(dirn, ".new"));
     SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
@@ -564,6 +830,7 @@
     safe_free(new_path);
     SD->swaplog_fd = fd;
     debug(47, 3) ("Cache Dir #%d log opened on FD %d\n", dirn, fd);
+#endif
 }
 
 void
@@ -600,13 +867,23 @@
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
 	SD = &Config.cacheSwap.swapDirs[i];
 	storeAppendPrintf(sentry, "\n");
-	storeAppendPrintf(sentry, "Store Directory #%d: %s\n", i, SD->path);
-	storeAppendPrintf(sentry, "First level subdirectories: %d\n", SD->l1);
-	storeAppendPrintf(sentry, "Second level subdirectories: %d\n", SD->l2);
-	storeAppendPrintf(sentry, "Maximum Size: %d KB\n", SD->max_size);
-	storeAppendPrintf(sentry, "Current Size: %d KB\n", SD->cur_size);
-	storeAppendPrintf(sentry, "Percent Used: %0.2f%%\n",
-	    100.0 * SD->cur_size / SD->max_size);
+	storeAppendPrintf(sentry, "Store Directory #%d: %s [%d][%d]\n",
+	    i, SD->path, SD->l1, SD->l2);
+	storeAppendPrintf(sentry, "Size: %d < %d < %d KB of %d MB (%.2f%%)\n",
+	    SD->low_size, SD->cur_size, SD->low_size + SD->win_size*STORE_GRAN_MAX,
+	    SD->max_size / 1024, 100.0 * SD->cur_size / SD->max_size);
+#ifdef MMAPSTORE
+	{
+	    struct mmapinfo *mi = SD->mi;
+	    storeAppendPrintf(sentry,
+		"Swapfile: %.1f < %.1f < %.1f MB (%.2f%% efficiency)\n",
+		SD->heap->last * sizeof(storeSwapLogData) / (1024*1024.),
+		((char*)mi->mmapend-(char*)mi->mmapbase) / (1024*1024.),
+		((char*)mi->mmapmax-(char*)mi->mmapbase) / (1024*1024.),
+		100. * (SD->heap->last * sizeof(storeSwapLogData)) /
+		  ((char*)mi->mmapend-(char*)mi->mmapbase));
+	}
+#endif
 	storeAppendPrintf(sentry, "Filemap bits in use: %d of %d (%d%%)\n",
 	    SD->map->n_files_in_map, SD->map->max_n_files,
 	    percent(SD->map->n_files_in_map, SD->map->max_n_files));
@@ -643,6 +920,50 @@
     return n;
 }
 
+
+void
+storeDirConfigure(void)
+{
+    SwapDir *SD;
+    int n;
+    int i;
+    fileMap *fm;
+    Config.Swap.maxSize = 0;
+    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
+	SD = &Config.cacheSwap.swapDirs[i];
+	Config.Swap.maxSize += SD->max_size;
+	SD->low_size = (double) SD->max_size * Config.Swap.lowWaterMark /100;
+	SD->win_size = (double) SD->max_size *
+		(Config.Swap.highWaterMark - Config.Swap.lowWaterMark) /100
+		/STORE_GRAN_MAX;
+	if (!SD->win_size)
+	    SD->win_size = 1;
+	n = SD->max_size / Config.Store.avgObjectSize * 3 / 2;
+	if (NULL == SD->map) {
+	    /* first time */
+	    SD->map = file_map_create(n);
+	    SD->heap = 0;
+	} else if (n > SD->map->max_n_files) {
+	    /* it grew, need to expand */
+	    fm = file_map_create(n);
+	    filemapCopy(SD->map, fm);
+	    filemapFreeMemory(SD->map);
+	    SD->map = fm;
+	}
+	/* else it shrunk, and we leave the old one in place */
+    }
+}
+
+void
+storeDirDiskFull(int fn)
+{
+    int dirn = fn >> SWAP_DIR_SHIFT;
+    SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
+    assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
+    SD->max_size = SD->cur_size;
+    debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n",
+	dirn, SD->cur_size);
+}
 /*
  *  storeDirWriteCleanLogs
  * 
@@ -652,6 +973,9 @@
 int
 storeDirWriteCleanLogs(int reopen)
 {
+#ifdef MMAPSTORE
+    return 0;
+#else
     StoreEntry *e = NULL;
     int *fd;
     int n = 0;
@@ -662,11 +986,16 @@
     char **cln;
     int dirn;
     int N = Config.cacheSwap.n_configured;
-    dlink_node *m;
     char **outbuf;
     off_t *outbufoffset;
     storeSwapLogData s;
     size_t ss = sizeof(storeSwapLogData);
+    #ifdef	HPL_REPL
+    int node;
+    #else	/* HPL_REPL */
+    dlink_node *m;
+    #endif	/* HPL_REPL */
+
     if (store_rebuilding) {
 	debug(20, 1) ("Not currently OK to rewrite swap log.\n");
 	debug(20, 1) ("storeDirWriteCleanLogs: Operation aborted.\n");
@@ -707,34 +1036,43 @@
 	outbuf[dirn] = xcalloc(CLEAN_BUF_SZ, 1);
 	outbufoffset[dirn] = 0;
     }
-    for (m = store_list.tail; m; m = m->prev) {
+    #ifdef	HPL_REPL
+    for (node=0; node < heap_nodes(store_heap); node++)
+    #else	/* HPL_REPL */
+    for (m = store_list.tail; m; m = m->prev)
+    #endif	/* HPL_REPL */
+      {
+	#ifdef	HPL_REPL
+	e = (StoreEntry*)heap_peep(store_heap, node);
+	#else	/* HPL_REPL */
 	e = m->data;
-	if (e->swap_file_number < 0)
+	#endif	/* HPL_REPL */
+	if (e->Sswap_file_number < 0)
 	    continue;
 	if (e->swap_status != SWAPOUT_DONE)
 	    continue;
-	if (e->swap_file_sz <= 0)
+	if (e->Sswap_file_sz <= 0)
 	    continue;
-	if (EBIT_TEST(e->flags, RELEASE_REQUEST))
+	if (EBIT_TEST(e->Sflag, RELEASE_REQUEST))
 	    continue;
-	if (EBIT_TEST(e->flags, KEY_PRIVATE))
+	if (EBIT_TEST(e->Sflag, KEY_PRIVATE))
 	    continue;
-	if (EBIT_TEST(e->flags, ENTRY_SPECIAL))
+	if (EBIT_TEST(e->Sflag, ENTRY_SPECIAL))
 	    continue;
-	dirn = storeDirNumber(e->swap_file_number);
+	dirn = storeDirNumber(e->Sswap_file_number);
 	assert(dirn < N);
 	if (fd[dirn] < 0)
 	    continue;
 	memset(&s, '\0', ss);
 	s.op = (char) SWAP_LOG_ADD;
-	s.swap_file_number = e->swap_file_number;
-	s.timestamp = e->timestamp;
-	s.lastref = e->lastref;
-	s.expires = e->expires;
-	s.lastmod = e->lastmod;
-	s.swap_file_sz = e->swap_file_sz;
-	s.refcount = e->refcount;
-	s.flags = e->flags;
+	s.swap_file_number = e->Sswap_file_number;
+	s.timestamp = e->Stimestamp;
+	s.lastref = e->Slastref;
+	s.expires = e->Sexpires;
+	s.lastmod = e->Slastmod;
+	s.swap_file_sz = e->Sswap_file_sz;
+	s.refcount = e->Srefcount;
+	s.flags = e->Sflag;
 	xmemcpy(&s.key, e->key, MD5_DIGEST_CHARS);
 	xmemcpy(outbuf[dirn] + outbufoffset[dirn], &s, ss);
 	outbufoffset[dirn] += ss;
@@ -828,42 +1166,6 @@
     safe_free(cln);
     safe_free(fd);
     return n;
+#endif
 }
 #undef CLEAN_BUF_SZ
-
-void
-storeDirConfigure(void)
-{
-    SwapDir *SD;
-    int n;
-    int i;
-    fileMap *fm;
-    Config.Swap.maxSize = 0;
-    for (i = 0; i < Config.cacheSwap.n_configured; i++) {
-	SD = &Config.cacheSwap.swapDirs[i];;
-	Config.Swap.maxSize += SD->max_size;
-	n = 2 * SD->max_size / Config.Store.avgObjectSize;
-	if (NULL == SD->map) {
-	    /* first time */
-	    SD->map = file_map_create(n);
-	} else if (n > SD->map->max_n_files) {
-	    /* it grew, need to expand */
-	    fm = file_map_create(n);
-	    filemapCopy(SD->map, fm);
-	    filemapFreeMemory(SD->map);
-	    SD->map = fm;
-	}
-	/* else it shrunk, and we leave the old one in place */
-    }
-}
-
-void
-storeDirDiskFull(int fn)
-{
-    int dirn = fn >> SWAP_DIR_SHIFT;
-    SwapDir *SD = &Config.cacheSwap.swapDirs[dirn];
-    assert(0 <= dirn && dirn < Config.cacheSwap.n_configured);
-    SD->max_size = SD->cur_size;
-    debug(20, 1) ("WARNING: Shrinking cache_dir #%d to %d KB\n",
-	dirn, SD->cur_size);
-}
Index: squid/src/store_log.c
diff -u squid/src/store_log.c:1.1.1.1 squid/src/store_log.c:1.1.1.1.10.1
--- squid/src/store_log.c:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/src/store_log.c	Fri Nov 10 10:44:53 2000
@@ -66,7 +66,7 @@
 	(int) current_time.tv_sec,
 	(int) current_time.tv_usec / 1000,
 	storeLogTags[tag],
-	e->swap_file_number,
+	e->Sswap_file_number,
 	reply->sline.status,
 	(int) reply->date,
 	(int) reply->last_modified,
Index: squid/src/store_rebuild.c
diff -u squid/src/store_rebuild.c:1.1.1.2 squid/src/store_rebuild.c:1.1.1.2.10.1
--- squid/src/store_rebuild.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_rebuild.c	Fri Nov 10 10:44:53 2000
@@ -91,8 +91,10 @@
 static void storeRebuildComplete(void);
 static EVH storeRebuildADirectory;
 static int storeGetNextFile(rebuild_dir *, int *sfileno, int *size);
-static StoreEntry *storeAddDiskRestore(const cache_key * key,
-    int file_number,
+#ifdef MMAPSTORE
+static StoreEntry *storeAddDiskRestore(storeSwapLogData*s);
+#else
+static StoreEntry *storeAddDiskRestore(int file_number,
     size_t swap_file_sz,
     time_t expires,
     time_t timestamp,
@@ -101,6 +103,7 @@
     u_num32 refcount,
     u_short flags,
     int clean);
+#endif
 static AIOCB storeValidateComplete;
 
 static int
@@ -109,7 +112,13 @@
     LOCAL_ARRAY(char, hdr_buf, DISK_PAGE_SIZE);
     StoreEntry *e = NULL;
     StoreEntry tmpe;
+#ifdef MMAPSTORE
+    storeSwapLogData tmps;
+    SwapDir *sd = Config.cacheSwap.swapDirs + d->dirn;
+    cache_key*key;
+#else
     cache_key key[MD5_DIGEST_CHARS];
+#endif
     int sfileno = 0;
     int count;
     int size;
@@ -119,7 +128,7 @@
     tlv *tlv_list;
     tlv *t;
     assert(d != NULL);
-    debug(20, 3) ("storeRebuildFromDirectory: DIR #%d\n", d->dirn);
+    debug(20, 2) ("storeRebuildFromDirectory: DIR #%d\n", d->dirn);
     for (count = 0; count < d->speed; count++) {
 	assert(fd == -1);
 	fd = storeGetNextFile(d, &sfileno, &size);
@@ -169,8 +178,14 @@
 	    continue;
 	}
 	debug(20, 3) ("storeRebuildFromDirectory: successful swap meta unpacking\n");
-	memset(key, '\0', MD5_DIGEST_CHARS);
 	memset(&tmpe, '\0', sizeof(StoreEntry));
+#ifdef MMAPSTORE
+	tmpe.s=&tmps;
+	memset(&tmps, '\0', sizeof(StoreEntry));
+	key = tmps.key;
+#else
+	memset(key, '\0', MD5_DIGEST_CHARS);
+#endif
 	for (t = tlv_list; t; t = t->next) {
 	    switch (t->type) {
 	    case STORE_META_KEY:
@@ -179,7 +194,7 @@
 		break;
 	    case STORE_META_STD:
 		assert(t->length == STORE_HDR_METASIZE);
-		xmemcpy(&tmpe.timestamp, t->value, STORE_HDR_METASIZE);
+		xmemcpy(&tmpe.Stimestamp, t->value, STORE_HDR_METASIZE);
 		break;
 	    default:
 		break;
@@ -192,25 +207,27 @@
 	    storeUnlinkFileno(sfileno);
 	    continue;
 	}
+#ifndef MMAPSTORE
 	tmpe.key = key;
+#endif
 	/* check sizes */
-	if (tmpe.swap_file_sz == 0) {
-	    tmpe.swap_file_sz = sb.st_size;
-	} else if (tmpe.swap_file_sz == sb.st_size - swap_hdr_len) {
-	    tmpe.swap_file_sz = sb.st_size;
-	} else if (tmpe.swap_file_sz != sb.st_size) {
+	if (tmpe.Sswap_file_sz == 0) {
+	    tmpe.Sswap_file_sz = sb.st_size;
+	} else if (tmpe.Sswap_file_sz == sb.st_size - swap_hdr_len) {
+	    tmpe.Sswap_file_sz = sb.st_size;
+	} else if (tmpe.Sswap_file_sz != sb.st_size) {
 	    debug(20, 1) ("storeRebuildFromDirectory: SIZE MISMATCH %d!=%d\n",
-		tmpe.swap_file_sz, (int) sb.st_size);
+		tmpe.Sswap_file_sz, (int) sb.st_size);
 	    storeUnlinkFileno(sfileno);
 	    continue;
 	}
-	if (EBIT_TEST(tmpe.flags, KEY_PRIVATE)) {
+	if (EBIT_TEST(tmpe.Sflag, KEY_PRIVATE)) {
 	    storeUnlinkFileno(sfileno);
 	    RebuildState.badflags++;
 	    continue;
 	}
 	e = storeGet(key);
-	if (e && e->lastref >= tmpe.lastref) {
+	if (e && e->Slastref >= tmpe.Slastref) {
 	    /* key already exists, current entry is newer */
 	    /* keep old, ignore new */
 	    RebuildState.dupcount++;
@@ -218,21 +235,34 @@
 	} else if (NULL != e) {
 	    /* URL already exists, this swapfile not being used */
 	    /* junk old, load new */
-	    storeRelease(e);	/* release old entry */
+	    storeLockObject(e);
+	    storeReleaseRequest(e);	/* release old entry */
+	    e->lock_count--;
 	    RebuildState.dupcount++;
 	}
 	RebuildState.objcount++;
 	storeEntryDump(&tmpe, 5);
+#ifdef MMAPSTORE
+	{
+	    storeSwapLogData *ns = memAllocate(MEM_STORESWAPLOGDATA);
+            *ns = tmps;
+	    ns->swap_file_number = -1;
+	    set_swap_file_number(ns, sfileno);
+	    e = storeAddDiskRestore(storeSwapAppendList(sd, ns));
+	}
+	storeDirSwapLog(e, SWAP_LOG_ADD);
+#else
 	e = storeAddDiskRestore(key,
 	    sfileno,
-	    tmpe.swap_file_sz,
-	    tmpe.expires,
-	    tmpe.timestamp,
-	    tmpe.lastref,
-	    tmpe.lastmod,
-	    tmpe.refcount,	/* refcount */
-	    tmpe.flags,		/* flags */
+	    tmpe.Sswap_file_sz,
+	    tmpe.Sexpires,
+	    tmpe.Stimestamp,
+	    tmpe.Slastref,
+	    tmpe.Slastmod,
+	    tmpe.Srefcount,	/* refcount */
+	    tmpe.Sflag,		/* flags */
 	    d->clean);
+#endif
     }
     return count;
 }
@@ -241,16 +271,28 @@
 storeRebuildFromSwapLog(rebuild_dir * d)
 {
     StoreEntry *e = NULL;
-    storeSwapLogData s;
+    storeSwapLogData ts,*s;
     size_t ss = sizeof(storeSwapLogData);
     int count;
     int used;			/* is swapfile already in use? */
     int disk_entry_newer;	/* is the log entry newer than current entry? */
     double x;
-    assert(d != NULL);
     /* load a number of objects per invocation */
+#ifdef MMAPSTORE
+    SwapDir *sd = Config.cacheSwap.swapDirs + d->dirn;
+    struct mmapinfo *mi = sd->mi;
+    for (s=mi->mmapbase, count = 0;; s++, count++) {
+	if (s - mi->mmapend >= 0) {
+	    debug(20, 1) ("Done reading Cache Dir #%d swaplog (%d entries)\n",
+		d->dirn, d->n_read);
+	    d->log = 0;
+	    return -1;
+	}
+#else
+    assert(d != NULL);
+    s = &ts;
     for (count = 0; count < d->speed; count++) {
-	if (fread(&s, ss, 1, d->log) != 1) {
+	if (fread(s, ss, 1, d->log) != 1) {
 	    debug(20, 1) ("Done reading Cache Dir #%d swaplog (%d entries)\n",
 		d->dirn, d->n_read);
 	    fclose(d->log);
@@ -258,20 +300,28 @@
 	    storeDirCloseTmpSwapLog(d->dirn);
 	    return -1;
 	}
+#endif
 	d->n_read++;
-	if (s.op <= SWAP_LOG_NOP)
+#ifdef MMAPSTORE
+	if (s->swap_file_number<0) {
+	    goto delit;
+	}
+#else
+	if (s->op <= SWAP_LOG_NOP)
 	    continue;
-	if (s.op >= SWAP_LOG_MAX)
+	if (s->op >= SWAP_LOG_MAX)
 	    continue;
-	s.swap_file_number = storeDirProperFileno(d->dirn, s.swap_file_number);
+#endif
+	s->swap_file_number = storeDirProperFileno(d->dirn, s->swap_file_number);
+#ifndef MMAPSTORE
 	debug(20, 3) ("storeRebuildFromSwapLog: %s %s %08X\n",
-	    swap_log_op_str[(int) s.op],
-	    storeKeyText(s.key),
-	    s.swap_file_number);
-	if (s.op == SWAP_LOG_ADD) {
+	    swap_log_op_str[(int) s->op],
+	    storeKeyText(s->key),
+	    s->swap_file_number);
+	if (s->op == SWAP_LOG_ADD) {
 	    (void) 0;
-	} else if (s.op == SWAP_LOG_DEL) {
-	    if ((e = storeGet(s.key)) != NULL) {
+	} else if (s->op == SWAP_LOG_DEL) {
+	    if ((e = storeGet(s->key)) != NULL) {
 		/*
 		 * Make sure we don't unlink the file, it might be
 		 * in use by a subsequent entry.  Also note that
@@ -281,9 +331,9 @@
 		 */
 		storeExpireNow(e);
 		storeReleaseRequest(e);
-		if (e->swap_file_number > -1) {
-		    storeDirMapBitReset(e->swap_file_number);
-		    e->swap_file_number = -1;
+		if (e->Sswap_file_number > -1) {
+		    storeDirMapBitReset(e->Sswap_file_number);
+		    e->Sswap_file_number = -1;
 		}
 		RebuildState.objcount--;
 		RebuildState.cancelcount++;
@@ -297,49 +347,60 @@
 	    RebuildState.invalid++;
 	    continue;
 	}
+#endif
 	if ((++RebuildState.linecount & 0xFFFF) == 0)
 	    debug(20, 1) ("  %7d Entries read so far.\n",
 		RebuildState.linecount);
-	if (!storeDirValidFileno(s.swap_file_number)) {
+	if (!storeDirValidFileno(s->swap_file_number)) {
 	    RebuildState.invalid++;
-	    continue;
+	    goto remswap;
 	}
-	if (EBIT_TEST(s.flags, KEY_PRIVATE)) {
+	used = storeDirMapBitTest(s->swap_file_number);
+	if (EBIT_TEST(s->flags, KEY_PRIVATE)) {
 	    RebuildState.badflags++;
-	    continue;
+	    if (!used)
+	       goto remswap;
+	    goto delit;
 	}
-	e = storeGet(s.key);
-	used = storeDirMapBitTest(s.swap_file_number);
+	e = storeGet(s->key);
 	/* If this URL already exists in the cache, does the swap log
 	 * appear to have a newer entry?  Compare 'lastref' from the
-	 * swap log to e->lastref. */
-	disk_entry_newer = e ? (s.lastref > e->lastref ? 1 : 0) : 0;
+	 * swap log to e->Slastref. */
+	disk_entry_newer = e ? (s->lastref > e->Slastref ? 1 : 0) : 0;
 	if (used && !disk_entry_newer) {
 	    /* log entry is old, ignore it */
 	    RebuildState.clashcount++;
-	    continue;
-	} else if (used && e && e->swap_file_number == s.swap_file_number) {
+	    goto delit;
+	} else if (used && e && e->Sswap_file_number == s->swap_file_number) {
 	    /* swapfile taken, same URL, newer, update meta */
 	    if (e->store_status == STORE_OK) {
-		e->lastref = s.timestamp;
-		e->timestamp = s.timestamp;
-		e->expires = s.expires;
-		e->lastmod = s.lastmod;
-		e->flags = s.flags;
-		e->refcount += s.refcount;
+		e->Slastref = s->timestamp;
+		e->Stimestamp = s->timestamp;
+		e->Sexpires = s->expires;
+		e->Slastmod = s->lastmod;
+		e->Sflag = s->flags;
+		e->Srefcount += s->refcount;
+#ifdef	HPL_REPL
+		/* Update the position of this object in the store and memory heaps. */
+		assert(e->n.ode.id >= 0);
+		heap_update(sd->heap, &e->n.ode);
+		if (e->mem_obj)
+		  heap_update(inmem_heap, &e->mem_obj->n.ode);
+#endif	/* HPL_REPL */
+
 	    } else {
 		debug_trap("storeRebuildFromSwapLog: bad condition");
 		debug(20, 1) ("\tSee %s:%d\n", __FILE__, __LINE__);
 	    }
-	    continue;
+	    goto delit;
 	} else if (used) {
 	    /* swapfile in use, not by this URL, log entry is newer */
 	    /* This is sorta bad: the log entry should NOT be newer at this
 	     * point.  If the log is dirty, the filesize check should have
-	     * caught this.  If the log is clean, there should never be a
+	     * caught this->  If the log is clean, there should never be a
 	     * newer entry. */
 	    debug(20, 1) ("WARNING: newer swaplog entry for fileno %08X\n",
-		s.swap_file_number);
+		s->swap_file_number);
 	    /* I'm tempted to remove the swapfile here just to be safe,
 	     * but there is a bad race condition in the NOVM version if
 	     * the swapfile has recently been opened for writing, but
@@ -349,24 +410,32 @@
 	    /* We'll assume the existing entry is valid, probably because
 	     * were in a slow rebuild and the the swap file number got taken
 	     * and the validation procedure hasn't run. */
+#ifndef MMAPSTORE
 	    assert(RebuildState.need_to_validate);
+#endif
 	    RebuildState.clashcount++;
-	    continue;
+	    goto delit;
 	} else if (e && !disk_entry_newer) {
 	    /* key already exists, current entry is newer */
 	    /* keep old, ignore new */
 	    RebuildState.dupcount++;
+remswap:
+#ifdef MMAPSTORE
+	    storeUnlinkFileno(s->swap_file_number);
+erasit:	    storeDirMapBitReset(s->swap_file_number);
+delit:	    storeSwapToFreeList(sd, s);
+#else
+delit:;
+#endif
 	    continue;
 	} else if (e) {
 	    /* key already exists, this swapfile not being used */
 	    /* junk old, load new */
 	    storeExpireNow(e);
 	    storeReleaseRequest(e);
-	    if (e->swap_file_number > -1) {
-		storeDirMapBitReset(e->swap_file_number);
-		e->swap_file_number = -1;
-	    }
 	    RebuildState.dupcount++;
+	    if (e->Sswap_file_number > -1)
+		goto erasit;
 	} else {
 	    /* URL doesnt exist, swapfile not in use */
 	    /* load new */
@@ -374,17 +443,24 @@
 	}
 	/* update store_swap_size */
 	RebuildState.objcount++;
-	e = storeAddDiskRestore(s.key,
-	    s.swap_file_number,
-	    s.swap_file_sz,
-	    s.expires,
-	    s.timestamp,
-	    s.lastref,
-	    s.lastmod,
-	    s.refcount,
-	    s.flags,
+#ifdef MMAPSTORE
+	e = storeAddDiskRestore(s);
+#else
+	e = storeAddDiskRestore(s->key,
+	    s->swap_file_number,
+	    s->swap_file_sz,
+	    s->expires,
+	    s->timestamp,
+	    s->lastref,
+	    s->lastmod,
+	    s->refcount,
+	    s->flags,
 	    d->clean);
 	storeDirSwapLog(e, SWAP_LOG_ADD);
+#endif
+#if HPL_REPL
+	heap_insert(sd->heap, e);
+#endif
     }
     return count;
 }
@@ -395,6 +471,7 @@
     int count;
     rebuild_dir *d;
     rebuild_dir **D;
+loop:
     if ((d = RebuildState.rebuild_dir) == NULL) {
 	storeRebuildComplete();
 	return;
@@ -409,7 +486,7 @@
 	d->next = NULL;
     }
     if (opt_foreground_rebuild)
-	storeRebuildADirectory(NULL);
+	goto loop;
     else
 	eventAdd("storeRebuild", storeRebuildADirectory, NULL, 0.0, 1);
 }
@@ -435,7 +512,7 @@
     tlv *tlv_list;
     StoreEntry e;
     e.key = key;
-    e.swap_file_sz = swap_file_sz;
+    e.Sswap_file_sz = swap_file_sz;
     e.expires = expires;
     e.lastref = lastref;
     e.refcount = refcount;
@@ -543,6 +620,9 @@
 /* Add a new object to the cache with empty memory copy and pointer to disk
  * use to rebuild store from disk. */
 static StoreEntry *
+#ifdef MMAPSTORE
+storeAddDiskRestore(storeSwapLogData*s)
+#else
 storeAddDiskRestore(const cache_key * key,
     int file_number,
     size_t swap_file_sz,
@@ -553,32 +633,39 @@
     u_num32 refcount,
     u_short flags,
     int clean)
+#endif
 {
     StoreEntry *e = NULL;
+#ifndef MMAPSTORE
     debug(20, 5) ("StoreAddDiskRestore: %s, fileno=%08X\n", storeKeyText(key), file_number);
+#endif
     /* if you call this you'd better be sure file_number is not 
      * already in use! */
     e = new_StoreEntry(STORE_ENTRY_WITHOUT_MEMOBJ, NULL, NULL);
     e->store_status = STORE_OK;
     storeSetMemStatus(e, NOT_IN_MEMORY);
     e->swap_status = SWAPOUT_DONE;
-    e->swap_file_number = file_number;
-    e->swap_file_sz = swap_file_sz;
     e->lock_count = 0;
-    e->refcount = 0;
-    e->lastref = lastref;
-    e->timestamp = timestamp;
-    e->expires = expires;
-    e->lastmod = lastmod;
-    e->refcount = refcount;
-    e->flags = flags;
-    EBIT_SET(e->flags, ENTRY_CACHABLE);
-    EBIT_CLR(e->flags, RELEASE_REQUEST);
-    EBIT_CLR(e->flags, KEY_PRIVATE);
     e->ping_status = PING_NONE;
-    EBIT_CLR(e->flags, ENTRY_VALIDATED);
-    storeDirMapBitSet(e->swap_file_number);
-    storeHashInsert(e, key);	/* do it after we clear KEY_PRIVATE */
+#ifdef MMAPSTORE
+    e->s = s;
+#else
+    e->key = key;
+    e->Sswap_file_number = file_number;
+    e->Sswap_file_sz = swap_file_sz;
+    e->Slastref = lastref;
+    e->Stimestamp = timestamp;
+    e->Sexpires = expires;
+    e->Slastmod = lastmod;
+    e->Srefcount = refcount;
+    e->Sflag = flags;
+#endif
+    EBIT_SET(e->Sflag, ENTRY_CACHABLE);
+    EBIT_CLR(e->Sflag, RELEASE_REQUEST);
+    EBIT_CLR(e->Sflag, KEY_PRIVATE);
+    EBIT_CLR(e->Sflag, ENTRY_VALIDATED);
+    storeDirMapBitSet(e->Sswap_file_number);
+    storeHashInsert(e, e->Skey);	/* do it after we clear KEY_PRIVATE */
     return e;
 }
 
@@ -591,13 +678,18 @@
     StoreEntry *e;
     hash_link *link_ptr = NULL;
     hash_link *link_next = NULL;
+    time_t force_doublecheck = RebuildState.start - 1024;
     if (++bucketnum >= store_hash_buckets) {
 	debug(20, 1) ("  Completed Validation Procedure\n");
 	debug(20, 1) ("  Validated %d Entries\n", validnum);
 	debug(20, 1) ("  store_swap_size = %dk\n", store_swap_size);
 	store_rebuilding = 0;
-	if (opt_store_doublecheck)
+	if (opt_store_doublecheck) {
+#if 0	/* bogus assertion srb */
 	    assert(store_errors == 0);
+#endif
+	    opt_store_doublecheck = 0;	/* only do this once */
+	}
 	if (store_digest)
 	    storeDigestNoteStoreReady();
 	return;
@@ -606,41 +698,57 @@
     while (NULL != (link_ptr = link_next)) {
 	link_next = link_ptr->next;
 	e = (StoreEntry *) link_ptr;
-	if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
+	if (EBIT_TEST(e->Sflag, ENTRY_VALIDATED))
 	    continue;
+	if (e->Sswap_file_number < 0)
+	    continue;
+	if (EBIT_TEST(e->Sflag, RELEASE_REQUEST)) {
 	/*
 	 * Calling storeRelease() has no effect because we're
 	 * still in 'store_rebuilding' state
 	 */
-	if (e->swap_file_number < 0)
+relit:	    storeLockObject(e);
+	    storeReleaseRequest(e);	/* release entry */
+	    e->lock_count--;
 	    continue;
-	if (opt_store_doublecheck) {
+	}
+  	if (e->Sswap_file_number < 0)
+  	    continue;
+	if (opt_store_doublecheck ||
+		!e->Sswap_file_sz ||
+		e->Slastref > force_doublecheck) {
 	    struct stat sb;
-	    if (stat(storeSwapFullPath(e->swap_file_number, NULL), &sb) < 0) {
+	    if (stat(storeSwapFullPath(e->Sswap_file_number, NULL), &sb) < 0) {
+	        static unsigned vleft = 1024;
 		store_errors++;
-		debug(20, 0) ("storeCleanup: MISSING SWAP FILE\n");
-		debug(20, 0) ("storeCleanup: FILENO %08X\n", e->swap_file_number);
-		debug(20, 0) ("storeCleanup: PATH %s\n",
-		    storeSwapFullPath(e->swap_file_number, NULL));
-		storeEntryDump(e, 0);
-		continue;
+	        if (vleft) {
+		    if (!--vleft)
+			debug (20, 0) ("storeCleanup: Too many missing "
+			    "swapfiles, suppressing logging\n");
+		    debug(20, 1) ("storeCleanup: MISSING SWAP FILE\n");
+		    debug(20, 1) ("storeCleanup: FILENO %08X\n",
+			e->Sswap_file_number);
+		    debug(20, 1) ("storeCleanup: PATH %s\n",
+		        storeSwapFullPath(e->Sswap_file_number, NULL));
+dumpit:		    storeEntryDump(e, 1);
+	    }
+		goto relit;
 	    }
-	    if (e->swap_file_sz != sb.st_size) {
+	    if (e->Sswap_file_sz != sb.st_size) {
 		store_errors++;
-		debug(20, 0) ("storeCleanup: SIZE MISMATCH\n");
-		debug(20, 0) ("storeCleanup: FILENO %08X\n", e->swap_file_number);
-		debug(20, 0) ("storeCleanup: PATH %s\n",
-		    storeSwapFullPath(e->swap_file_number, NULL));
-		debug(20, 0) ("storeCleanup: ENTRY SIZE: %d, FILE SIZE: %d\n",
-		    e->swap_file_sz, (int) sb.st_size);
-		storeEntryDump(e, 0);
-		continue;
+		debug(20, 1) ("storeCleanup: SIZE MISMATCH\n");
+		debug(20, 1) ("storeCleanup: FILENO %08X\n", e->Sswap_file_number);
+		debug(20, 1) ("storeCleanup: PATH %s\n",
+		    storeSwapFullPath(e->Sswap_file_number, NULL));
+		debug(20, 1) ("storeCleanup: ENTRY SIZE: %d, FILE SIZE: %d\n",
+		    e->Sswap_file_sz, (int) sb.st_size);
+		goto dumpit;
 	    }
 	}
-	EBIT_SET(e->flags, ENTRY_VALIDATED);
+	EBIT_SET(e->Sflag, ENTRY_VALIDATED);
 	/* Only set the file bit if we know its a valid entry */
 	/* otherwise, set it in the validation procedure */
-	storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
+	storeDirUpdateSwapSize(e->Sswap_file_number, e->Sswap_file_sz, 1);
 	if ((++validnum & 0xFFFF) == 0)
 	    debug(20, 1) ("  %7d Entries Validated so far.\n", validnum);
     }
@@ -656,13 +764,13 @@
 #if !USE_ASYNC_IO
     int x;
 #endif
-    assert(!EBIT_TEST(e->flags, ENTRY_VALIDATED));
-    if (e->swap_file_number < 0) {
-	EBIT_CLR(e->flags, ENTRY_VALIDATED);
+    assert(!EBIT_TEST(e->Sflag, ENTRY_VALIDATED));
+    if (e->Sswap_file_number < 0) {
+	EBIT_CLR(e->Sflag, ENTRY_VALIDATED);
 	callback(callback_data, 0, 0);
 	return;
     }
-    path = storeSwapFullPath(e->swap_file_number, NULL);
+    path = storeSwapFullPath(e->Sswap_file_number, NULL);
     sb = xmalloc(sizeof(struct stat));
     ctrlp = xmalloc(sizeof(valid_ctrl_t));
     ctrlp->sb = sb;
@@ -698,14 +806,14 @@
 	return;
     }
     if (retcode < 0 && errcode == EWOULDBLOCK) {
-	path = storeSwapFullPath(e->swap_file_number, NULL);
+	path = storeSwapFullPath(e->Sswap_file_number, NULL);
 	retcode = stat(path, sb);
     }
-    if (retcode < 0 || sb->st_size == 0 || sb->st_size != e->swap_file_sz) {
-	EBIT_CLR(e->flags, ENTRY_VALIDATED);
+    if (retcode < 0 || sb->st_size == 0 || sb->st_size != e->Sswap_file_sz) {
+	EBIT_CLR(e->Sflag, ENTRY_VALIDATED);
     } else {
-	EBIT_SET(e->flags, ENTRY_VALIDATED);
-	storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
+	EBIT_SET(e->Sflag, ENTRY_VALIDATED);
+	storeDirUpdateSwapSize(e->Sswap_file_number, e->Sswap_file_sz, 1);
     }
     errno = errcode;
     ctrlp->callback(ctrlp->callback_data, retcode, errcode);
@@ -750,6 +858,7 @@
     int i;
     memset(&RebuildState, '\0', sizeof(RebuildState));
     RebuildState.start = squid_curtime;
+    store_swap_size = 0;
     for (i = 0; i < Config.cacheSwap.n_configured; i++) {
 	d = xcalloc(1, sizeof(rebuild_dir));
 	d->dirn = i;
Index: squid/src/store_swapin.c
diff -u squid/src/store_swapin.c:1.1.1.2 squid/src/store_swapin.c:1.1.1.2.12.1
--- squid/src/store_swapin.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_swapin.c	Fri Nov 10 10:44:53 2000
@@ -50,21 +50,21 @@
 {
     swapin_ctrl_t *ctrlp;
     assert(e->mem_status == NOT_IN_MEMORY);
-    if (!EBIT_TEST(e->flags, ENTRY_VALIDATED)) {
+    if (!EBIT_TEST(e->Sflag, ENTRY_VALIDATED)) {
 	/* We're still reloading and haven't validated this entry yet */
 	callback(-1, callback_data);
 	return;
     }
     debug(20, 3) ("storeSwapInStart: called for %08X %s \n",
-	e->swap_file_number, storeKeyText(e->key));
+	e->Sswap_file_number, storeKeyText(e->Skey));
     assert(e->swap_status == SWAPOUT_WRITING || e->swap_status == SWAPOUT_DONE);
-    assert(e->swap_file_number >= 0);
+    assert(e->Sswap_file_number >= 0);
     assert(e->mem_obj != NULL);
     ctrlp = xmalloc(sizeof(swapin_ctrl_t));
     ctrlp->e = e;
     ctrlp->callback = callback;
     ctrlp->callback_data = callback_data;
-    if (EBIT_TEST(e->flags, ENTRY_VALIDATED))
+    if (EBIT_TEST(e->Sflag, ENTRY_VALIDATED))
 	storeSwapInValidateComplete(ctrlp, 0, 0);
     else
 	storeValidate(e, storeSwapInValidateComplete, ctrlp, callback_data);
@@ -81,13 +81,13 @@
     }
     e = ctrlp->e;
     assert(e->mem_status == NOT_IN_MEMORY);
-    if (!EBIT_TEST(e->flags, ENTRY_VALIDATED)) {
+    if (!EBIT_TEST(e->Sflag, ENTRY_VALIDATED)) {
 	/* Invoke a store abort that should free the memory object */
 	(ctrlp->callback) (-1, ctrlp->callback_data);
 	xfree(ctrlp);
 	return;
     }
-    ctrlp->path = xstrdup(storeSwapFullPath(e->swap_file_number, NULL));
+    ctrlp->path = xstrdup(storeSwapFullPath(e->Sswap_file_number, NULL));
     debug(20, 3) ("storeSwapInValidateComplete: Opening %s\n", ctrlp->path);
     store_open_disk_fd++;
     file_open(ctrlp->path,
@@ -126,8 +126,8 @@
 	file_close(fd);
 	store_open_disk_fd--;
 	fd = -1;
-    } else if (sb.st_size == 0 || sb.st_size != e->swap_file_sz) {
-	debug(20, 1) ("storeSwapInFileOpened: %s: Size mismatch: %d(fstat) != %d(object)\n", ctrlp->path, (int) sb.st_size, e->swap_file_sz);
+    } else if (sb.st_size == 0 || sb.st_size != e->Sswap_file_sz) {
+	debug(20, 1) ("storeSwapInFileOpened: %s: Size mismatch: %d(fstat) != %d(object)\n", ctrlp->path, (int) sb.st_size, e->Sswap_file_sz);
 	file_close(fd);
 	store_open_disk_fd--;
 	fd = -1;
Index: squid/src/store_swapmeta.c
diff -u squid/src/store_swapmeta.c:1.1.1.1 squid/src/store_swapmeta.c:1.1.1.1.12.1
--- squid/src/store_swapmeta.c:1.1.1.1	Tue Jan 25 19:21:47 2000
+++ squid/src/store_swapmeta.c	Fri Nov 10 10:44:53 2000
@@ -72,8 +72,8 @@
     assert(e->swap_status == SWAPOUT_WRITING);
     url = storeUrl(e);
     debug(20, 3) ("storeSwapMetaBuild: %s\n", url);
-    T = storeSwapTLVAdd(STORE_META_KEY, e->key, MD5_DIGEST_CHARS, T);
-    T = storeSwapTLVAdd(STORE_META_STD, &e->timestamp, STORE_HDR_METASIZE, T);
+    T = storeSwapTLVAdd(STORE_META_KEY, e->Skey, MD5_DIGEST_CHARS, T);
+    T = storeSwapTLVAdd(STORE_META_STD, &e->Stimestamp, STORE_HDR_METASIZE, T);
     T = storeSwapTLVAdd(STORE_META_URL, url, strlen(url) + 1, T);
     return TLV;
 }
Index: squid/src/store_swapout.c
diff -u squid/src/store_swapout.c:1.1.1.2 squid/src/store_swapout.c:1.1.1.2.12.1
--- squid/src/store_swapout.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/store_swapout.c	Fri Nov 10 10:44:53 2000
@@ -54,8 +54,8 @@
     assert(e->mem_obj);
     cbdataAdd(ctrlp, cbdataXfree, 0);
     storeLockObject(e);
-    e->swap_file_number = storeDirMapAllocate();
-    ctrlp->swapfilename = xstrdup(storeSwapFullPath(e->swap_file_number, NULL));
+    set_swap_file_number(e, storeDirMapAllocate());
+    ctrlp->swapfilename = xstrdup(storeSwapFullPath(e->Sswap_file_number, NULL));
     ctrlp->e = e;
     ctrlp->oldswapstatus = e->swap_status;
     e->swap_status = SWAPOUT_OPENING;
@@ -74,20 +74,20 @@
     swapout_ctrl_t *ctrlp = data;
     StoreEntry *e = ctrlp->e;
     MemObject *mem = e->mem_obj;
-    debug(20, 3) ("storeSwapOutHandle: '%s', len=%d\n", storeKeyText(e->key), (int) len);
+    debug(20, 3) ("storeSwapOutHandle: '%s', len=%d\n", storeKeyText(e->Skey), (int) len);
     if (flag < 0) {
 	debug(20, 1) ("storeSwapOutHandle: SwapOut failure (err code = %d).\n",
 	    flag);
 	e->swap_status = SWAPOUT_NONE;
-	if (e->swap_file_number > -1) {
-	    storeUnlinkFileno(e->swap_file_number);
-	    storeDirMapBitReset(e->swap_file_number);
+	if (e->Sswap_file_number > -1) {
+	    storeUnlinkFileno(e->Sswap_file_number);
+	    storeDirMapBitReset(e->Sswap_file_number);
 	    if (flag == DISK_NO_SPACE_LEFT) {
-		storeDirDiskFull(e->swap_file_number);
+		storeDirDiskFull(e->Sswap_file_number);
 		storeDirConfigure();
 		storeConfigure();
 	    }
-	    e->swap_file_number = -1;
+	    set_swap_file_number(e, -1);
 	}
 	storeReleaseRequest(e);
 	storeSwapOutFileClose(e);
@@ -112,10 +112,17 @@
     }
     /* swapping complete */
     debug(20, 5) ("storeSwapOutHandle: SwapOut complete: '%s' to %s.\n",
-	storeUrl(e), storeSwapFullPath(e->swap_file_number, NULL));
-    e->swap_file_sz = objectLen(e) + mem->swap_hdr_sz;
+	storeUrl(e), storeSwapFullPath(e->Sswap_file_number, NULL));
+    e->Sswap_file_sz = objectLen(e) + mem->swap_hdr_sz;
+#ifdef	HPL_REPL
+    /* Update the position of this object in the store and memory heaps. */
+    if (e->n.ode.id >= 0)
+        heap_update(Store_Heap(e), &e->n.ode);
+    if (mem->n.ode.id >= 0)
+        heap_update(inmem_heap, &mem->n.ode);
+#endif	/* HPL_REPL */
     e->swap_status = SWAPOUT_DONE;
-    storeDirUpdateSwapSize(e->swap_file_number, e->swap_file_sz, 1);
+    storeDirUpdateSwapSize(e->Sswap_file_number, e->Sswap_file_sz, 1);
     if (storeCheckCachable(e)) {
 	storeLog(STORE_LOG_SWAPOUT, e);
 	storeDirSwapLog(e, SWAP_LOG_ADD);
@@ -142,8 +149,8 @@
     debug(20, 7) ("storeCheckSwapOut: %s\n", storeUrl(e));
     debug(20, 7) ("storeCheckSwapOut: store_status = %s\n",
 	storeStatusStr[e->store_status]);
-    if (EBIT_TEST(e->flags, ENTRY_ABORTED)) {
-	assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
+    if (EBIT_TEST(e->Sflag, ENTRY_ABORTED)) {
+	assert(EBIT_TEST(e->Sflag, RELEASE_REQUEST));
 	storeSwapOutFileClose(e);
 	return;
     }
@@ -158,7 +165,7 @@
 #if USE_ASYNC_IO
     if (mem->inmem_hi < mem->swapout.queue_offset) {
 	storeAbort(e);
-	assert(EBIT_TEST(e->flags, RELEASE_REQUEST));
+	assert(EBIT_TEST(e->Sflag, RELEASE_REQUEST));
 	storeSwapOutFileClose(e);
 	return;
     }
@@ -191,10 +198,10 @@
     if (swapout_size == 0) {
 	if (e->store_status == STORE_OK && !storeSwapOutWriteQueued(mem)) {
 	    debug(20, 7) ("storeCheckSwapOut: nothing to write for STORE_OK\n");
-	    if (e->swap_file_number > -1) {
-		storeUnlinkFileno(e->swap_file_number);
-		storeDirMapBitReset(e->swap_file_number);
-		e->swap_file_number = -1;
+	    if (e->Sswap_file_number > -1) {
+		storeUnlinkFileno(e->Sswap_file_number);
+		storeDirMapBitReset(e->Sswap_file_number);
+	        set_swap_file_number(e, -1);
 	    }
 	    e->swap_status = SWAPOUT_NONE;
 	    storeReleaseRequest(e);
@@ -234,11 +241,12 @@
 	swap_buf,
 	swapout_size);
     if (swap_buf_len < 0) {
-	debug(20, 1) ("stmemCopy returned %d for '%s'\n", swap_buf_len, storeKeyText(e->key));
-	storeUnlinkFileno(e->swap_file_number);
-	storeDirMapBitReset(e->swap_file_number);
-	e->swap_file_number = -1;
+	debug(20, 1) ("stmemCopy returned %d for '%s'\n", swap_buf_len, storeKeyText(e->Skey));
+	storeUnlinkFileno(e->Sswap_file_number);
+	storeDirMapBitReset(e->Sswap_file_number);
 	e->swap_status = SWAPOUT_NONE;
+	storeDirSwapLog(e, SWAP_LOG_DEL);
+	set_swap_file_number(e, -1);
 	memFree(swap_buf, MEM_DISK_BUF);
 	storeReleaseRequest(e);
 	storeSwapOutFileClose(e);
@@ -264,7 +272,7 @@
     MemObject *mem = e->mem_obj;
     swapout_ctrl_t *ctrlp;
     assert(mem != NULL);
-    debug(20, 3) ("storeSwapOutFileClose: %s\n", storeKeyText(e->key));
+    debug(20, 3) ("storeSwapOutFileClose: %s\n", storeKeyText(e->Skey));
     if (mem->swapout.fd < 0) {
 #if USE_ASYNC_IO
 	aioCancel(-1, e);	/* Make doubly certain pending ops are gone */
@@ -306,8 +314,8 @@
 	 * we don't try re-using it over and over
 	 */
 	if (errno != EPERM)
-	    storeDirMapBitReset(e->swap_file_number);
-	e->swap_file_number = -1;
+	    storeDirMapBitReset(e->Sswap_file_number);
+	set_swap_file_number(e, -1);
 	e->swap_status = ctrlp->oldswapstatus;
 	xfree(ctrlp->swapfilename);
 	cbdataFree(ctrlp);
@@ -319,7 +327,7 @@
     e->swap_status = SWAPOUT_WRITING;
     debug(20, 5) ("storeSwapOutFileOpened: Begin SwapOut '%s' to FD %d '%s'\n",
 	storeUrl(e), fd, ctrlp->swapfilename);
-    debug(20, 5) ("swap_file_number=%08X\n", e->swap_file_number);
+    debug(20, 5) ("swap_file_number=%08X\n", e->Sswap_file_number);
     tlv_list = storeSwapMetaBuild(e);
     buf = storeSwapMetaPack(tlv_list, &swap_hdr_sz);
     storeSwapTLVFree(tlv_list);
@@ -399,5 +407,5 @@
     for (sc = e->mem_obj->clients; sc; sc = sc->next)
 	if (sc->type == STORE_DISK_CLIENT)
 	    return 1;
-    return EBIT_TEST(e->flags, ENTRY_CACHABLE);
+    return EBIT_TEST(e->Sflag, ENTRY_CACHABLE);
 }
Index: squid/src/structs.h
diff -u squid/src/structs.h:1.1.1.2 squid/src/structs.h:1.1.1.2.10.1
--- squid/src/structs.h:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/structs.h	Fri Nov 10 10:44:53 2000
@@ -1,4 +1,7 @@
-
+#define MMAPSTORE	/*srb*/
+#define NEVERFREE
+#define SSPOOLS
+#define HPL_REPL	1
 /*
  * $Id: squid-bugless-2_2-s2_2,v 1.2 2004/09/29 00:22:50 hno Exp $
  *
@@ -231,6 +234,13 @@
 	int pct;
 	size_t max;
     } quickAbort;
+#ifdef	HPL_REPL
+    char * replPolicy;
+#endif	/* HPL_REPL */
+    /* 
+     * Note: the non-LRU policies do not use referenceAge, but we cannot
+     * remove it until we find out how to implement #else for cf_parser.c
+     */
     time_t referenceAge;
     time_t negativeTtl;
     time_t negativeDnsTtl;
@@ -253,6 +263,7 @@
     size_t maxRequestSize;
     struct {
 	ushortlist *http;
+	ushort bhttp;
 	u_short icp;
 #if USE_HTCP
 	u_short htcp;
@@ -1195,15 +1206,30 @@
 #endif
 };
 
+#ifdef	HPL_REPL
+#include "heap.h"
+#endif	/* HPL_REPL */
 
 /* This structure can be freed while object is purged out from memory */
 struct _MemObject {
-    method_t method;
     char *url;
+    store_client *clients;
+#if HPL_REPL
+    /* 
+     * A MemObject knows where it is in the in-memory heap.
+     */
+    union {
+     heap_node ode;
+     struct _MemObject *ext;
+    } n;
+    StoreEntry *entry;
+#else	/* HPL_REPL */
+    dlink_node lru;
+#endif	/* HPL_REPL */
+    method_t method;
     mem_hdr data_hdr;
     off_t inmem_hi;
     off_t inmem_lo;
-    store_client *clients;
     int nclients;
     struct {
 	off_t queue_offset;	/* relative to in-mem data */
@@ -1222,17 +1248,51 @@
 	void *data;
     } abort;
     char *log_url;
-    dlink_node lru;
     int id;
     ssize_t object_sz;
     size_t swap_hdr_sz;
 };
 
+#ifdef MMAPSTORE
+#define Skey			s->key
+#define Stimestamp		s->timestamp
+#define Slastref		s->lastref
+#define Sexpires		s->expires
+#define Slastmod		s->lastmod
+#define Sswap_file_sz		s->swap_file_sz
+#define Srefcount		s->refcount
+#define Sflag			s->flags
+#define Sswap_file_number	s->swap_file_number
+#else
+#define Skey			key
+#define Stimestamp		timestamp
+#define Slastref		lastref
+#define Sexpires		expires
+#define Slastmod		lastmod
+#define Sswap_file_sz		swap_file_sz
+#define Srefcount		refcount
+#define Sflag			flags
+#define Sswap_file_number	swap_file_number
+#endif
+
 struct _StoreEntry {
     /* first two items must be same as hash_link */
+#ifdef MMAPSTORE
+    storeSwapLogData *s;
+#else
     const cache_key *key;
-    StoreEntry *next;
+#endif
+    StoreEntry *next;		/* for the hash table */
+#ifdef	HPL_REPL
+    union {
+     heap_node ode;
+     StoreEntry *ext;
+    } n;
+#else	/* HPL_REPL */
+    dlink_node lru;
+#endif	/* HPL_REPL */
     MemObject *mem_obj;
+#ifndef MMAPSTORE
     time_t timestamp;
     time_t lastref;
     time_t expires;
@@ -1241,7 +1301,7 @@
     u_short refcount;
     u_short flags;
     int swap_file_number;
-    dlink_node lru;
+#endif
     u_short lock_count;		/* Assume < 65536! */
     mem_status_t mem_status:3;
     ping_status_t ping_status:3;
@@ -1249,14 +1309,31 @@
     swap_status_t swap_status:3;
 };
 
+#ifdef MMAPSTORE
+struct mmapinfo {
+    storeSwapLogData*mmapbase,*mmapend,*mmapmax,*mmapfreelist;
+    char*path;
+    struct mmapinfo*next;
+};
+#endif
+
 struct _SwapDir {
+#ifdef MMAPSTORE
+    struct mmapinfo*mi;
+#endif
     char *path;
     int l1;
     int l2;
+    int low_size;
     int cur_size;
+    int win_size;
     int max_size;
     int suggest;
     fileMap *map;
+#if HPL_REPL
+    heap_p heap;
+    unsigned riddance;
+#endif
     int swaplog_fd;
     struct {
 	unsigned int selected:1;
@@ -1518,16 +1595,18 @@
 };
 
 struct _storeSwapLogData {
-    char op;
-    int swap_file_number;
+    unsigned char key[MD5_DIGEST_CHARS];
+    size_t swap_file_sz;
     time_t timestamp;
     time_t lastref;
     time_t expires;
     time_t lastmod;
-    size_t swap_file_sz;
     u_short refcount;
     u_short flags;
-    unsigned char key[MD5_DIGEST_CHARS];
+#ifndef MMAPSTORE
+    char op;
+#endif
+    int swap_file_number;
 };
 
 /* object to track per-action memory usage (e.g. #idle objects) */
@@ -1550,7 +1629,8 @@
 struct _MemPool {
     const char *label;
     size_t obj_size;
-    Stack pstack;		/* stack for free pointers */
+    void*pstack;		/* stack for free pointers */
+    struct _MemPool *ss;	/* same size free pool */
     MemPoolMeter meter;
 };
 
Index: squid/src/tools.c
diff -u squid/src/tools.c:1.1.1.2 squid/src/tools.c:1.1.1.2.10.1
--- squid/src/tools.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/tools.c	Fri Nov 10 10:44:53 2000
@@ -216,7 +216,10 @@
 {
     struct rusage rusage;
     squid_getrusage(&rusage);
-    fprintf(debug_log, "CPU Usage: %.3f seconds\n", rusage_cputime(&rusage));
+    fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
+	    rusage_cputime(&rusage), 
+	    rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
+	    rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
     fprintf(debug_log, "Maximum Resident Size: %d KB\n",
 	rusage_maxrss(&rusage));
     fprintf(debug_log, "Page faults with physical i/o: %d\n",
@@ -262,7 +265,9 @@
     releaseServerSockets();
     storeDirWriteCleanLogs(0);
     PrintRusage();
+#if 0 /* srb prevent deadlocks */
     dumpMallocStats();
+#endif
     if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
 	/* skip if more than 10 days old */
 	if (Config.adminEmail)
Index: squid/src/url.c
diff -u squid/src/url.c:1.1.1.2 squid/src/url.c:1.1.1.2.10.1
--- squid/src/url.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/url.c	Fri Nov 10 10:44:53 2000
@@ -241,7 +241,7 @@
     /* remove trailing dots from hostnames */
     while ((l = strlen(host)) > 0 && host[--l] == '.')
 	host[l] = '\0';
-    if (Config.appendDomain && !strchr(host, '.'))
+    if (Config.appendDomain && *host && !strchr(host, '.'))
 	strncat(host, Config.appendDomain, SQUIDHOSTNAMELEN);
     if (port == 0) {
 	debug(23, 3) ("urlParse: Invalid port == 0\n");
Index: squid/src/urn.c
diff -u squid/src/urn.c:1.1.1.2 squid/src/urn.c:1.1.1.2.10.1
--- squid/src/urn.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/urn.c	Fri Nov 10 10:44:53 2000
@@ -187,7 +187,7 @@
     int urlcnt = 0;
 
     debug(52, 3) ("urnHandleReply: Called with size=%d.\n", size);
-    if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(urlres_e->Sflag, ENTRY_ABORTED)) {
 	memFree(buf, MEM_4K_BUF);
 	return;
     }
Index: squid/src/wais.c
diff -u squid/src/wais.c:1.1.1.2 squid/src/wais.c:1.1.1.2.28.1
--- squid/src/wais.c:1.1.1.2	Tue Jan 25 19:23:10 2000
+++ squid/src/wais.c	Fri Nov 10 10:44:53 2000
@@ -93,7 +93,7 @@
 #if DELAY_POOLS
     delay_id delay_id = delayMostBytesAllowed(entry->mem_obj);
 #endif
-    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
+    if (EBIT_TEST(entry->Sflag, ENTRY_ABORTED)) {
 	comm_close(fd);
 	return;
     }
@@ -130,7 +130,7 @@
 		waisReadReply, waisState, 0);
 	} else {
 	    ErrorState *err;
-	    EBIT_CLR(entry->flags, ENTRY_CACHABLE);
+	    EBIT_CLR(entry->Sflag, ENTRY_CACHABLE);
 	    storeReleaseRequest(entry);
 	    err = errorCon(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR);
 	    err->xerrno = errno;
@@ -147,7 +147,7 @@
 	comm_close(fd);
     } else if (len == 0) {
 	/* Connection closed; retrieval done. */
-	entry->expires = squid_curtime;
+	entry->Sexpires = squid_curtime;
 	fwdComplete(waisState->fwd);
 	comm_close(fd);
     } else {
@@ -211,9 +211,9 @@
     memBufPrintf(&mb, "\r\n");
     debug(24, 6) ("waisSendRequest: buf: %s\n", mb.buf);
     comm_write_mbuf(fd, mb, waisSendComplete, waisState);
-    if (EBIT_TEST(waisState->entry->flags, ENTRY_CACHABLE))
+    if (EBIT_TEST(waisState->entry->Sflag, ENTRY_CACHABLE))
 	storeSetPublicKey(waisState->entry);	/* Make it public */
-    EBIT_CLR(waisState->entry->flags, ENTRY_FWD_HDR_WAIT);
+    EBIT_CLR(waisState->entry->Sflag, ENTRY_FWD_HDR_WAIT);
 }
 
 void
