diff -dcrpN --exclude=configure pgsql.orig/configure.in pgsql/configure.in
*** pgsql.orig/configure.in	2008-05-20 10:26:45.000000000 +0200
--- pgsql/configure.in	2008-06-19 10:17:09.000000000 +0200
*************** AC_SUBST(TAS)
*** 474,479 ****
--- 474,507 ----
  
  
  #
+ # Use posix_fadvise() to tune readahead (--enable-posix-fadvise)
+ #
+ AC_MSG_CHECKING([whether to enable posix_fadvise() support])
+ PGAC_ARG_BOOL(enable, posix-fadvise, yes,    [  --disable-posix-fadvise disable posix_fadvise() support],
+ 		[AC_TRY_RUN([
+ 			#define _XOPEN_SOURCE 600
+ 			#include <sys/types.h>
+ 			#include <sys/stat.h>
+ 			#include <fcntl.h>
+ 			int             fd, ret;
+ 
+ 			int main(void)
+ 			{
+ 				fd = open("configure", O_RDONLY);
+ 				ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+ 				close(fd);
+ 				return ret;
+ 			}],
+ 			[AC_DEFINE([USE_POSIX_FADVISE], 1,
+ 				[Define to 1 if you want posix_fadvise() support. (--enable-posix-fadvise)])
+ 			 AC_MSG_RESULT(yes)],
+ 			[AC_MSG_RESULT(no)],
+ 			[AC_MSG_RESULT(no)]
+ 		)],
+ 		[AC_MSG_RESULT(no)])
+ 
+ 
+ #
  # Automatic dependency tracking
  #
  PGAC_ARG_BOOL(enable, depend, no, [  --enable-depend         turn on automatic dependency tracking],
diff -dcrpN --exclude=configure pgsql.orig/doc/src/sgml/config.sgml pgsql/doc/src/sgml/config.sgml
*** pgsql.orig/doc/src/sgml/config.sgml	2008-06-19 10:02:35.000000000 +0200
--- pgsql/doc/src/sgml/config.sgml	2008-06-19 13:01:59.000000000 +0200
*************** archive_command = 'copy "%p" /mnt/server
*** 2041,2046 ****
--- 2041,2064 ----
        </listitem>
       </varlistentry>
  
+      <varlistentry id="guc-preread-pages-bitmapscan" xreflabel="effective_cache_size">
+       <term><varname>preread_pages_bitmapscan</varname> (<type>integer</type>)</term>
+       <indexterm>
+        <primary><varname>preread_pages_bitmapscan</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         <productname>PostgreSQL</productname> can give hints to POSIX compatible
+         operating systems using posix_fadvise(2) to pre-read pages that will
+         be needed in the near future. Reading the pages into the OS kernel's
+         disk buffer will be done asynchronically while <productname>PostgreSQL</productname>
+         works on pages which are already in memory. This may speed up bitmap scans
+         considerably. This setting only applies to bitmap scans.
+         Hinting for sequential scans is also used but no GUC is needed in this case.
+        </para>      
+       </listitem>   
+      </varlistentry>
+ 
       </variablelist>
  
      </sect2>
diff -dcrpN --exclude=configure pgsql.orig/src/backend/access/gin/ginget.c pgsql/src/backend/access/gin/ginget.c
*** pgsql.orig/src/backend/access/gin/ginget.c	2008-06-19 10:02:36.000000000 +0200
--- pgsql/src/backend/access/gin/ginget.c	2008-06-19 11:44:27.000000000 +0200
*************** startScanEntry(Relation index, GinState 
*** 314,320 ****
  
  		if ( entry->partialMatch && !tbm_is_empty(entry->partialMatch) )
  		{
! 			tbm_begin_iterate(entry->partialMatch);
  			entry->isFinished = FALSE;
  		}
  	}
--- 314,320 ----
  
  		if ( entry->partialMatch && !tbm_is_empty(entry->partialMatch) )
  		{
! 			entry->partialMatchIterator = tbm_begin_iterate(entry->partialMatch);
  			entry->isFinished = FALSE;
  		}
  	}
