diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index c458bfb565..06d94d2545 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -23,6 +23,190 @@
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 
+/* Lowest level of radix tree is represented by bitmap */
+typedef struct
+{
+	char data[256/8];
+} BlockSetLevel4Data;
+
+typedef BlockSetLevel4Data *BlockSetLevel4;
+
+/* statically typed inner level chunks points to ground level */
+typedef struct
+{
+	/* null references denote empty subtree */
+	BlockSetLevel4 next[256];
+} BlockSetLevel3Data;
+
+typedef BlockSetLevel3Data *BlockSetLevel3;
+
+/* inner level points to another inner level */
+typedef struct
+{
+	BlockSetLevel3 next[256];
+} BlockSetLevel2Data;
+
+typedef BlockSetLevel2Data *BlockSetLevel2;
+
+/* Radix tree root */
+typedef struct
+{
+	BlockSetLevel2 next[256];
+} BlockSetData;
+
+typedef BlockSetData *BlockSet;
+
+/* multiplex block number into indexes of radix tree */
+#define BLOCKSET_SPLIT_BLKNO				\
+	int i1, i2, i3, i4, byte_no, byte_mask;	\
+	i4 = blkno % 256;						\
+	blkno /= 256;							\
+	i3 = blkno % 256;						\
+	blkno /= 256;							\
+	i2 = blkno % 256;						\
+	blkno /= 256;							\
+	i1 = blkno;								\
+	byte_no = i4 / 8;						\
+	byte_mask = 1 << (i4 % 8)				\
+
+/* indicate presence of block number in set */
+static
+BlockSet blockset_set(BlockSet bs, BlockNumber blkno)
+{
+	BLOCKSET_SPLIT_BLKNO;
+	if (bs == NULL)
+	{
+		bs = palloc0(sizeof(BlockSetData));
+	}
+	BlockSetLevel2 bs2 = bs->next[i1];
+	if (bs2 == NULL)
+	{
+		bs2 = palloc0(sizeof(BlockSetLevel2Data));
+		bs->next[i1] = bs2;
+	}
+	BlockSetLevel3 bs3 = bs2->next[i2];
+	if (bs3 == NULL)
+	{
+		bs3 = palloc0(sizeof(BlockSetLevel3Data));
+		bs2->next[i2] = bs3;
+	}
+	BlockSetLevel4 bs4 = bs3->next[i3];
+	if (bs4 == NULL)
+	{
+		bs4 = palloc0(sizeof(BlockSetLevel4Data));
+		bs3->next[i3] = bs4;
+	}
+	bs4->data[byte_no] = byte_mask | bs4->data[byte_no];
+	return bs;
+}
+
+/* Test presence of block in set */
+static
+bool blockset_get(BlockNumber blkno, BlockSet bs)
+{
+	BLOCKSET_SPLIT_BLKNO;
+	if (bs == NULL)
+		return false;
+	BlockSetLevel2 bs2 = bs->next[i1];
+	if (bs2 == NULL)
+		return false;
+	BlockSetLevel3 bs3 = bs2->next[i2];
+	if (bs3 == NULL)
+		return false;
+	BlockSetLevel4 bs4 = bs3->next[i3];
+	if (bs4 == NULL)
+		return false;
+	return (bs4->data[byte_no] & byte_mask);
+}
+
+/* 
+ * Find nearest block number in set no less than blkno
+ * Return InvalidBlockNumber if nothing to return
+ * If given InvalidBlockNumber - returns minimal element in set
+ */
+static
+BlockNumber blockset_next(BlockSet bs, BlockNumber blkno)
+{
+	if (blkno == InvalidBlockNumber)
+		blkno = 0; /* equvalent to ++, left for clear code */
+	else
+		blkno++;
+
+	BLOCKSET_SPLIT_BLKNO;
+
+	if (bs == NULL)
+		return InvalidBlockNumber;
+	for (; i1 < 256; i1++)
+	{
+		BlockSetLevel2 bs2 = bs->next[i1];
+		if (!bs2)
+			continue;
+		for (; i2 < 256; i2++)
+		{
+			BlockSetLevel3 bs3 = bs2->next[i2];
+			if (!bs3)
+				continue;
+			for (; i3 < 256; i3++)
+			{
+				BlockSetLevel4 bs4 = bs3->next[i3];
+				if (!bs4)
+					continue;
+				for (; byte_no < 256 / 8; byte_no++)
+				{
+					if (!bs4->data[byte_no])
+						continue;
+					while (byte_mask <= 0x70)
+					{
+						if ((byte_mask & bs4->data[byte_no]) == byte_mask)
+						{
+							i4 = byte_no * 8;
+							while (byte_mask >>= 1) i4++;
+							return i4 + 256 * (i3 + 256 * (i2 + 256 * i1));
+						}
+						byte_mask <<= 1;
+					}
+					byte_mask = 1;
+				}
+				byte_no = 0;
+			}
+			i3 = 0;
+		}
+		i2 = 0;
+	}
+	return InvalidBlockNumber;
+}
+
+/* free anything palloced */
+static
+void blockset_free(BlockSet bs)
+{
+	BlockNumber blkno = 0;
+	BLOCKSET_SPLIT_BLKNO;
+	if (bs == NULL)
+		return;
+	for (; i1 < 256; i1++)
+	{
+		BlockSetLevel2 bs2 = bs->next[i1];
+		if (!bs2)
+			continue;
+		for (; i2 < 256; i2++)
+		{
+			BlockSetLevel3 bs3 = bs2->next[i2];
+			if (!bs3)
+				continue;
+			for (; i3 < 256; i3++)
+			{
+				BlockSetLevel4 bs4 = bs3->next[i3];
+				if (bs4)
+					pfree(bs4);
+			}
+			pfree(bs3);
+		}
+		pfree(bs2);
+	}
+	pfree(bs);
+}
+
 /* Working state needed by gistbulkdelete */
 typedef struct
 {
@@ -34,8 +218,8 @@ typedef struct
 	BlockNumber totFreePages;	/* true total # of free pages */
 	BlockNumber emptyPages;
 
-	Bitmapset  *internalPagesMap;
-	Bitmapset  *emptyLeafPagesMap;
+	BlockSet	internalPagesMap;
+	BlockSet	emptyLeafPagesMap;
 } GistVacState;
 
 static void gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
