Index: src/cf.data.pre
===================================================================
RCS file: /server/cvs-server/squid/squid/src/cf.data.pre,v
retrieving revision 1.363
diff -u -r1.363 cf.data.pre
--- src/cf.data.pre	3 Aug 2006 02:31:11 -0000	1.363
+++ src/cf.data.pre	11 Aug 2006 04:55:21 -0000
@@ -1162,6 +1162,14 @@
 	number of memory-only buffers that COSS will use.  The default value
 	is 10, which will use a maximum of 10MB of memory for buffers.
 
+	maxfullbufs=n defines the maximum number of stripes a COSS partition 
+	will have in memory waiting to be freed (either because the disk is
+	under load and the stripe is unwritten, or because clients are still 
+	transferring data from objects using the memory).  In order to try 
+	and maintain a good hit rate under load, COSS will reserve the last 
+	2 full stripes for object hits. (ie a COSS cache_dir will reject 
+	new objects when the number of full stripes is 2 less than maxfullbufs)
+
 	Common options:
 
 	read-only, this cache_dir is read only.
Index: src/fs/coss/store_coss.h
===================================================================
RCS file: /server/cvs-server/squid/squid/src/fs/coss/store_coss.h,v
retrieving revision 1.11
diff -u -r1.11 store_coss.h
--- src/fs/coss/store_coss.h	3 Aug 2006 02:31:12 -0000	1.11
+++ src/fs/coss/store_coss.h	11 Aug 2006 04:55:22 -0000
@@ -145,6 +145,9 @@
     float minumum_overwrite_pct;
     int minimum_stripe_distance;
     int numstripes;
+    int maxfullstripes;
+    int hitonlyfullstripes;
+    int numfullstripes;
     int sizerange_max;
     int sizerange_min;
     struct _cossstripe *stripes;
Index: src/fs/coss/store_dir_coss.c
===================================================================
RCS file: /server/cvs-server/squid/squid/src/fs/coss/store_dir_coss.c,v
retrieving revision 1.52
diff -u -r1.52 store_dir_coss.c
--- src/fs/coss/store_dir_coss.c	5 Aug 2006 15:36:24 -0000	1.52
+++ src/fs/coss/store_dir_coss.c	11 Aug 2006 04:55:23 -0000
@@ -44,6 +44,7 @@
 #endif
 
 #define STORE_META_BUFSZ 4096
+#define HITONLY_BUFS 2
 
 int n_coss_dirs = 0;
 int max_coss_dir_size = 0;
@@ -97,10 +98,12 @@
 static void storeCossDirParseOverwritePct(SwapDir *, const char *, const char *, int);
 static void storeCossDirParseMaxWaste(SwapDir *, const char *, const char *, int);
 static void storeCossDirParseMemOnlyBufs(SwapDir *, const char *, const char *, int);
+static void storeCossDirParseMaxFullBufs(SwapDir *, const char *, const char *, int);
 static void storeCossDirDumpBlkSize(StoreEntry *, const char *, SwapDir *);
 static void storeCossDirDumpOverwritePct(StoreEntry *, const char *, SwapDir *);
 static void storeCossDirDumpMaxWaste(StoreEntry *, const char *, SwapDir *);
 static void storeCossDirDumpMemOnlyBufs(StoreEntry *, const char *, SwapDir *);
+static void storeCossDirDumpMaxFullBufs(StoreEntry *, const char *, SwapDir *);
 static OBJH storeCossStats;
 
 static void storeDirCoss_StartDiskRebuild(RebuildState * rb);
@@ -114,6 +117,7 @@
     {"overwrite-percent", storeCossDirParseOverwritePct, storeCossDirDumpOverwritePct},
     {"max-stripe-waste", storeCossDirParseMaxWaste, storeCossDirDumpMaxWaste},
     {"membufs", storeCossDirParseMemOnlyBufs, storeCossDirDumpMemOnlyBufs},
+    {"maxfullbufs", storeCossDirParseMaxFullBufs, storeCossDirDumpMaxFullBufs},
     {NULL, NULL}
 };
 
@@ -624,11 +628,17 @@
     loadav += disk_size_weight * current_write_weight;
 
     /* Remove the folowing check if we want to allow COSS partitions to get
-     * "too busy"
+     * too busy to accept new objects
      */
     if (loadav > MAX_LOAD_VALUE)
 	loadav = MAX_LOAD_VALUE;
 
