Commit da56e576 authored by Tom Lane's avatar Tom Lane

Modify tidbitmap.c to avoid creating a hash table until there is more

than one heap page represented in the bitmap.  This is a bit ugly but
it cuts overhead fairly effectively in simple join cases.  Per example
from Sergey Koposov.
parent e90df662
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* Copyright (c) 2003-2005, PostgreSQL Global Development Group * Copyright (c) 2003-2005, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.2 2005/04/19 22:35:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/tidbitmap.c,v 1.3 2005/05/17 00:43:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -90,6 +90,24 @@ typedef struct PagetableEntry ...@@ -90,6 +90,24 @@ typedef struct PagetableEntry
bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)]; bitmapword words[Max(WORDS_PER_PAGE, WORDS_PER_CHUNK)];
} PagetableEntry; } PagetableEntry;
/*
* dynahash.c is optimized for relatively large, long-lived hash tables.
* This is not ideal for TIDBitMap, particularly when we are using a bitmap
* scan on the inside of a nestloop join: a bitmap may well live only long
* enough to accumulate one entry in such cases. We therefore avoid creating
* an actual hashtable until we need two pagetable entries. When just one
* pagetable entry is needed, we store it in a fixed field of TIDBitMap.
* (NOTE: we don't get rid of the hashtable if the bitmap later shrinks down
* to zero or one page again. So, status can be TBM_HASH even when nentries
* is zero or one.)
*/
typedef enum
{
TBM_EMPTY, /* no hashtable, nentries == 0 */
TBM_ONE_PAGE, /* entry1 contains the single entry */
TBM_HASH /* pagetable is valid, entry1 is not */
} TBMStatus;
/* /*
* Here is the representation for a whole TIDBitMap: * Here is the representation for a whole TIDBitMap:
*/ */
...@@ -97,25 +115,29 @@ struct TIDBitmap ...@@ -97,25 +115,29 @@ struct TIDBitmap
{ {
NodeTag type; /* to make it a valid Node */ NodeTag type; /* to make it a valid Node */
MemoryContext mcxt; /* memory context containing me */ MemoryContext mcxt; /* memory context containing me */
TBMStatus status; /* see codes above */
HTAB *pagetable; /* hash table of PagetableEntry's */ HTAB *pagetable; /* hash table of PagetableEntry's */
int nentries; /* number of entries in pagetable */ int nentries; /* number of entries in pagetable */
int maxentries; /* limit on same to meet maxbytes */ int maxentries; /* limit on same to meet maxbytes */
int npages; /* number of exact entries in pagetable */ int npages; /* number of exact entries in pagetable */
int nchunks; /* number of lossy entries in pagetable */ int nchunks; /* number of lossy entries in pagetable */
bool iterating; /* tbm_begin_iterate called? */ bool iterating; /* tbm_begin_iterate called? */
PagetableEntry entry1; /* used when status == TBM_ONE_PAGE */
/* the remaining fields are used while producing sorted output: */ /* the remaining fields are used while producing sorted output: */
TBMIterateResult *output; /* NULL if not yet created */
PagetableEntry **spages; /* sorted exact-page list, or NULL */ PagetableEntry **spages; /* sorted exact-page list, or NULL */
PagetableEntry **schunks; /* sorted lossy-chunk list, or NULL */ PagetableEntry **schunks; /* sorted lossy-chunk list, or NULL */
int spageptr; /* next spages index */ int spageptr; /* next spages index */
int schunkptr; /* next schunks index */ int schunkptr; /* next schunks index */
int schunkbit; /* next bit to check in current schunk */ int schunkbit; /* next bit to check in current schunk */
TBMIterateResult output; /* MUST BE LAST (because variable-size) */
}; };
/* Local function prototypes */ /* Local function prototypes */
static PagetableEntry *tbm_find_pageentry(const TIDBitmap *tbm, static void tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage);
BlockNumber pageno); static bool tbm_intersect_page(PagetableEntry *apage, const TIDBitmap *b);
static const PagetableEntry *tbm_find_pageentry(const TIDBitmap *tbm,
BlockNumber pageno);
static PagetableEntry *tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno); static PagetableEntry *tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno);
static bool tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno); static bool tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno);
static void tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno); static void tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno);
...@@ -134,37 +156,79 @@ TIDBitmap * ...@@ -134,37 +156,79 @@ TIDBitmap *
tbm_create(long maxbytes) tbm_create(long maxbytes)
{ {
TIDBitmap *tbm; TIDBitmap *tbm;
HASHCTL hash_ctl;
long nbuckets; long nbuckets;
tbm = makeNode(TIDBitmap); /*
/* we rely on makeNode to have zeroed all the fields */ * 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));
tbm->type = T_TIDBitmap; /* Set NodeTag */
tbm->mcxt = CurrentMemoryContext; tbm->mcxt = CurrentMemoryContext;
tbm->status = TBM_EMPTY;
/* /*
* Estimate number of hashtable entries we can have within maxbytes. * Estimate number of hashtable entries we can have within maxbytes.
* This estimates the hash overhead at MAXALIGN(sizeof(HASHELEMENT)) * This estimates the hash overhead at MAXALIGN(sizeof(HASHELEMENT))
* plus a pointer per hash entry, which is crude but good enough for * plus a pointer per hash entry, which is crude but good enough for
* our purpose. (NOTE: this does not count the space for data * our purpose. Also count an extra Pointer per entry for the arrays
* structures created during iteration readout.) * created during iteration readout.
*/ */
nbuckets = maxbytes / nbuckets = maxbytes /
(MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry)) (MAXALIGN(sizeof(HASHELEMENT)) + MAXALIGN(sizeof(PagetableEntry))
+ sizeof(Pointer)); + sizeof(Pointer) + sizeof(Pointer));
nbuckets = Min(nbuckets, INT_MAX-1); /* safety limit */ nbuckets = Min(nbuckets, INT_MAX-1); /* safety limit */
nbuckets = Max(nbuckets, 16); /* sanity limit */
tbm->maxentries = (int) nbuckets; tbm->maxentries = (int) nbuckets;
return tbm;
}
/*
* Actually create the hashtable. Since this is a moderately expensive
* proposition, we don't do it until we have to.
*/
static void
tbm_create_pagetable(TIDBitmap *tbm)
{
HASHCTL hash_ctl;
Assert(tbm->status != TBM_HASH);
Assert(tbm->pagetable == NULL);
/* Create the hashtable proper */
MemSet(&hash_ctl, 0, sizeof(hash_ctl)); MemSet(&hash_ctl, 0, sizeof(hash_ctl));
hash_ctl.keysize = sizeof(BlockNumber); hash_ctl.keysize = sizeof(BlockNumber);
hash_ctl.entrysize = sizeof(PagetableEntry); hash_ctl.entrysize = sizeof(PagetableEntry);
hash_ctl.hash = tag_hash; hash_ctl.hash = tag_hash;
hash_ctl.hcxt = CurrentMemoryContext; hash_ctl.hcxt = tbm->mcxt;
tbm->pagetable = hash_create("TIDBitmap", tbm->pagetable = hash_create("TIDBitmap",
128, /* start small and extend */ 128, /* start small and extend */
&hash_ctl, &hash_ctl,
HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT); HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
return tbm; /* If entry1 is valid, push it into the hashtable */
if (tbm->status == TBM_ONE_PAGE)
{
PagetableEntry *page;
bool found;
page = (PagetableEntry *) hash_search(tbm->pagetable,
(void *) &tbm->entry1.blockno,
HASH_ENTER, &found);
if (page == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
Assert(!found);
memcpy(page, &tbm->entry1, sizeof(PagetableEntry));
}
tbm->status = TBM_HASH;
} }
/* /*
...@@ -173,9 +237,8 @@ tbm_create(long maxbytes) ...@@ -173,9 +237,8 @@ tbm_create(long maxbytes)
void void
tbm_free(TIDBitmap *tbm) tbm_free(TIDBitmap *tbm)
{ {
hash_destroy(tbm->pagetable); if (tbm->pagetable)
if (tbm->output) hash_destroy(tbm->pagetable);
pfree(tbm->output);
if (tbm->spages) if (tbm->spages)
pfree(tbm->spages); pfree(tbm->spages);
if (tbm->schunks) if (tbm->schunks)
...@@ -235,62 +298,77 @@ tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids) ...@@ -235,62 +298,77 @@ tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids)
void void
tbm_union(TIDBitmap *a, const TIDBitmap *b) tbm_union(TIDBitmap *a, const TIDBitmap *b)
{ {
HASH_SEQ_STATUS status; Assert(!a->iterating);
/* Nothing to do if b is empty */
if (b->nentries == 0)
return;
/* Scan through chunks and pages in b, merge into a */
if (b->status == TBM_ONE_PAGE)
tbm_union_page(a, &b->entry1);
else
{
HASH_SEQ_STATUS status;
PagetableEntry *bpage;
Assert(b->status == TBM_HASH);
hash_seq_init(&status, b->pagetable);
while ((bpage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
tbm_union_page(a, bpage);
}
}
/* Process one page of b during a union op */
static void
tbm_union_page(TIDBitmap *a, const PagetableEntry *bpage)
{
PagetableEntry *apage; PagetableEntry *apage;
PagetableEntry *bpage;
int wordnum; int wordnum;
Assert(!a->iterating); if (bpage->ischunk)
/* Scan through chunks and pages in b, merge into a */
hash_seq_init(&status, b->pagetable);
while ((bpage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
{ {
if (bpage->ischunk) /* Scan b's chunk, mark each indicated page lossy in a */
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
{ {
/* Scan b's chunk, mark each indicated page lossy in a */ bitmapword w = bpage->words[wordnum];
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
if (w != 0)
{ {
bitmapword w = bpage->words[wordnum]; BlockNumber pg;
if (w != 0) pg = bpage->blockno + (wordnum * BITS_PER_BITMAPWORD);
while (w != 0)
{ {
BlockNumber pg; if (w & 1)
tbm_mark_page_lossy(a, pg);
pg = bpage->blockno + (wordnum * BITS_PER_BITMAPWORD); pg++;
while (w != 0) w >>= 1;
{
if (w & 1)
tbm_mark_page_lossy(a, pg);
pg++;
w >>= 1;
}
} }
} }
} }
else if (tbm_page_is_lossy(a, bpage->blockno)) }
else if (tbm_page_is_lossy(a, bpage->blockno))
{
/* page is already lossy in a, nothing to do */
return;
}
else
{
apage = tbm_get_pageentry(a, bpage->blockno);
if (apage->ischunk)
{ {
/* page is already lossy in a, nothing to do */ /* The page is a lossy chunk header, set bit for itself */
continue; apage->words[0] |= ((bitmapword) 1 << 0);
} }
else else
{ {
apage = tbm_get_pageentry(a, bpage->blockno); /* Both pages are exact, merge at the bit level */
if (apage->ischunk) for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
{ apage->words[wordnum] |= bpage->words[wordnum];
/* The page is a lossy chunk header, set bit for itself */
apage->words[0] |= ((bitmapword) 1 << 0);
}
else
{
/* Both pages are exact, merge at the bit level */
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
apage->words[wordnum] |= bpage->words[wordnum];
}
} }
if (a->nentries > a->maxentries)
tbm_lossify(a);
} }
if (a->nentries > a->maxentries)
tbm_lossify(a);
} }
/* /*
...@@ -301,96 +379,121 @@ tbm_union(TIDBitmap *a, const TIDBitmap *b) ...@@ -301,96 +379,121 @@ tbm_union(TIDBitmap *a, const TIDBitmap *b)
void void
tbm_intersect(TIDBitmap *a, const TIDBitmap *b) tbm_intersect(TIDBitmap *a, const TIDBitmap *b)
{ {
HASH_SEQ_STATUS status;
PagetableEntry *apage;
PagetableEntry *bpage;
int wordnum;
Assert(!a->iterating); Assert(!a->iterating);
/* Nothing to do if a is empty */
if (a->nentries == 0)
return;
/* Scan through chunks and pages in a, try to match to b */ /* Scan through chunks and pages in a, try to match to b */
hash_seq_init(&status, a->pagetable); if (a->status == TBM_ONE_PAGE)
while ((apage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
{ {
if (apage->ischunk) if (tbm_intersect_page(&a->entry1, b))
{ {
/* Scan each bit in chunk, try to clear */ /* Page is now empty, remove it from a */
bool candelete = true; Assert(!a->entry1.ischunk);
a->npages--;
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++) a->nentries--;
{ Assert(a->nentries == 0);
bitmapword w = apage->words[wordnum]; a->status = TBM_EMPTY;
}
if (w != 0) }
{ else
bitmapword neww = w; {
BlockNumber pg; HASH_SEQ_STATUS status;
int bitnum; PagetableEntry *apage;
pg = apage->blockno + (wordnum * BITS_PER_BITMAPWORD); Assert(a->status == TBM_HASH);
bitnum = 0; hash_seq_init(&status, a->pagetable);
while (w != 0) while ((apage = (PagetableEntry *) hash_seq_search(&status)) != NULL)
{ {
if (w & 1) if (tbm_intersect_page(apage, b))
{
if (!tbm_page_is_lossy(b, pg) &&
tbm_find_pageentry(b, pg) == NULL)
{
/* Page is not in b at all, lose lossy bit */
neww &= ~((bitmapword) 1 << bitnum);
}
}
pg++;
bitnum++;
w >>= 1;
}
apage->words[wordnum] = neww;
if (neww != 0)
candelete = false;
}
}
if (candelete)
{ {
/* Chunk is now empty, remove it from a */ /* Page or chunk is now empty, remove it from a */
if (apage->ischunk)
a->nchunks--;
else
a->npages--;
a->nentries--;
if (hash_search(a->pagetable, if (hash_search(a->pagetable,
(void *) &apage->blockno, (void *) &apage->blockno,
HASH_REMOVE, NULL) == NULL) HASH_REMOVE, NULL) == NULL)
elog(ERROR, "hash table corrupted"); elog(ERROR, "hash table corrupted");
a->nentries--;
a->nchunks--;
} }
} }
else if (tbm_page_is_lossy(b, apage->blockno)) }
{ }
/* page is lossy in b, cannot clear any bits */
continue; /*
} * Process one page of a during an intersection op
else *
* Returns TRUE if apage is now empty and should be deleted from a
*/
static bool
tbm_intersect_page(PagetableEntry *apage, const TIDBitmap *b)
{
const PagetableEntry *bpage;
int wordnum;
if (apage->ischunk)
{
/* Scan each bit in chunk, try to clear */
bool candelete = true;
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
{ {
bool candelete = true; bitmapword w = apage->words[wordnum];
bpage = tbm_find_pageentry(b, apage->blockno); if (w != 0)
if (bpage != NULL)
{ {
/* Both pages are exact, merge at the bit level */ bitmapword neww = w;
Assert(!bpage->ischunk); BlockNumber pg;
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++) int bitnum;
pg = apage->blockno + (wordnum * BITS_PER_BITMAPWORD);
bitnum = 0;
while (w != 0)
{ {
apage->words[wordnum] &= bpage->words[wordnum]; if (w & 1)
if (apage->words[wordnum] != 0) {
candelete = false; if (!tbm_page_is_lossy(b, pg) &&
tbm_find_pageentry(b, pg) == NULL)
{
/* Page is not in b at all, lose lossy bit */
neww &= ~((bitmapword) 1 << bitnum);
}
}
pg++;
bitnum++;
w >>= 1;
} }
apage->words[wordnum] = neww;
if (neww != 0)
candelete = false;
} }
if (candelete) }
return candelete;
}
else if (tbm_page_is_lossy(b, apage->blockno))
{
/* page is lossy in b, cannot clear any bits */
return false;
}
else
{
bool candelete = true;
bpage = tbm_find_pageentry(b, apage->blockno);
if (bpage != NULL)
{
/* Both pages are exact, merge at the bit level */
Assert(!bpage->ischunk);
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
{ {
/* Page is now empty, remove it from a */ apage->words[wordnum] &= bpage->words[wordnum];
if (hash_search(a->pagetable, if (apage->words[wordnum] != 0)
(void *) &apage->blockno, candelete = false;
HASH_REMOVE, NULL) == NULL)
elog(ERROR, "hash table corrupted");
a->nentries--;
a->npages--;
} }
} }
return candelete;
} }
} }
...@@ -411,15 +514,16 @@ tbm_begin_iterate(TIDBitmap *tbm) ...@@ -411,15 +514,16 @@ tbm_begin_iterate(TIDBitmap *tbm)
tbm->iterating = true; tbm->iterating = true;
/* /*
* Allocate the output data structure if we didn't already. * Reset iteration pointers.
* (We don't do this during tbm_create since it's entirely possible */
* that a TIDBitmap will live and die without ever being iterated.) 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->output) if (tbm->nentries == 0 || tbm->status != TBM_HASH)
tbm->output = (TBMIterateResult *) return;
MemoryContextAllocZero(tbm->mcxt,
sizeof(TBMIterateResult) +
MAX_TUPLES_PER_PAGE * sizeof(OffsetNumber));
/* /*
* Create and fill the sorted page lists if we didn't already. * Create and fill the sorted page lists if we didn't already.
*/ */
...@@ -447,12 +551,6 @@ tbm_begin_iterate(TIDBitmap *tbm) ...@@ -447,12 +551,6 @@ tbm_begin_iterate(TIDBitmap *tbm)
qsort(tbm->spages, npages, sizeof(PagetableEntry *), tbm_comparator); qsort(tbm->spages, npages, sizeof(PagetableEntry *), tbm_comparator);
if (nchunks > 1) if (nchunks > 1)
qsort(tbm->schunks, nchunks, sizeof(PagetableEntry *), tbm_comparator); qsort(tbm->schunks, nchunks, sizeof(PagetableEntry *), tbm_comparator);
/*
* Reset iteration pointers.
*/
tbm->spageptr = 0;
tbm->schunkptr = 0;
tbm->schunkbit = 0;
} }
/* /*
...@@ -468,7 +566,7 @@ tbm_begin_iterate(TIDBitmap *tbm) ...@@ -468,7 +566,7 @@ tbm_begin_iterate(TIDBitmap *tbm)
TBMIterateResult * TBMIterateResult *
tbm_iterate(TIDBitmap *tbm) tbm_iterate(TIDBitmap *tbm)
{ {
TBMIterateResult *output = tbm->output; TBMIterateResult *output = &(tbm->output);
Assert(tbm->iterating); Assert(tbm->iterating);
/* /*
...@@ -521,10 +619,16 @@ tbm_iterate(TIDBitmap *tbm) ...@@ -521,10 +619,16 @@ tbm_iterate(TIDBitmap *tbm)
if (tbm->spageptr < tbm->npages) if (tbm->spageptr < tbm->npages)
{ {
PagetableEntry *page = tbm->spages[tbm->spageptr]; PagetableEntry *page;
int ntuples; int ntuples;
int wordnum; int wordnum;
/* In ONE_PAGE state, we don't allocate an spages[] array */
if (tbm->status == TBM_ONE_PAGE)
page = &tbm->entry1;
else
page = tbm->spages[tbm->spageptr];
/* scan bitmap to extract individual offset numbers */ /* scan bitmap to extract individual offset numbers */
ntuples = 0; ntuples = 0;
for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++) for (wordnum = 0; wordnum < WORDS_PER_PAGE; wordnum++)
...@@ -559,10 +663,22 @@ tbm_iterate(TIDBitmap *tbm) ...@@ -559,10 +663,22 @@ tbm_iterate(TIDBitmap *tbm)
* *
* Returns NULL if there is no non-lossy entry for the pageno. * Returns NULL if there is no non-lossy entry for the pageno.
*/ */
static PagetableEntry * static const PagetableEntry *
tbm_find_pageentry(const TIDBitmap *tbm, BlockNumber pageno) tbm_find_pageentry(const TIDBitmap *tbm, BlockNumber pageno)
{ {
PagetableEntry *page; const PagetableEntry *page;
if (tbm->nentries == 0) /* in case pagetable doesn't exist */
return NULL;
if (tbm->status == TBM_ONE_PAGE)
{
page = &tbm->entry1;
if (page->blockno != pageno)
return NULL;
Assert(!page->ischunk);
return page;
}
page = (PagetableEntry *) hash_search(tbm->pagetable, page = (PagetableEntry *) hash_search(tbm->pagetable,
(void *) &pageno, (void *) &pageno,
...@@ -588,14 +704,33 @@ tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno) ...@@ -588,14 +704,33 @@ tbm_get_pageentry(TIDBitmap *tbm, BlockNumber pageno)
PagetableEntry *page; PagetableEntry *page;
bool found; bool found;
/* Look up or create an entry */ if (tbm->status == TBM_EMPTY)
page = (PagetableEntry *) hash_search(tbm->pagetable, {
(void *) &pageno, /* Use the fixed slot */
HASH_ENTER, &found); page = &tbm->entry1;
if (page == NULL) found = false;
ereport(ERROR, tbm->status = TBM_ONE_PAGE;
(errcode(ERRCODE_OUT_OF_MEMORY), }
errmsg("out of memory"))); else
{
if (tbm->status == TBM_ONE_PAGE)
{
page = &tbm->entry1;
if (page->blockno == pageno)
return page;
/* Time to switch from one page to a hashtable */
tbm_create_pagetable(tbm);
}
/* Look up or create an entry */
page = (PagetableEntry *) hash_search(tbm->pagetable,
(void *) &pageno,
HASH_ENTER, &found);
if (page == NULL)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory")));
}
/* Initialize it if not present before */ /* Initialize it if not present before */
if (!found) if (!found)
...@@ -623,6 +758,7 @@ tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno) ...@@ -623,6 +758,7 @@ tbm_page_is_lossy(const TIDBitmap *tbm, BlockNumber pageno)
/* we can skip the lookup if there are no lossy chunks */ /* we can skip the lookup if there are no lossy chunks */
if (tbm->nchunks == 0) if (tbm->nchunks == 0)
return false; return false;
Assert(tbm->status == TBM_HASH);
bitno = pageno % PAGES_PER_CHUNK; bitno = pageno % PAGES_PER_CHUNK;
chunk_pageno = pageno - bitno; chunk_pageno = pageno - bitno;
...@@ -656,6 +792,10 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno) ...@@ -656,6 +792,10 @@ tbm_mark_page_lossy(TIDBitmap *tbm, BlockNumber pageno)
int wordnum; int wordnum;
int bitnum; int bitnum;
/* We force the bitmap into hashtable mode whenever it's lossy */
if (tbm->status != TBM_HASH)
tbm_create_pagetable(tbm);
bitno = pageno % PAGES_PER_CHUNK; bitno = pageno % PAGES_PER_CHUNK;
chunk_pageno = pageno - bitno; chunk_pageno = pageno - bitno;
...@@ -731,6 +871,8 @@ tbm_lossify(TIDBitmap *tbm) ...@@ -731,6 +871,8 @@ tbm_lossify(TIDBitmap *tbm)
* during each call. * during each call.
*/ */
Assert(!tbm->iterating); Assert(!tbm->iterating);
Assert(tbm->status == TBM_HASH);
hash_seq_init(&status, tbm->pagetable); hash_seq_init(&status, tbm->pagetable);
while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL) while ((page = (PagetableEntry *) hash_seq_search(&status)) != NULL)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment