*** freespace.c	Sun Apr 24 12:51:49 2005
--- freespace.new.c	Fri May 20 13:13:37 2005
***************
*** 70,75 ****
--- 70,78 ----
  #include "storage/lwlock.h"
  #include "storage/shmem.h"
  
+ #include "utils/relcache.h"
+ #include "utils/lsyscache.h"
+ 
  
  /* Initial value for average-request moving average */
  #define INITIAL_AVERAGE ((Size) (BLCKSZ / 32))
*************** typedef BlockIdData IndexFSMPageData;
*** 123,128 ****
--- 126,132 ----
   *		relfilenode
   *		isIndex
   *		avgRequest
+  *		minRequest
   *		lastPageCount
   *		storedPages
   *		arena data		array of storedPages FSMPageData or IndexFSMPageData
*************** typedef struct FsmCacheRelHeader
*** 152,157 ****
--- 156,162 ----
  	RelFileNode key;			/* hash key (must be first) */
  	bool		isIndex;		/* if true, we store only page numbers */
  	uint32		avgRequest;		/* moving average of space requests */
+ 	uint32		minRequest;		/* minimum of space requests  */
  	int32		lastPageCount;	/* pages passed to RecordRelationFreeSpace */
  	int32		storedPages;	/* # of pages stored in arena */
  } FsmCacheRelHeader;
*************** struct FSMRelation
*** 206,211 ****
--- 211,217 ----
  	FSMRelation *priorPhysical; /* prior rel in arena-storage order */
  	bool		isIndex;		/* if true, we store only page numbers */
  	Size		avgRequest;		/* moving average of space requests */
+ 	Size		minRequest;		/* minimum of space requests */
  	int			lastPageCount;	/* pages passed to RecordRelationFreeSpace */
  	int			firstChunk;		/* chunk # of my first chunk in arena */
  	int			storedPages;	/* # of pages stored in arena */
*************** GetPageWithFreeSpace(RelFileNode *rel, S
*** 385,390 ****
--- 391,398 ----
  
  		cur_avg += ((int) spaceNeeded - cur_avg) / 32;
  		fsmrel->avgRequest = (Size) cur_avg;
+ 		if(fsmrel->minRequest > spaceNeeded)
+ 			fsmrel->minRequest = spaceNeeded;
  	}
  	freepage = find_free_space(fsmrel, spaceNeeded);
  	LWLockRelease(FreeSpaceLock);
*************** RecordAndGetPageWithFreeSpace(RelFileNod
*** 429,434 ****
--- 437,444 ----
  
  		cur_avg += ((int) spaceNeeded - cur_avg) / 32;
  		fsmrel->avgRequest = (Size) cur_avg;
+ 		if(fsmrel->minRequest > spaceNeeded)
+ 			fsmrel->minRequest = spaceNeeded;
  	}
  	/* Do the Get */
  	freepage = find_free_space(fsmrel, spaceNeeded);
*************** DumpFreeSpaceMap(int code, Datum arg)
*** 793,798 ****
--- 803,809 ----
  		relheader.key = fsmrel->key;
  		relheader.isIndex = fsmrel->isIndex;
  		relheader.avgRequest = fsmrel->avgRequest;
+ 		relheader.minRequest = fsmrel->minRequest;
  		relheader.lastPageCount = fsmrel->lastPageCount;
  		relheader.storedPages = fsmrel->storedPages;
  		if (fwrite(&relheader, 1, sizeof(relheader), fp) != sizeof(relheader))
*************** LoadFreeSpaceMap(void)
*** 902,907 ****
--- 913,919 ----
  		if (fread(&relheader, 1, sizeof(relheader), fp) != sizeof(relheader) ||
  			(relheader.isIndex != false && relheader.isIndex != true) ||
  			relheader.avgRequest >= BLCKSZ ||
+ 			relheader.minRequest >= BLCKSZ ||
  			relheader.lastPageCount < 0 ||
  			relheader.storedPages < 0)
  		{
*************** LoadFreeSpaceMap(void)
*** 936,941 ****
--- 948,954 ----
  		 */
  		fsmrel = create_fsm_rel(&relheader.key);
  		fsmrel->avgRequest = relheader.avgRequest;
+ 		fsmrel->minRequest = relheader.minRequest;
  
  		curAlloc = realloc_fsm_rel(fsmrel, relheader.lastPageCount,
  								   relheader.isIndex);
*************** create_fsm_rel(RelFileNode *rel)
*** 1046,1051 ****
--- 1059,1065 ----
  		/* New hashtable entry, initialize it (hash_search set the key) */
  		fsmrel->isIndex = false;	/* until we learn different */
  		fsmrel->avgRequest = INITIAL_AVERAGE;
+ 		fsmrel->minRequest = BLCKSZ-1;
  		fsmrel->lastPageCount = 0;
  		fsmrel->firstChunk = -1;	/* no space allocated */
  		fsmrel->storedPages = 0;
*************** find_free_space(FSMRelation *fsmrel, Siz
*** 1268,1273 ****
--- 1282,1315 ----
  			pageIndex = 0;
  	}
  
+ 	if(spaceNeeded >= fsmrel->minRequest && fsmrel->storedPages > 0)
+ 	{
+ 		/* Free space becomes empty.  */
+ 
+ 		/* Notify. */
+ 		Relation r;
+ 		r = RelationIdGetRelation(fsmrel->key.relNode);
+ 		if(r)
+ 		{
+ 			elog(LOG, "FreeSpace for \"%s.%s\" becomes empty. (stored=%d, avg=%d, min=%d)",
+ 				get_namespace_name(RelationGetNamespace(r)),
+ 				RelationGetRelationName(r),
+ 				fsmrel->storedPages, fsmrel->avgRequest, fsmrel->minRequest);
+ 			RelationClose(r);
+ 		}
+ 		else
+ 		{
+ 			elog(LOG, "FreeSpace for %u/%u/%u becomes empty. (stored=%d, avg=%d, min=%d)",
+ 				fsmrel->key.spcNode, fsmrel->key.dbNode, fsmrel->key.relNode,
+ 				fsmrel->storedPages, fsmrel->avgRequest, fsmrel->minRequest);
+ 		}
+ 
+ 		/* Detach empty fsm relation.  */
+ 		fsmrel->storedPages = 0;
+ 		/* XXX: or delete_fsm_rel(fsmrel) */
+ 		/* XXX: or kick autovacuum */
+ 	}
+ 
  	return InvalidBlockNumber;	/* nothing found */
  }
  
*************** DumpFreeSpace(void)
*** 1876,1885 ****
  	for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
  	{
  		relNum++;
! 		fprintf(stderr, "Map %d: rel %u/%u/%u isIndex %d avgRequest %u lastPageCount %d nextPage %d\nMap= ",
  				relNum,
  			fsmrel->key.spcNode, fsmrel->key.dbNode, fsmrel->key.relNode,
! 				(int) fsmrel->isIndex, fsmrel->avgRequest,
  				fsmrel->lastPageCount, fsmrel->nextPage);
  		if (fsmrel->isIndex)
  		{
--- 1918,1927 ----
  	for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
  	{
  		relNum++;
! 		fprintf(stderr, "Map %d: rel %u/%u/%u isIndex %d avgRequest %d minRequest %d lastPageCount %d nextPage %d\nMap= ",
  				relNum,
  			fsmrel->key.spcNode, fsmrel->key.dbNode, fsmrel->key.relNode,
! 				(int) fsmrel->isIndex, fsmrel->avgRequest, fsmrel->minRequest,
  				fsmrel->lastPageCount, fsmrel->nextPage);
  		if (fsmrel->isIndex)
  		{