*************** entryGetItem(Relation index, GinScanEntr
*** 532,538 ****
  		{
  			if ( entry->partialMatchResult == NULL || entry->offset >= entry->partialMatchResult->ntuples )
  			{
! 				entry->partialMatchResult = tbm_iterate( entry->partialMatch );
  
  				if ( entry->partialMatchResult == NULL )
  				{
--- 532,538 ----
  		{
  			if ( entry->partialMatchResult == NULL || entry->offset >= entry->partialMatchResult->ntuples )
  			{
! 				entry->partialMatchResult = tbm_iterate( entry->partialMatchIterator );
  
  				if ( entry->partialMatchResult == NULL )
  				{
diff -dcrpN --exclude=configure pgsql.orig/src/backend/access/heap/heapam.c pgsql/src/backend/access/heap/heapam.c
*** pgsql.orig/src/backend/access/heap/heapam.c	2008-06-19 10:02:37.000000000 +0200
--- pgsql/src/backend/access/heap/heapam.c	2008-06-19 12:33:35.000000000 +0200
***************
*** 54,59 ****
--- 54,60 ----
  #include "miscadmin.h"
  #include "pgstat.h"
  #include "storage/bufmgr.h"
+ #include "storage/fd.h"
  #include "storage/lmgr.h"
  #include "storage/procarray.h"
  #include "storage/smgr.h"
*************** heapgetpage(HeapScanDesc scan, BlockNumb
*** 197,202 ****
--- 198,207 ----
  
  	Assert(page < scan->rs_nblocks);
  
+ 	/* advise the kernel to prefetch data from the disk
+  	 * we do so to cheat the kernel prefetch code */
+ 	AdviseBuffer(scan->rs_rd, page, BUFFER_ADV_SEQUENTIAL);
+ 
  	/* release previous scan buffer, if any */
  	if (BufferIsValid(scan->rs_cbuf))
  	{
diff -dcrpN --exclude=configure pgsql.orig/src/backend/access/nbtree/nbtsearch.c pgsql/src/backend/access/nbtree/nbtsearch.c
*** pgsql.orig/src/backend/access/nbtree/nbtsearch.c	2008-06-19 10:02:37.000000000 +0200
--- pgsql/src/backend/access/nbtree/nbtsearch.c	2008-06-19 10:48:18.000000000 +0200
***************
*** 20,28 ****
--- 20,30 ----
  #include "access/relscan.h"
  #include "pgstat.h"
  #include "storage/bufmgr.h"
+ #include "storage/fd.h"
  #include "utils/lsyscache.h"
  #include "utils/rel.h"
  
+ extern int preread_pages_bitmapscan;
  
  static bool _bt_readpage(IndexScanDesc scan, ScanDirection dir,
  			 OffsetNumber offnum);
*************** _bt_readpage(IndexScanDesc scan, ScanDir
*** 1068,1073 ****
--- 1070,1086 ----
  		so->currPos.itemIndex = MaxIndexTuplesPerPage - 1;
  	}
  
+ 	if (!preread_pages_bitmapscan)
+ 		/* don't preread */;
+ 	else if (ScanDirectionIsForward(dir) && 
+ 			 so->currPos.moreRight && 
+ 			 !P_RIGHTMOST(opaque))
+ 		AdviseBuffer(scan->indexRelation, opaque->btpo_next, BUFFER_ADV_WILLNEED);
+ 	else if (ScanDirectionIsBackward(dir) && 
+ 			 so->currPos.moreLeft && 
+ 			 !P_LEFTMOST(opaque))
+ 		AdviseBuffer(scan->indexRelation, opaque->btpo_prev, BUFFER_ADV_WILLNEED);
+ 
  	return (so->currPos.firstItem <= so->currPos.lastItem);
  }
  
diff -dcrpN --exclude=configure pgsql.orig/src/backend/access/transam/xlog.c pgsql/src/backend/access/transam/xlog.c
*** pgsql.orig/src/backend/access/transam/xlog.c	2008-06-19 10:02:38.000000000 +0200
--- pgsql/src/backend/access/transam/xlog.c	2008-06-19 10:17:09.000000000 +0200
*************** XLogNeedsFlush(XLogRecPtr record)
*** 1932,1937 ****
--- 1932,1946 ----
   * Note: errors here are ERROR not PANIC because we might or might not be
   * inside a critical section (eg, during checkpoint there is no reason to
   * take down the system on failure).  They will promote to PANIC if we are
+  *
+  * WAL segment files will not be re-read in normal operation, so we advise
+  * OS to release any cached pages.	But do not do so if WAL archiving is
+  * active, because archiver process could use the cache to read the WAL
+  * segment.  This is done by using posix_fadvise() where supported,
+  * otherwise the OS is not advised.
+  *
+  * While O_DIRECT works for O_SYNC, posix_fadvise() works for fsync() and
+  * O_SYNC, and some platforms only have posix_fadvise().
   * in a critical section.
   */
  static int
*************** XLogFileInit(uint32 log, uint32 seg,
*** 1965,1971 ****
--- 1974,1986 ----
  								path, log, seg)));
  		}
  		else
+ 		{
+ #ifdef USE_POSIX_FADVISE
+ 			if (!XLogArchivingActive())
+ 				posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
+ #endif
  			return fd;
+ 		}
  	}
  
  	/*
*************** XLogFileInit(uint32 log, uint32 seg,
*** 1987,1992 ****
--- 2002,2012 ----
  		ereport(ERROR,
  				(errcode_for_file_access(),
  				 errmsg("could not create file \"%s\": %m", tmppath)));
+ #ifdef USE_POSIX_FADVISE
+ 	if (!XLogArchivingActive())
+ 		posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
+ #endif
+ 
  
  	/*
  	 * Zero-fill the file.	We have to do this the hard way to ensure that all
*************** XLogFileInit(uint32 log, uint32 seg,
*** 2065,2070 ****
--- 2085,2095 ----
  				(errcode_for_file_access(),
  		   errmsg("could not open file \"%s\" (log file %u, segment %u): %m",
  				  path, log, seg)));
+ #ifdef USE_POSIX_FADVISE
+ 	if (!XLogArchivingActive())
+ 		posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
+ #endif
+ 
  
  	return fd;
  }
*************** XLogFileClose(void)
*** 2385,2415 ****
  {
  	Assert(openLogFile >= 0);
  
- 	/*
- 	 * posix_fadvise is problematic on many platforms: on older x86 Linux it
- 	 * just dumps core, and there are reports of problems on PPC platforms as
- 	 * well.  The following is therefore disabled for the time being. We could
- 	 * consider some kind of configure test to see if it's safe to use, but
- 	 * since we lack hard evidence that there's any useful performance gain to
- 	 * be had, spending time on that seems unprofitable for now.
- 	 */
- #ifdef NOT_USED
- 
- 	/*
- 	 * WAL segment files will not be re-read in normal operation, so we advise
- 	 * OS to release any cached pages.	But do not do so if WAL archiving is
- 	 * active, because archiver process could use the cache to read the WAL
- 	 * segment.
- 	 *
- 	 * While O_DIRECT works for O_SYNC, posix_fadvise() works for fsync() and
- 	 * O_SYNC, and some platforms only have posix_fadvise().
- 	 */
- #if defined(HAVE_DECL_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED)
- 	if (!XLogArchivingActive())
- 		posix_fadvise(openLogFile, 0, 0, POSIX_FADV_DONTNEED);
- #endif
- #endif   /* NOT_USED */
- 
  	if (close(openLogFile))
  		ereport(PANIC,
  				(errcode_for_file_access(),
--- 2410,2415 ----
diff -dcrpN --exclude=configure pgsql.orig/src/backend/commands/explain.c pgsql/src/backend/commands/explain.c
*** pgsql.orig/src/backend/commands/explain.c	2008-05-15 09:16:12.000000000 +0200
--- pgsql/src/backend/commands/explain.c	2008-06-19 10:17:09.000000000 +0200
*************** explain_outNode(StringInfo str,
*** 746,751 ****
--- 746,761 ----
  						   ((Scan *) plan)->scanrelid,
  						   outer_plan, NULL,
  						   str, indent, es);
+ 			if (es->printAnalyze && 
+ 				planstate->instrument && 
+ 				planstate->instrument->nloops > 0)
+ 			{
+ 				BitmapHeapScanState *bmhs_state = (BitmapHeapScanState*)planstate;
+ 				Assert(IsA(planstate, BitmapHeapScanState));
+ 				for (i = 0; i < indent; i++)
+ 					appendStringInfo(str, "  ");
+ 				appendStringInfo(str, "  Preread target: %d\n", bmhs_state->preread_target);
+ 			}
  			/* FALL THRU */
  		case T_SeqScan:
  		case T_FunctionScan:
diff -dcrpN --exclude=configure pgsql.orig/src/backend/executor/nodeBitmapHeapscan.c pgsql/src/backend/executor/nodeBitmapHeapscan.c
*** pgsql.orig/src/backend/executor/nodeBitmapHeapscan.c	2008-06-19 10:02:39.000000000 +0200
--- pgsql/src/backend/executor/nodeBitmapHeapscan.c	2008-06-19 10:47:41.000000000 +0200
***************
*** 41,50 ****
--- 41,53 ----
  #include "executor/nodeBitmapHeapscan.h"
  #include "pgstat.h"
  #include "storage/bufmgr.h"
+ #include "storage/fd.h"
  #include "utils/memutils.h"
  #include "utils/snapmgr.h"
  #include "utils/tqual.h"
  
+ /* GUC */
+ int preread_pages_bitmapscan = 64;
  
  static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
  static void bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres);
*************** BitmapHeapNext(BitmapHeapScanState *node
*** 122,128 ****
  		node->tbm = tbm;
  		node->tbmres = tbmres = NULL;
  
! 		tbm_begin_iterate(tbm);
  	}
  
  	for (;;)
--- 125,134 ----
  		node->tbm = tbm;
  		node->tbmres = tbmres = NULL;
  
! 		node->results_iterator = tbm_begin_iterate(tbm);
! 		node->preread_iterator = tbm_begin_iterate(tbm);
! 		node->preread_pages_bitmapscan = 0;
! 		node->preread_target = 0;
  	}
  
  	for (;;)
*************** BitmapHeapNext(BitmapHeapScanState *node
*** 135,147 ****
  		 */
  		if (tbmres == NULL)
  		{
! 			node->tbmres = tbmres = tbm_iterate(tbm);
  			if (tbmres == NULL)
  			{
  				/* no more entries in the bitmap */
  				break;
  			}
  
  			/*
  			 * Ignore any claimed entries past what we think is the end of the
  			 * relation.  (This is probably not necessary given that we got at
--- 141,178 ----
  		 */
  		if (tbmres == NULL)
  		{
! 			node->tbmres = tbmres = tbm_iterate(node->results_iterator);
! 
  			if (tbmres == NULL)
  			{
+ 				elog(DEBUG2, "no more entries in bitmap");
  				/* no more entries in the bitmap */
  				break;
  			}
  
+ 			if (node->preread_pages_bitmapscan > 0)
+ 				node->preread_pages_bitmapscan  -= 1; 
+ 			else
+ 			{
+ 				/* we don't have any pages preread so make sure to advance the
+ 				 * preread iterator as well so we don't pull out stale pages
+ 				 * later. */
+ 				TBMIterateResult *tbmpre = tbm_iterate(node->preread_iterator);
+ 				Assert(tbmpre->blockno == tbmres->blockno);
+ 			}
+ 
+ 			/* try to ramp up quickly if we're reading tuples spread across many pages */
+ 			if (node->preread_target >= preread_pages_bitmapscan)
+ 				;
+ 			else if (node->preread_target >= preread_pages_bitmapscan / 2)
+ 				node->preread_target = preread_pages_bitmapscan;
+ 			else if (node->preread_target > 0)
+ 				node->preread_target *= 2;
+ 			else
+ 				node->preread_target = 1;
+ 
+ 			elog(DEBUG1, "preread_pages target for bitmap scan: %d", node->preread_target);
+ 
  			/*
  			 * Ignore any claimed entries past what we think is the end of the
  			 * relation.  (This is probably not necessary given that we got at
*************** BitmapHeapNext(BitmapHeapScanState *node
*** 170,175 ****
--- 201,222 ----
  			 * Continuing in previously obtained page; advance rs_cindex
  			 */
  			scan->rs_cindex++;
+ 
+ 			/* try to preread at least a few pages even before we get to the
+ 			 * second page if we don't stop reading after the first tuple */
+ 			if (node->preread_target < preread_pages_bitmapscan)
+ 				node->preread_target += 1;
+ 		}
+ 
+ 		while (node->preread_pages_bitmapscan + 1 < node->preread_target) {
+ 			TBMIterateResult *tbmpre = tbm_iterate(node->preread_iterator);
+ 			if (tbmpre == NULL) {
+ 				/* no more entries in the bitmap to preread */
+ 				node->preread_pages_bitmapscan = INT_MAX;
+ 				break;
+ 			}
+ 			node->preread_pages_bitmapscan  += 1;
+ 			AdviseBuffer(scan->rs_rd, tbmpre->blockno, BUFFER_ADV_WILLNEED);
  		}
  
  		/*
diff -dcrpN --exclude=configure pgsql.orig/src/backend/executor/nodeIndexscan.c pgsql/src/backend/executor/nodeIndexscan.c
*** pgsql.orig/src/backend/executor/nodeIndexscan.c	2008-06-19 10:02:39.000000000 +0200
--- pgsql/src/backend/executor/nodeIndexscan.c	2008-06-19 10:17:09.000000000 +0200
*************** ExecIndexEvalArrayKeys(ExprContext *econ
*** 290,296 ****
  	/* We want to keep the arrays in per-tuple memory */
  	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
  
! 	for (j = 0; j < numArrayKeys; j++)
  	{
  		ScanKey		scan_key = arrayKeys[j].scan_key;
  		ExprState  *array_expr = arrayKeys[j].array_expr;
--- 290,296 ----
  	/* We want to keep the arrays in per-tuple memory */
  	oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
  
! 	for (j = numArrayKeys-1; j >= 0; j--)
  	{
  		ScanKey		scan_key = arrayKeys[j].scan_key;
  		ExprState  *array_expr = arrayKeys[j].array_expr;
diff -dcrpN --exclude=configure pgsql.orig/src/backend/nodes/tidbitmap.c pgsql/src/backend/nodes/tidbitmap.c
*** pgsql.orig/src/backend/nodes/tidbitmap.c	2008-04-11 12:48:00.000000000 +0200
--- pgsql/src/backend/nodes/tidbitmap.c	2008-06-19 11:32:26.000000000 +0200
*************** struct TIDBitmap
*** 139,144 ****
--- 139,150 ----
  	/* the remaining fields are used while producing sorted output: */
  	PagetableEntry **spages;	/* sorted exact-page list, or NULL */
  	PagetableEntry **schunks;	/* sorted lossy-chunk list, or NULL */
+ };
+ 
+ 
+ struct TBMIterator
+ {
+ 	struct TIDBitmap   *tbm;	/* TIDBitmap we're iterating over */
  	int			spageptr;		/* next spages index */
  	int			schunkptr;		/* next schunks index */
  	int			schunkbit;		/* next bit to check in current schunk */
*************** tbm_create(long maxbytes)
*** 172,183 ****
  	TIDBitmap  *tbm;
  	long		nbuckets;
  
! 	/*
! 	 * Create the TIDBitmap struct, with enough trailing space to serve the
! 	 * needs of the TBMIterateResult sub-struct.
! 	 */
! 	tbm = (TIDBitmap *) palloc(sizeof(TIDBitmap) +
! 							   MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
  	/* Zero all the fixed fields */
  	MemSetAligned(tbm, 0, sizeof(TIDBitmap));
  
--- 178,184 ----
  	TIDBitmap  *tbm;
  	long		nbuckets;
  
! 	tbm = (TIDBitmap *) palloc(sizeof(TIDBitmap));
  	/* Zero all the fixed fields */
  	MemSetAligned(tbm, 0, sizeof(TIDBitmap));
  
*************** tbm_is_empty(const TIDBitmap *tbm)
*** 537,564 ****
   * of the bitmap.  However, you can call this multiple times to scan the
   * contents repeatedly.
   */
! void
  tbm_begin_iterate(TIDBitmap *tbm)
  {
  	HASH_SEQ_STATUS status;
  	PagetableEntry *page;
  	int			npages;
  	int			nchunks;
  
  	tbm->iterating = true;
  
  	/*
  	 * Reset iteration pointers.
  	 */
! 	tbm->spageptr = 0;
! 	tbm->schunkptr = 0;
! 	tbm->schunkbit = 0;
  
  	/*
! 	 * Nothing else to do if no entries, nor if we don't have a hashtable.
  	 */
! 	if (tbm->nentries == 0 || tbm->status != TBM_HASH)
! 		return;
  
  	/*
  	 * Create and fill the sorted page lists if we didn't already.
--- 538,582 ----
   * of the bitmap.  However, you can call this multiple times to scan the
   * contents repeatedly.
   */
! TBMIterator *
  tbm_begin_iterate(TIDBitmap *tbm)
  {
  	HASH_SEQ_STATUS status;
  	PagetableEntry *page;
  	int			npages;
  	int			nchunks;
+ 	TBMIterator	   *iterator;
  
  	tbm->iterating = true;
  
  	/*
+ 	 * Nothing else to do if no entries
+ 	 */
+ 	if (tbm->nentries == 0)
+ 		return NULL;
+ 
+ 	/*
+ 	 * Create the TBMIterator struct, with enough trailing space to serve the
+ 	 * needs of the TBMIterateResult sub-struct.
+ 	 *
+ 	 * FIXME I don't like that this is using tbm->mcxt. You might want to
+ 	 * iterate many times and throw away the iterators long before the tbm.
+ 	 */
+ 	iterator = MemoryContextAlloc(tbm->mcxt, sizeof(TBMIterator) + MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
+ 	iterator->tbm = tbm;
+ 
+ 	/*
  	 * Reset iteration pointers.
  	 */
! 	iterator->spageptr = 0;
! 	iterator->schunkptr = 0;
! 	iterator->schunkbit = 0;
  
  	/*
! 	 * Nothing else to do if we don't have a hashtable.
  	 */
! 	if (tbm->status == TBM_ONE_PAGE)
! 		return iterator;
  
  	/*
  	 * Create and fill the sorted page lists if we didn't already.
*************** tbm_begin_iterate(TIDBitmap *tbm)
*** 587,592 ****
--- 605,611 ----
  		qsort(tbm->spages, npages, sizeof(PagetableEntry *), tbm_comparator);
  	if (nchunks > 1)
  		qsort(tbm->schunks, nchunks, sizeof(PagetableEntry *), tbm_comparator);
+ 	return iterator;
  }
  
  /*
*************** tbm_begin_iterate(TIDBitmap *tbm)
*** 602,621 ****
   * testing, recheck is always set true when ntuples < 0.)
   */
  TBMIterateResult *
! tbm_iterate(TIDBitmap *tbm)
  {
! 	TBMIterateResult *output = &(tbm->output);
  
  	Assert(tbm->iterating);
  
  	/*
  	 * If lossy chunk pages remain, make sure we've advanced schunkptr/
  	 * schunkbit to the next set bit.
  	 */
! 	while (tbm->schunkptr < tbm->nchunks)
  	{
! 		PagetableEntry *chunk = tbm->schunks[tbm->schunkptr];
! 		int			schunkbit = tbm->schunkbit;
  
  		while (schunkbit < PAGES_PER_CHUNK)
  		{
--- 621,647 ----
   * testing, recheck is always set true when ntuples < 0.)
   */
  TBMIterateResult *
! tbm_iterate(TBMIterator *iterator)
  {
! 	TIDBitmap *tbm;
! 	TBMIterateResult *output;
! 
! 	/* We return NULL for an iterator against an empty bitmap */
! 	if (iterator == NULL)
! 		return NULL;
  
+ 	tbm = iterator->tbm;
+ 	output = &(iterator->output);
  	Assert(tbm->iterating);
  
  	/*
  	 * If lossy chunk pages remain, make sure we've advanced schunkptr/
  	 * schunkbit to the next set bit.
  	 */
! 	while (iterator->schunkptr < tbm->nchunks)
  	{
! 		PagetableEntry *chunk = tbm->schunks[iterator->schunkptr];
! 		int			schunkbit = iterator->schunkbit;
  
  		while (schunkbit < PAGES_PER_CHUNK)
  		{
*************** tbm_iterate(TIDBitmap *tbm)
*** 628,664 ****
  		}
  		if (schunkbit < PAGES_PER_CHUNK)
  		{
! 			tbm->schunkbit = schunkbit;
  			break;
  		}
  		/* advance to next chunk */
! 		tbm->schunkptr++;
! 		tbm->schunkbit = 0;
  	}
  
  	/*
  	 * If both chunk and per-page data remain, must output the numerically
  	 * earlier page.
  	 */
! 	if (tbm->schunkptr < tbm->nchunks)
  	{
! 		PagetableEntry *chunk = tbm->schunks[tbm->schunkptr];
  		BlockNumber chunk_blockno;
  
! 		chunk_blockno = chunk->blockno + tbm->schunkbit;
! 		if (tbm->spageptr >= tbm->npages ||
! 			chunk_blockno < tbm->spages[tbm->spageptr]->blockno)
  		{
  			/* Return a lossy page indicator from the chunk */
  			output->blockno = chunk_blockno;
  			output->ntuples = -1;
  			output->recheck = true;
! 			tbm->schunkbit++;
  			return output;
  		}
  	}
  
! 	if (tbm->spageptr < tbm->npages)
  	{
  		PagetableEntry *page;
  		int			ntuples;
--- 654,690 ----
  		}
  		if (schunkbit < PAGES_PER_CHUNK)
  		{
! 			iterator->schunkbit = schunkbit;
  			break;
  		}
  		/* advance to next chunk */
! 		iterator->schunkptr++;
! 		iterator->schunkbit = 0;
  	}
  
  	/*
  	 * If both chunk and per-page data remain, must output the numerically
  	 * earlier page.
  	 */
! 	if (iterator->schunkptr < tbm->nchunks)
  	{
! 		PagetableEntry *chunk = tbm->schunks[iterator->schunkptr];
  		BlockNumber chunk_blockno;
  
! 		chunk_blockno = chunk->blockno + iterator->schunkbit;
! 		if (iterator->spageptr >= tbm->npages ||
! 			chunk_blockno < tbm->spages[iterator->spageptr]->blockno)
  		{
  			/* Return a lossy page indicator from the chunk */
  			output->blockno = chunk_blockno;
  			output->ntuples = -1;
  			output->recheck = true;
! 			iterator->schunkbit++;
  			return output;
  		}
  	}
  
! 	if (iterator->spageptr < tbm->npages)
  	{
  		PagetableEntry *page;
  		int			ntuples;
*************** tbm_iterate(TIDBitmap *tbm)
*** 668,674 ****
  		if (tbm->status == TBM_ONE_PAGE)
  			page = &tbm->entry1;
  		else
! 			page = tbm->spages[tbm->spageptr];
  
  		/* scan bitmap to extract individual offset numbers */
  		ntuples = 0;
--- 694,700 ----
  		if (tbm->status == TBM_ONE_PAGE)
  			page = &tbm->entry1;
  		else
! 			page = tbm->spages[iterator->spageptr];
  
  		/* scan bitmap to extract individual offset numbers */
  		ntuples = 0;
*************** tbm_iterate(TIDBitmap *tbm)
*** 692,698 ****
  		output->blockno = page->blockno;
  		output->ntuples = ntuples;
  		output->recheck = page->recheck;
! 		tbm->spageptr++;
  		return output;
  	}
  
--- 718,724 ----
  		output->blockno = page->blockno;
  		output->ntuples = ntuples;
  		output->recheck = page->recheck;
! 		iterator->spageptr++;
  		return output;
  	}
  
diff -dcrpN --exclude=configure pgsql.orig/src/backend/storage/buffer/bufmgr.c pgsql/src/backend/storage/buffer/bufmgr.c
*** pgsql.orig/src/backend/storage/buffer/bufmgr.c	2008-06-19 10:02:46.000000000 +0200
--- pgsql/src/backend/storage/buffer/bufmgr.c	2008-06-19 11:01:00.000000000 +0200
*************** static void FlushBuffer(volatile BufferD
*** 98,103 ****
--- 98,134 ----
  static void AtProcExit_Buffers(int code, Datum arg);
  
  
+ void
+ AdviseBuffer(Relation reln, BlockNumber blockNum, int advice)
+ {
+ 	BufferTag	newTag;			/* identity of requested block */
+ 	uint32		newHash;		/* hash value for newTag */
+ 	LWLockId	newPartitionLock;		/* buffer partition lock for it */
+ 	int			buf_id;
+ 
+ 	elog(DEBUG1, "advising storage manager to read ahead of block %d", blockNum);
+ 
+ 	/* Open it at the smgr level if not already done */
+ 	RelationOpenSmgr(reln);
+ 
+ 	/* create a tag so we can lookup the buffer */
+ 	INIT_BUFFERTAG(newTag, reln->rd_smgr->smgr_rnode, blockNum);
+ 
+ 	/* determine its hash code and partition lock ID */
+ 	newHash = BufTableHashCode(&newTag);
+ 	newPartitionLock = BufMappingPartitionLock(newHash);
+ 
+ 	/* see if the block is in the buffer pool already */
+ 	LWLockAcquire(newPartitionLock, LW_SHARED);
+ 	buf_id = BufTableLookup(&newTag, newHash);
+ 	LWLockRelease(newPartitionLock);
+ 
+ 	if (buf_id < 0)
+ 		smgradvise(reln->rd_smgr, blockNum, advice);
+ 
+ 	return;
+ }
+ 
  /*
   * ReadBuffer -- returns a buffer containing the requested
   *		block of the requested relation.  If the blknum
diff -dcrpN --exclude=configure pgsql.orig/src/backend/storage/file/fd.c pgsql/src/backend/storage/file/fd.c
*** pgsql.orig/src/backend/storage/file/fd.c	2008-03-11 10:52:20.000000000 +0100
--- pgsql/src/backend/storage/file/fd.c	2008-06-19 10:17:09.000000000 +0200
*************** retry:
*** 1075,1080 ****
--- 1075,1127 ----
  	return returnCode;
  }
  
+ #ifdef USE_POSIX_FADVISE
+ int FileAdvise(File file, long offset, int amount, int advice)
+ {
+ 	int	returnCode;
+ 	int	pos_adv;
+ 
+ 	Assert(FileIsValid(file));
+ 	
+ 	DO_DB(elog(LOG, "FileAdvise: %d (%s) %ld %d",
+ 			   file, VfdCache[file].fileName,
+ 			   offset, amount));
+ 
+ 	returnCode = FileAccess(file);
+ 	if (returnCode < 0)
+ 		return returnCode;
+ 
+ 	switch (advice)
+ 	{
+ 		case BUFFER_ADV_NORMAL:
+ 			pos_adv = POSIX_FADV_NORMAL;
+ 			break;
+ 		case BUFFER_ADV_SEQUENTIAL:
+ 			pos_adv = POSIX_FADV_SEQUENTIAL;
+ 			break;
+ 		case BUFFER_ADV_RANDOM:
+ 			pos_adv = POSIX_FADV_RANDOM;
+ 			break;
+ 		case BUFFER_ADV_NOREUSE:
+ 			pos_adv = POSIX_FADV_NOREUSE;
+ 			break;
+ 		case BUFFER_ADV_WILLNEED:
+ 			pos_adv = POSIX_FADV_WILLNEED;
+ 			break;
+ 		case BUFFER_ADV_DONTNEED:
+ 			pos_adv = POSIX_FADV_DONTNEED;
+ 			break;
+ 		default:
+ 			return -1;
+ 	}
+ 
+ 	returnCode = posix_fadvise(VfdCache[file].fd, offset, amount, pos_adv);
+ 
+ 	return returnCode;
+ }
+ #endif
+ 
+ 
  int
  FileWrite(File file, char *buffer, int amount)
  {
diff -dcrpN --exclude=configure pgsql.orig/src/backend/storage/smgr/md.c pgsql/src/backend/storage/smgr/md.c
*** pgsql.orig/src/backend/storage/smgr/md.c	2008-05-02 12:40:51.000000000 +0200
--- pgsql/src/backend/storage/smgr/md.c	2008-06-19 10:17:09.000000000 +0200
*************** mdclose(SMgrRelation reln)
*** 545,550 ****
--- 545,569 ----
  	}
  }
  
+ void
+ mdadvise(SMgrRelation reln, BlockNumber blocknum, int advice)
+ {
+ 	long		seekpos;
+ 	MdfdVec    *v;
+ 
+ 	v = _mdfd_getseg(reln, blocknum, false, EXTENSION_FAIL);
+ 
+ #ifndef LET_OS_MANAGE_FILESIZE
+ 	seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE)));
+ 	Assert(seekpos < BLCKSZ * RELSEG_SIZE);
+ #else
+ 	seekpos = (long) (BLCKSZ * (blocknum));
+ #endif
+ 
+ 	FileAdvise(v->mdfd_vfd, seekpos, BLCKSZ, advice);
+ }
+ 
+ 
  /*
   *	mdread() -- Read the specified block from a relation.
   */
diff -dcrpN --exclude=configure pgsql.orig/src/backend/storage/smgr/smgr.c pgsql/src/backend/storage/smgr/smgr.c
*** pgsql.orig/src/backend/storage/smgr/smgr.c	2008-06-19 10:02:47.000000000 +0200
--- pgsql/src/backend/storage/smgr/smgr.c	2008-06-19 10:17:09.000000000 +0200
*************** typedef struct f_smgr
*** 47,52 ****
--- 47,53 ----
  	void		(*smgr_unlink) (RelFileNode rnode, bool isRedo);
  	void		(*smgr_extend) (SMgrRelation reln, BlockNumber blocknum,
  											char *buffer, bool isTemp);
+ 	void		(*smgr_advise) (SMgrRelation reln, BlockNumber blocknum, int advice);
  	void		(*smgr_read) (SMgrRelation reln, BlockNumber blocknum,
  										  char *buffer);
  	void		(*smgr_write) (SMgrRelation reln, BlockNumber blocknum,
*************** typedef struct f_smgr
*** 66,72 ****
  static const f_smgr smgrsw[] = {
  	/* magnetic disk */
  	{mdinit, NULL, mdclose, mdcreate, mdunlink, mdextend,
! 		mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
  		NULL, NULL, mdpreckpt, mdsync, mdpostckpt
  	}
  };
--- 67,73 ----
  static const f_smgr smgrsw[] = {
  	/* magnetic disk */
  	{mdinit, NULL, mdclose, mdcreate, mdunlink, mdextend,
! 		mdadvise, mdread, mdwrite, mdnblocks, mdtruncate, mdimmedsync,
  		NULL, NULL, mdpreckpt, mdsync, mdpostckpt
  	}
  };
*************** smgrextend(SMgrRelation reln, BlockNumbe
*** 492,497 ****
--- 493,508 ----
  }
  
  /*
+  *	smgradvise() -- 
+  *
+  */
+ void
+ smgradvise(SMgrRelation reln, BlockNumber blocknum, int advice)
+ {
+ 	(*(smgrsw[reln->smgr_which].smgr_advise)) (reln, blocknum, advice);
+ }
+ 
+ /*
   *	smgrread() -- read a particular block from a relation into the supplied
   *				  buffer.
   *
diff -dcrpN --exclude=configure pgsql.orig/src/backend/utils/misc/guc.c pgsql/src/backend/utils/misc/guc.c
*** pgsql.orig/src/backend/utils/misc/guc.c	2008-05-30 12:46:37.000000000 +0200
--- pgsql/src/backend/utils/misc/guc.c	2008-06-19 12:43:49.000000000 +0200
*************** extern char *default_tablespace;
*** 114,119 ****
--- 114,120 ----
  extern char *temp_tablespaces;
  extern bool synchronize_seqscans;
  extern bool fullPageWrites;
+ extern int preread_pages_bitmapscan;
  
  #ifdef TRACE_SORT
  extern bool trace_sort;
*************** static struct config_int ConfigureNamesI
*** 1848,1853 ****
--- 1849,1864 ----
  		-1, -1, INT_MAX, NULL, NULL
  	},
  
+ 	{
+ 		{"preread_pages_bitmapscan", PGC_USERSET, RESOURCES,
+ 			gettext_noop("How many pages to preread ahead of a bitmap index scan."),
+ 			NULL,
+ 			GUC_UNIT_BLOCKS,
+ 		},
+ 			&preread_pages_bitmapscan,
+ 			64, 0, INT_MAX, NULL, NULL
+ 	},
+ 
  	/* End-of-list marker */
  	{
  		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL
diff -dcrpN --exclude=configure pgsql.orig/src/include/access/gin.h pgsql/src/include/access/gin.h
*** pgsql.orig/src/include/access/gin.h	2008-06-19 10:02:58.000000000 +0200
--- pgsql/src/include/access/gin.h	2008-06-19 11:43:55.000000000 +0200
*************** typedef struct GinScanEntryData
*** 369,374 ****
--- 369,375 ----
  	/* partial match support */
  	bool		isPartialMatch;
  	TIDBitmap  *partialMatch;
+ 	TBMIterator	 *partialMatchIterator;
  	TBMIterateResult *partialMatchResult;
  	StrategyNumber strategy;
  
diff -dcrpN --exclude=configure pgsql.orig/src/include/nodes/execnodes.h pgsql/src/include/nodes/execnodes.h
*** pgsql.orig/src/include/nodes/execnodes.h	2008-06-19 10:03:02.000000000 +0200
--- pgsql/src/include/nodes/execnodes.h	2008-06-19 12:37:51.000000000 +0200
*************** typedef struct BitmapHeapScanState
*** 1088,1093 ****
--- 1088,1097 ----
  	ScanState	ss;				/* its first field is NodeTag */
  	List	   *bitmapqualorig;
  	TIDBitmap  *tbm;
+ 	TBMIterator *results_iterator;
+ 	TBMIterator *preread_iterator;
+ 	unsigned preread_pages_bitmapscan;
+ 	unsigned preread_target;
  	TBMIterateResult *tbmres;
  } BitmapHeapScanState;
  
diff -dcrpN --exclude=configure pgsql.orig/src/include/nodes/tidbitmap.h pgsql/src/include/nodes/tidbitmap.h
*** pgsql.orig/src/include/nodes/tidbitmap.h	2008-04-11 12:48:15.000000000 +0200
--- pgsql/src/include/nodes/tidbitmap.h	2008-06-19 11:34:15.000000000 +0200
***************
*** 29,35 ****
   * Actual bitmap representation is private to tidbitmap.c.	Callers can
   * do IsA(x, TIDBitmap) on it, but nothing else.
   */
! typedef struct TIDBitmap TIDBitmap;
  
  /* Result structure for tbm_iterate */
  typedef struct
--- 29,36 ----
   * Actual bitmap representation is private to tidbitmap.c.	Callers can
   * do IsA(x, TIDBitmap) on it, but nothing else.
   */
! typedef struct TIDBitmap	TIDBitmap;
! typedef struct TBMIterator	TBMIterator;
  
  /* Result structure for tbm_iterate */
  typedef struct
*************** extern void tbm_intersect(TIDBitmap *a, 
*** 55,61 ****
  
  extern bool tbm_is_empty(const TIDBitmap *tbm);
  
! extern void tbm_begin_iterate(TIDBitmap *tbm);
! extern TBMIterateResult *tbm_iterate(TIDBitmap *tbm);
  
  #endif   /* TIDBITMAP_H */
--- 56,62 ----
  
  extern bool tbm_is_empty(const TIDBitmap *tbm);
  
! extern TBMIterator	*tbm_begin_iterate(TIDBitmap *tbm);
! extern TBMIterateResult	*tbm_iterate(TBMIterator *iterator);
  
  #endif   /* TIDBITMAP_H */
diff -dcrpN --exclude=configure pgsql.orig/src/include/pg_config.h.in pgsql/src/include/pg_config.h.in
*** pgsql.orig/src/include/pg_config.h.in	2008-05-08 11:54:11.000000000 +0200
--- pgsql/src/include/pg_config.h.in	2008-06-19 10:27:12.000000000 +0200
***************
*** 722,727 ****
--- 722,731 ----
  /* Define to 1 to build with PAM support. (--with-pam) */
  #undef USE_PAM
  
+ /* Define to 1 if you want posix_fadvise() support. (--enable-posix-fadvise)
+    */
+ #undef USE_POSIX_FADVISE
+ 
  /* Use replacement snprintf() functions. */
  #undef USE_REPL_SNPRINTF
  
diff -dcrpN --exclude=configure pgsql.orig/src/include/storage/bufmgr.h pgsql/src/include/storage/bufmgr.h
*** pgsql.orig/src/include/storage/bufmgr.h	2008-06-19 10:03:06.000000000 +0200
--- pgsql/src/include/storage/bufmgr.h	2008-06-19 10:56:00.000000000 +0200
*************** extern PGDLLIMPORT int32 *LocalRefCount;
*** 143,148 ****
--- 143,149 ----
  /*
   * prototypes for functions in bufmgr.c
   */
+ extern void AdviseBuffer(Relation reln, BlockNumber blockNum, int advice);
  extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
  extern Buffer ReadBufferWithStrategy(Relation reln, BlockNumber blockNum,
  					   BufferAccessStrategy strategy);
diff -dcrpN --exclude=configure pgsql.orig/src/include/storage/fd.h pgsql/src/include/storage/fd.h
*** pgsql.orig/src/include/storage/fd.h	2008-03-11 10:52:21.000000000 +0100
--- pgsql/src/include/storage/fd.h	2008-06-19 10:17:35.000000000 +0200
*************** typedef int File;
*** 53,58 ****
--- 53,71 ----
  /* GUC parameter */
  extern int	max_files_per_process;
  
+ /*
+  * Abstract aliases for POSIX_FADV_* modes
+  */
+ typedef enum FileAdviceMode
+ {
+ 	BUFFER_ADV_NORMAL,
+ 	BUFFER_ADV_SEQUENTIAL,
+ 	BUFFER_ADV_RANDOM,
+ 	BUFFER_ADV_NOREUSE,
+ 	BUFFER_ADV_WILLNEED,
+ 	BUFFER_ADV_DONTNEED
+ } FileAdviceMode;
+ 
  
  /*
   * prototypes for functions in fd.c
*************** extern File OpenTemporaryFile(bool inter
*** 64,69 ****
--- 77,87 ----
  extern void FileClose(File file);
  extern int	FileRead(File file, char *buffer, int amount);
  extern int	FileWrite(File file, char *buffer, int amount);
+ #ifdef USE_POSIX_FADVISE
+ extern int	FileAdvise(File file, long offset, int amount, int advice);
+ #else
+ #define FileAdvise(file, offset, amount, advice)	(0)
+ #endif
  extern int	FileSync(File file);
  extern off_t FileSeek(File file, off_t offset, int whence);
  extern int	FileTruncate(File file, off_t offset);
diff -dcrpN --exclude=configure pgsql.orig/src/include/storage/smgr.h pgsql/src/include/storage/smgr.h
*** pgsql.orig/src/include/storage/smgr.h	2008-01-01 20:45:59.000000000 +0100
--- pgsql/src/include/storage/smgr.h	2008-06-19 10:17:35.000000000 +0200
*************** extern void smgrscheduleunlink(SMgrRelat
*** 68,73 ****
--- 68,74 ----
  extern void smgrdounlink(SMgrRelation reln, bool isTemp, bool isRedo);
  extern void smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer,
  		   bool isTemp);
+ extern void smgradvise(SMgrRelation reln, BlockNumber blocknum, int advice);
  extern void smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer);
  extern void smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer,
  		  bool isTemp);
*************** extern void mdcreate(SMgrRelation reln, 
*** 100,105 ****
--- 101,107 ----
  extern void mdunlink(RelFileNode rnode, bool isRedo);
  extern void mdextend(SMgrRelation reln, BlockNumber blocknum, char *buffer,
  		 bool isTemp);
+ extern void mdadvise(SMgrRelation reln, BlockNumber blocknum, int advice);
  extern void mdread(SMgrRelation reln, BlockNumber blocknum, char *buffer);
  extern void mdwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer,
  		bool isTemp);