+    /* Finally, we want to reject all new obects if the number of full stripes
+     * is too large
+     */
+    if (cs->numfullstripes > cs->hitonlyfullstripes)
+	loadav += MAX_LOAD_VALUE;
+
     debug(47, 9) ("storeAufsDirCheckObj: load=%d\n", loadav);
     return loadav;
 #else
@@ -802,6 +812,15 @@
     }
     cs->minimum_stripe_distance = cs->numstripes * cs->minumum_overwrite_pct;
 
+    /* Make sure cs->maxfull has a default value */
+    if(cs->maxfullstripes == 0)
+	cs->maxfullstripes = cs->numstripes;
+
+    /* We will reject new objects (ie go into hit-only mode)
+     * if there are <= 2 stripes available
+     */
+    cs->hitonlyfullstripes = cs->maxfullstripes - HITONLY_BUFS;
+
     debug(47, 0) ("COSS: number of memory-only stripes %d of %d bytes each\n", cs->nummemstripes, COSS_MEMBUF_SZ);
     cs->memstripes = xcalloc(cs->nummemstripes, sizeof(struct _cossstripe));
     for (i = 0; i < cs->nummemstripes; i++) {
@@ -810,7 +829,7 @@
 	cs->memstripes[i].numdiskobjs = -1;
     }
 
-    /* Update the max size (used for load calculations */
+    /* Update the max size (used for load calculations) */
     if (sd->max_size > max_coss_dir_size)
 	max_coss_dir_size = sd->max_size;
 }
@@ -846,6 +865,18 @@
 }
 
 static void
+storeCossDirParseMaxFullBufs(SwapDir * sd, const char *name, const char *value, int reconfiguring)
+{
+    CossInfo *cs = sd->fsdata;
+    int maxfull = atoi(value);
+    if (maxfull <= HITONLY_BUFS)
+	fatalf("COSS ERROR: There must be more than %d maxfullbufs\n", HITONLY_BUFS);
+    if (maxfull > 500)
+	fatal("COSS ERROR: Squid will likely use too much memory if it ever used 500MB worth of full buffers\n");
+    cs->maxfullstripes = maxfull;
+}
+
+static void
 storeCossDirParseMemOnlyBufs(SwapDir * sd, const char *name, const char *value, int reconfiguring)
 {
     CossInfo *cs = sd->fsdata;
@@ -918,6 +949,13 @@
 }
 
 static void