@@ -53,6 +237,7 @@ gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 
 	gistvacuumscan(info, stats, callback, callback_state);
 
+
 	return stats;
 }
 
@@ -174,11 +359,6 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		if (blkno >= num_pages)
 			break;
 
-		if (!vstate.internalPagesMap)
-			vstate.internalPagesMap = bms_make_empty(num_pages);
-		if (!vstate.emptyLeafPagesMap)
-			vstate.emptyLeafPagesMap = bms_make_empty(num_pages);
-
 		/* Iterate over pages, then loop back to recheck length */
 		for (; blkno < num_pages; blkno++)
 			gistvacuumpage(&vstate, blkno, blkno);
@@ -206,11 +386,11 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 	/* rescan all inner pages to find those that has empty child pages */
 	if (vstate.emptyPages > 0)
 	{
-		int			x;
+		BlockNumber			x;
 
-		x = -1;
+		x = InvalidBlockNumber;
 		while (vstate.emptyPages > 0 &&
-			   (x = bms_next_member(vstate.internalPagesMap, x)) >= 0)
+			   (x = blockset_next(vstate.internalPagesMap, x)) != InvalidBlockNumber)
 		{
 			Buffer		buffer;
 			Page		page;
@@ -248,7 +428,7 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 				idxtuple = (IndexTuple) PageGetItem(page, iid);
 				/* if this page was not empty in previous scan - we do not consider it */
 				leafBlockNo = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
-				if (!bms_is_member(leafBlockNo, vstate.emptyLeafPagesMap))
+				if (!blockset_get(leafBlockNo, vstate.emptyLeafPagesMap))
 					continue;
 
 				leafBuffer = ReadBufferExtended(rel, MAIN_FORKNUM, leafBlockNo,
@@ -321,8 +501,8 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		}
 	}
 
-	bms_free(vstate.emptyLeafPagesMap);
-	bms_free(vstate.internalPagesMap);
+	blockset_free(vstate.emptyLeafPagesMap);
+	blockset_free(vstate.internalPagesMap);
 }
 
 /*
@@ -447,7 +627,7 @@ restart:
 		nremain = maxoff - FirstOffsetNumber + 1;
 		if (nremain == 0)
 		{
-			vstate->emptyLeafPagesMap = bms_add_member(vstate->emptyLeafPagesMap, blkno);
+			vstate->emptyLeafPagesMap = blockset_set(vstate->emptyLeafPagesMap, blkno);
 			vstate->emptyPages++;
 		}
 		else
@@ -455,7 +635,7 @@ restart:
 	}
 	else
 	{
-		vstate->internalPagesMap = bms_add_member(vstate->internalPagesMap, blkno);
+		vstate->internalPagesMap = blockset_set(vstate->internalPagesMap, blkno);
 	}
 
 	UnlockReleaseBuffer(buffer);
