summaryrefslogtreecommitdiff
path: root/src/backend/access/gin
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gin')
-rw-r--r--src/backend/access/gin/ginbtree.c16
-rw-r--r--src/backend/access/gin/ginbulk.c134
-rw-r--r--src/backend/access/gin/ginentrypage.c6
-rw-r--r--src/backend/access/gin/ginfast.c4
-rw-r--r--src/backend/access/gin/gininsert.c5
5 files changed, 98 insertions, 67 deletions
diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index bb150a46893..ed3286651fc 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.15 2010/01/02 16:57:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.15.6.1 2010/08/01 02:12:51 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -267,6 +267,8 @@ findParents(GinBtree btree, GinBtreeStack *stack,
/*
* Insert value (stored in GinBtree) to tree described by stack
+ *
+ * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
*/
void
ginInsertValue(GinBtree btree, GinBtreeStack *stack)
@@ -308,10 +310,11 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack)
PageSetTLI(page, ThisTimeLineID);
}
- UnlockReleaseBuffer(stack->buffer);
+ LockBuffer(stack->buffer, GIN_UNLOCK);
END_CRIT_SECTION();
- freeGinBtreeStack(stack->parent);
+ freeGinBtreeStack(stack);
+
return;
}
else
@@ -325,7 +328,6 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack)
*/
newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata);
-
((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno;
parent = stack->parent;
@@ -341,7 +343,6 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack)
((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE;
((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber;
-
page = BufferGetPage(stack->buffer);
lpage = BufferGetPage(lbuffer);
rpage = BufferGetPage(rbuffer);
@@ -375,10 +376,11 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack)
UnlockReleaseBuffer(rbuffer);
UnlockReleaseBuffer(lbuffer);
- UnlockReleaseBuffer(stack->buffer);
-
+ LockBuffer(stack->buffer, GIN_UNLOCK);
END_CRIT_SECTION();
+ freeGinBtreeStack(stack);
+
return;
}
else
diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c
index bb726e69f4c..094479ccb18 100644
--- a/src/backend/access/gin/ginbulk.c
+++ b/src/backend/access/gin/ginbulk.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.19 2010/02/26 02:00:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.19.4.1 2010/08/01 02:12:51 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -19,17 +19,21 @@
#include "utils/memutils.h"
-#define DEF_NENTRY 2048
-#define DEF_NPTR 4
+#define DEF_NENTRY 2048 /* EntryAccumulator allocation quantum */
+#define DEF_NPTR 5 /* ItemPointer initial allocation quantum */
-static void *
-ginAppendData(void *old, void *new, void *arg)
-{
- EntryAccumulator *eo = (EntryAccumulator *) old,
- *en = (EntryAccumulator *) new;
+/* Combiner function for rbtree.c */
+static void
+ginCombineData(RBNode *existing, const RBNode *newdata, void *arg)
+{
+ EntryAccumulator *eo = (EntryAccumulator *) existing;
+ const EntryAccumulator *en = (const EntryAccumulator *) newdata;
BuildAccumulator *accum = (BuildAccumulator *) arg;
+ /*
+ * Note this code assumes that newdata contains only one itempointer.
+ */
if (eo->number >= eo->length)
{
accum->allocatedMemory -= GetMemoryChunkSpace(eo->list);
@@ -53,29 +57,57 @@ ginAppendData(void *old, void *new, void *arg)
eo->list[eo->number] = en->list[0];
eo->number++;
-
- return old;
}
+/* Comparator function for rbtree.c */
static int
-cmpEntryAccumulator(const void *a, const void *b, void *arg)
+cmpEntryAccumulator(const RBNode *a, const RBNode *b, void *arg)
{
- EntryAccumulator *ea = (EntryAccumulator *) a;
- EntryAccumulator *eb = (EntryAccumulator *) b;
+ const EntryAccumulator *ea = (const EntryAccumulator *) a;
+ const EntryAccumulator *eb = (const EntryAccumulator *) b;
BuildAccumulator *accum = (BuildAccumulator *) arg;
return compareAttEntries(accum->ginstate, ea->attnum, ea->value,
eb->attnum, eb->value);
}
+/* Allocator function for rbtree.c */
+static RBNode *
+ginAllocEntryAccumulator(void *arg)
+{
+ BuildAccumulator *accum = (BuildAccumulator *) arg;
+ EntryAccumulator *ea;
+
+ /*
+ * Allocate memory by rather big chunks to decrease overhead. We have
+ * no need to reclaim RBNodes individually, so this costs nothing.
+ */
+ if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
+ {
+ accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
+ accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
+ accum->length = 0;
+ }
+
+ /* Allocate new RBNode from current chunk */
+ ea = accum->entryallocator + accum->length;
+ accum->length++;
+
+ return (RBNode *) ea;
+}
+
void
ginInitBA(BuildAccumulator *accum)
{
accum->allocatedMemory = 0;
+ accum->length = 0;
accum->entryallocator = NULL;
- accum->tree = rb_create(cmpEntryAccumulator, ginAppendData, NULL, accum);
- accum->iterator = NULL;
- accum->tmpList = NULL;
+ accum->tree = rb_create(sizeof(EntryAccumulator),
+ cmpEntryAccumulator,
+ ginCombineData,
+ ginAllocEntryAccumulator,
+ NULL, /* no freefunc needed */
+ (void *) accum);
}
/*
@@ -104,55 +136,41 @@ getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
static void
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum entry)
{
- EntryAccumulator *key,
- *ea;
+ EntryAccumulator key;
+ EntryAccumulator *ea;
+ bool isNew;
/*
- * Allocate memory by rather big chunk to decrease overhead, we don't keep
- * pointer to previously allocated chunks because they will free by
- * MemoryContextReset() call.
+ * For the moment, fill only the fields of key that will be looked at
+ * by cmpEntryAccumulator or ginCombineData.
*/
- if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
- {
- accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
- accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
- accum->length = 0;
- }
+ key.attnum = attnum;
+ key.value = entry;
+ /* temporarily set up single-entry itempointer list */
+ key.list = heapptr;
- /* "Allocate" new key in chunk */
- key = accum->entryallocator + accum->length;
- accum->length++;
+ ea = (EntryAccumulator *) rb_insert(accum->tree, (RBNode *) &key, &isNew);
- key->attnum = attnum;
- key->value = entry;
- /* To prevent multiple palloc/pfree cycles, we reuse array */
- if (accum->tmpList == NULL)
- accum->tmpList =
- (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
- key->list = accum->tmpList;
- key->list[0] = *heapptr;
-
- ea = rb_insert(accum->tree, key);
-
- if (ea == NULL)
+ if (isNew)
{
/*
- * The key has been inserted, so continue initialization.
+ * Finish initializing new tree entry, including making permanent
+ * copies of the datum and itempointer.
*/
- key->value = getDatumCopy(accum, attnum, entry);
- key->length = DEF_NPTR;
- key->number = 1;
- key->shouldSort = FALSE;
- accum->allocatedMemory += GetMemoryChunkSpace(key->list);
- accum->tmpList = NULL;
+ ea->value = getDatumCopy(accum, attnum, entry);
+ ea->length = DEF_NPTR;
+ ea->number = 1;
+ ea->shouldSort = FALSE;
+ ea->list =
+ (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
+ ea->list[0] = *heapptr;
+ accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
}
else
{
/*
- * The key has been appended, so "free" allocated key by decrementing
- * chunk's counter.
+ * ginCombineData did everything needed.
*/
- accum->length--;
}
}
@@ -214,16 +232,20 @@ qsortCompareItemPointers(const void *a, const void *b)
return res;
}
+/* Prepare to read out the rbtree contents using ginGetEntry */
+void
+ginBeginBAScan(BuildAccumulator *accum)
+{
+ rb_begin_iterate(accum->tree, LeftRightWalk);
+}
+
ItemPointerData *
ginGetEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *value, uint32 *n)
{
EntryAccumulator *entry;
ItemPointerData *list;
- if (accum->iterator == NULL)
- accum->iterator = rb_begin_iterate(accum->tree, LeftRightWalk);
-
- entry = rb_iterate(accum->iterator);
+ entry = (EntryAccumulator *) rb_iterate(accum->tree);
if (entry == NULL)
return NULL;
diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c
index 6d307c8d59a..1896e09a544 100644
--- a/src/backend/access/gin/ginentrypage.c
+++ b/src/backend/access/gin/ginentrypage.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.24 2010/02/26 02:00:33 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.24.4.1 2010/08/01 02:12:51 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -615,7 +615,7 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
}
/*
- * return newly allocate rightmost tuple
+ * return newly allocated rightmost tuple
*/
IndexTuple
ginPageGetLinkItup(Buffer buf)
@@ -646,10 +646,12 @@ entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
itup = ginPageGetLinkItup(lbuf);
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page");
+ pfree(itup);
itup = ginPageGetLinkItup(rbuf);
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page");
+ pfree(itup);
}
void
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index f8e0b5ad40f..7aaab3a132e 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.7 2010/02/11 14:29:50 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginfast.c,v 1.7.6.1 2010/08/01 02:12:51 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -786,6 +786,7 @@ ginInsertCleanup(Relation index, GinState *ginstate,
* significant amount of time - so, run it without locking pending
* list.
*/
+ ginBeginBAScan(&accum);
while ((list = ginGetEntry(&accum, &attnum, &entry, &nlist)) != NULL)
{
ginEntryInsert(index, ginstate, attnum, entry, list, nlist, FALSE);
@@ -820,6 +821,7 @@ ginInsertCleanup(Relation index, GinState *ginstate,
ginInitBA(&accum);
processPendingPage(&accum, &datums, page, maxoff + 1);
+ ginBeginBAScan(&accum);
while ((list = ginGetEntry(&accum, &attnum, &entry, &nlist)) != NULL)
ginEntryInsert(index, ginstate, attnum, entry, list, nlist, FALSE);
}
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index e2a5e8b0135..951d6166a00 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.26 2010/02/11 14:29:50 teodor Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.26.6.1 2010/08/01 02:12:51 tgl Exp $
*-------------------------------------------------------------------------
*/
@@ -176,6 +176,7 @@ ginEntryInsert(Relation index, GinState *ginstate,
gdi = prepareScanPostingTree(index, rootPostingTree, FALSE);
gdi->btree.isBuild = isBuild;
insertItemPointer(gdi, items, nitem);
+ pfree(gdi);
return;
}
@@ -254,6 +255,7 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
uint32 nlist;
OffsetNumber attnum;
+ ginBeginBAScan(&buildstate->accum);
while ((list = ginGetEntry(&buildstate->accum, &attnum, &entry, &nlist)) != NULL)
{
/* there could be many entries, so be willing to abort here */
@@ -360,6 +362,7 @@ ginbuild(PG_FUNCTION_ARGS)
/* dump remaining entries to the index */
oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
+ ginBeginBAScan(&buildstate.accum);
while ((list = ginGetEntry(&buildstate.accum, &attnum, &entry, &nlist)) != NULL)
{
/* there could be many entries, so be willing to abort here */