+storeCossDirDumpMaxFullBufs(StoreEntry * e, const char *option, SwapDir * sd)
+{
+    CossInfo *cs = sd->fsdata;
+    storeAppendPrintf(e, " maxfullbufs=%d MB", cs->maxfullstripes);
+}
+
+static void
 storeCossDirDumpMemOnlyBufs(StoreEntry * e, const char *option, SwapDir * sd)
 {
     CossInfo *cs = sd->fsdata;
Index: src/fs/coss/store_io_coss.c
===================================================================
RCS file: /server/cvs-server/squid/squid/src/fs/coss/store_io_coss.c,v
retrieving revision 1.27
diff -u -r1.27 store_io_coss.c
--- src/fs/coss/store_io_coss.c	5 Aug 2006 15:06:29 -0000	1.27
+++ src/fs/coss/store_io_coss.c	11 Aug 2006 04:55:25 -0000
@@ -162,14 +162,29 @@
     /* Since we're not supporting NOTIFY anymore, lets fail */
     assert(which != COSS_ALLOC_NOTIFY);
 
-    /* Check if we have overflowed the disk .. */
-    if ((cs->current_offset + allocsize) > ((off_t) SD->max_size << 10)) {
+    /* Check to see if we need to allocate a membuf to start */
+    if (cs->current_membuf == NULL) {
+	if(cs->curstripe < cs->numstripes)
+	    newmb = storeCossCreateMemBuf(SD, cs->curstripe + 1, checkf, &coll);
+	else
+	    newmb = storeCossCreateMemBuf(SD, 0, checkf, &coll);
+
+	cs->current_membuf = newmb;
+	if (newmb == NULL) {
+	    cs->sizerange_max = SD->max_objsize;
+	    return -1;
+	}
+	cs->current_offset = cs->current_membuf->diskstart;
+
+	/* Check if we have overflowed the disk .. */
+    } else if ((cs->current_offset + allocsize) > ((off_t) SD->max_size << 10)) {
 	/*
 	 * tried to allocate past the end of the disk, so wrap
 	 * back to the beginning
 	 */
 	coss_stats.disk_overflows++;
 	cs->current_membuf->flags.full = 1;
+	cs->numfullstripes++;
 	cs->current_membuf->diskend = cs->current_offset;
 	storeCossMaybeWriteMemBuf(SD, cs->current_membuf);
 	/* cs->current_membuf may be invalid at this point */
@@ -178,6 +193,10 @@
 
 	newmb = storeCossCreateMemBuf(SD, 0, checkf, &coll);
 	cs->current_membuf = newmb;
+	if (newmb == NULL) {
+	    cs->sizerange_max = SD->max_objsize;
+	    return -1;
+	}
 
 	/* Check if we have overflowed the MemBuf */
     } else if ((cs->current_offset + allocsize) >= cs->current_membuf->diskend) {
@@ -186,6 +205,7 @@
 	 */
 	coss_stats.stripe_overflows++;
 	cs->current_membuf->flags.full = 1;
+	cs->numfullstripes++;
 	cs->current_offset = cs->current_membuf->diskend;
 	storeCossMaybeWriteMemBuf(SD, cs->current_membuf);
 	/* cs->current_membuf may be invalid at this point */
@@ -194,6 +214,10 @@
 	assert(cs->curstripe < (cs->numstripes - 1));
 	newmb = storeCossCreateMemBuf(SD, cs->curstripe + 1, checkf, &coll);
 	cs->current_membuf = newmb;
+	if (newmb == NULL) {
+	    cs->sizerange_max = SD->max_objsize;
+	    return -1;
+	}
     }
     /* If we didn't get a collision, then update the current offset and return it */
     if (coll == 0) {
@@ -372,6 +396,10 @@
 	} else {
 	    debug(79, 3) ("storeCossOpen: %s memory miss - not reallocating (Current stripe : %d  Object in stripe : %d)\n", SD->path, cs->curstripe, storeCossFilenoToStripe(cs, sio->swap_filen));
 	    nf = storeCossMemOnlyAllocate(SD, e);
+	    if (nf == -1) {
+		debug(79, 3) ("storeCossOpen: %s memory miss - reallocating because all membufs are in use\n", SD->path);
+		nf = storeCossAllocate(SD, e, COSS_ALLOC_REALLOC);
+	    }
 	}
 	if (nf == -1) {
 	    /* We have to clean up neatly .. */
@@ -732,6 +760,10 @@
 	    assert(cs->memstripes[mb->stripe].membuf == mb);
 	    cs->memstripes[mb->stripe].membuf = NULL;
 	}
+	else
+	{
+	    cs->numfullstripes--;
+	}
 	debug(79, 3) ("storeCossMaybeFreeBuf: %p: lockcount = 0, written = 1: marking dead\n", mb);
 	mb->flags.dead = 1;
 	dlinkDelete(&mb->node, &cs->membufs);
@@ -807,6 +839,7 @@
     CossInfo *cs = (CossInfo *) SD->fsdata;
     off_t start;
     int stripe;
+    static time_t last_warn = 0;
 
     /* TODO: Maybe make this a simple search for a free membuf */
     for (stripe = 0; stripe < cs->nummemstripes; stripe++) {
@@ -814,7 +847,10 @@
 	    break;
     }
     if (stripe >= cs->nummemstripes) {
-	debug(79, 1) ("storeCossCreateMemOnlyBuf: no free membufs.  You may beed to increase the value of membufs on the %s cache_dir\n", SD->path);
+	if (last_warn + 15 < squid_curtime) {
+	    debug(79, 1) ("storeCossCreateMemOnlyBuf: no free membufs.  You may need to increase the value of membufs on the %s cache_dir\n", SD->path);
+	    last_warn = squid_curtime;
+	}
 	return NULL;
     }
     cs->curmemstripe = stripe;
@@ -854,8 +890,17 @@
     CossInfo *cs = (CossInfo *) SD->fsdata;
     off_t start = (off_t) stripe * COSS_MEMBUF_SZ;
     off_t o;
+    static time_t last_warn = 0;
     assert(start >= 0);
 
+    if (cs->numfullstripes >= cs->maxfullstripes) {
+	if (last_warn + 15 < squid_curtime) {
+	    debug(79, 1) ("storeCossCreateMemBuf: Maximum number of full buffers reached on %s. You may need to increase the maxfullbuffers option for this cache_dir\n", SD->path);
+	    last_warn = squid_curtime;
+	}
+	return NULL;
+    }
+
     /* No, we shouldn't ever try to create a membuf if we haven't freed the one on
      * this stripe. Grr */
     assert(cs->stripes[stripe].membuf == NULL);
