aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginfast.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gin/ginfast.c')
-rw-r--r--src/backend/access/gin/ginfast.c181
1 files changed, 113 insertions, 68 deletions
diff --git a/src/backend/access/gin/ginfast.c b/src/backend/access/gin/ginfast.c
index 3941f7eb007..9960c786c94 100644
--- a/src/backend/access/gin/ginfast.c
+++ b/src/backend/access/gin/ginfast.c
@@ -18,8 +18,7 @@
#include "postgres.h"
-#include "access/genam.h"
-#include "access/gin.h"
+#include "access/gin_private.h"
#include "catalog/index.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
@@ -30,12 +29,13 @@
#define GIN_PAGE_FREESIZE \
( BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - MAXALIGN(sizeof(GinPageOpaqueData)) )
-typedef struct DatumArray
+typedef struct KeyArray
{
- Datum *values; /* expansible array */
+ Datum *keys; /* expansible array */
+ GinNullCategory *categories; /* another expansible array */
int32 nvalues; /* current number of valid entries */
- int32 maxvalues; /* allocated size of array */
-} DatumArray;
+ int32 maxvalues; /* allocated size of arrays */
+} KeyArray;
/*
@@ -88,8 +88,9 @@ writeListPage(Relation index, Buffer buffer,
GinPageGetOpaque(page)->rightlink = rightlink;
/*
- * tail page may contain only the whole row(s) or final part of row placed
- * on previous pages
+ * tail page may contain only whole row(s) or final part of row placed
+ * on previous pages (a "row" here meaning all the index tuples generated
+ * for one heap tuple)
*/
if (rightlink == InvalidBlockNumber)
{
@@ -210,13 +211,16 @@ makeSublist(Relation index, IndexTuple *tuples, int32 ntuples,
}
/*
- * Inserts collected values during normal insertion. Function guarantees
- * that all values of heap will be stored sequentially, preserving order
+ * Write the index tuples contained in *collector into the index's
+ * pending list.
+ *
+ * Function guarantees that all these tuples will be inserted consecutively,
+ * preserving order
*/
void
-ginHeapTupleFastInsert(Relation index, GinState *ginstate,
- GinTupleCollector *collector)
+ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
{
+ Relation index = ginstate->index;
Buffer metabuffer;
Page metapage;
GinMetaPageData *metadata = NULL;
@@ -291,7 +295,12 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
*/
START_CRIT_SECTION();
- memcpy(metadata, &sublist, sizeof(GinMetaPageData));
+ metadata->head = sublist.head;
+ metadata->tail = sublist.tail;
+ metadata->tailFreeSize = sublist.tailFreeSize;
+
+ metadata->nPendingPages = sublist.nPendingPages;
+ metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
}
else
{
@@ -421,34 +430,40 @@ ginHeapTupleFastInsert(Relation index, GinState *ginstate,
END_CRIT_SECTION();
if (needCleanup)
- ginInsertCleanup(index, ginstate, false, NULL);
+ ginInsertCleanup(ginstate, false, NULL);
}
/*
- * Collect values from one tuples to be indexed. All values for
- * one tuples should be written at once - to guarantee consistent state
+ * Create temporary index tuples for a single indexable item (one index column
+ * for the heap tuple specified by ht_ctid), and append them to the array
+ * in *collector. They will subsequently be written out using
+ * ginHeapTupleFastInsert. Note that to guarantee consistent state, all
+ * temp tuples for a given heap tuple must be written in one call to
+ * ginHeapTupleFastInsert.
*/
-uint32
-ginHeapTupleFastCollect(Relation index, GinState *ginstate,
+void
+ginHeapTupleFastCollect(GinState *ginstate,
GinTupleCollector *collector,
- OffsetNumber attnum, Datum value, ItemPointer item)
+ OffsetNumber attnum, Datum value, bool isNull,
+ ItemPointer ht_ctid)
{
Datum *entries;
+ GinNullCategory *categories;
int32 i,
nentries;
- entries = ginExtractEntriesSU(ginstate, attnum, value, &nentries);
-
- if (nentries == 0)
- /* nothing to insert */
- return 0;
+ /*
+ * Extract the key values that need to be inserted in the index
+ */
+ entries = ginExtractEntries(ginstate, attnum, value, isNull,
+ &nentries, &categories);
/*
* Allocate/reallocate memory for storing collected tuples
*/
if (collector->tuples == NULL)
{
- collector->lentuples = nentries * index->rd_att->natts;
+ collector->lentuples = nentries * ginstate->origTupdesc->natts;
collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples);
}
@@ -460,19 +475,19 @@ ginHeapTupleFastCollect(Relation index, GinState *ginstate,
}
/*
- * Creates tuple's array
+ * Build an index tuple for each key value, and add to array. In
+ * pending tuples we just stick the heap TID into t_tid.
*/
for (i = 0; i < nentries; i++)
{
- collector->tuples[collector->ntuples + i] =
- GinFormTuple(index, ginstate, attnum, entries[i], NULL, 0, true);
- collector->tuples[collector->ntuples + i]->t_tid = *item;
- collector->sumsize += IndexTupleSize(collector->tuples[collector->ntuples + i]);
- }
+ IndexTuple itup;
- collector->ntuples += nentries;
-
- return nentries;
+ itup = GinFormTuple(ginstate, attnum, entries[i], categories[i],
+ NULL, 0, true);
+ itup->t_tid = *ht_ctid;
+ collector->tuples[collector->ntuples++] = itup;
+ collector->sumsize += IndexTupleSize(itup);
+ }
}
/*
@@ -591,38 +606,55 @@ shiftList(Relation index, Buffer metabuffer, BlockNumber newHead,
return false;
}
-/* Add datum to DatumArray, resizing if needed */
+/* Initialize empty KeyArray */
static void
-addDatum(DatumArray *datums, Datum datum)
+initKeyArray(KeyArray *keys, int32 maxvalues)
{
- if (datums->nvalues >= datums->maxvalues)
+ keys->keys = (Datum *) palloc(sizeof(Datum) * maxvalues);
+ keys->categories = (GinNullCategory *)
+ palloc(sizeof(GinNullCategory) * maxvalues);
+ keys->nvalues = 0;
+ keys->maxvalues = maxvalues;
+}
+
+/* Add datum to KeyArray, resizing if needed */
+static void
+addDatum(KeyArray *keys, Datum datum, GinNullCategory category)
+{
+ if (keys->nvalues >= keys->maxvalues)
{
- datums->maxvalues *= 2;
- datums->values = (Datum *) repalloc(datums->values,
- sizeof(Datum) * datums->maxvalues);
+ keys->maxvalues *= 2;
+ keys->keys = (Datum *)
+ repalloc(keys->keys, sizeof(Datum) * keys->maxvalues);
+ keys->categories = (GinNullCategory *)
+ repalloc(keys->categories, sizeof(GinNullCategory) * keys->maxvalues);
}
- datums->values[datums->nvalues++] = datum;
+ keys->keys[keys->nvalues] = datum;
+ keys->categories[keys->nvalues] = category;
+ keys->nvalues++;
}
/*
- * Go through all tuples >= startoff on page and collect values in memory
+ * Collect data from a pending-list page in preparation for insertion into
+ * the main index.
+ *
+ * Go through all tuples >= startoff on page and collect values in accum
*
- * Note that da is just workspace --- it does not carry any state across
+ * Note that ka is just workspace --- it does not carry any state across
* calls.
*/
static void
-processPendingPage(BuildAccumulator *accum, DatumArray *da,
+processPendingPage(BuildAccumulator *accum, KeyArray *ka,
Page page, OffsetNumber startoff)
{
ItemPointerData heapptr;
OffsetNumber i,
maxoff;
- OffsetNumber attrnum,
- curattnum;
+ OffsetNumber attrnum;
- /* reset *da to empty */
- da->nvalues = 0;
+ /* reset *ka to empty */
+ ka->nvalues = 0;
maxoff = PageGetMaxOffsetNumber(page);
Assert(maxoff >= FirstOffsetNumber);
@@ -632,7 +664,11 @@ processPendingPage(BuildAccumulator *accum, DatumArray *da,
for (i = startoff; i <= maxoff; i = OffsetNumberNext(i))
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
+ OffsetNumber curattnum;
+ Datum curkey;
+ GinNullCategory curcategory;
+ /* Check for change of heap TID or attnum */
curattnum = gintuple_get_attrnum(accum->ginstate, itup);
if (!ItemPointerIsValid(&heapptr))
@@ -644,18 +680,25 @@ processPendingPage(BuildAccumulator *accum, DatumArray *da,
curattnum == attrnum))
{
/*
- * We can insert several datums per call, but only for one heap
- * tuple and one column.
+ * ginInsertBAEntries can insert several datums per call, but only
+ * for one heap tuple and one column. So call it at a boundary,
+ * and reset ka.
*/
- ginInsertRecordBA(accum, &heapptr, attrnum, da->values, da->nvalues);
- da->nvalues = 0;
+ ginInsertBAEntries(accum, &heapptr, attrnum,
+ ka->keys, ka->categories, ka->nvalues);
+ ka->nvalues = 0;
heapptr = itup->t_tid;
attrnum = curattnum;
}
- addDatum(da, gin_index_getattr(accum->ginstate, itup));
+
+ /* Add key to KeyArray */
+ curkey = gintuple_get_key(accum->ginstate, itup, &curcategory);
+ addDatum(ka, curkey, curcategory);
}
- ginInsertRecordBA(accum, &heapptr, attrnum, da->values, da->nvalues);
+ /* Dump out all remaining keys */
+ ginInsertBAEntries(accum, &heapptr, attrnum,
+ ka->keys, ka->categories, ka->nvalues);
}
/*
@@ -679,9 +722,10 @@ processPendingPage(BuildAccumulator *accum, DatumArray *da,
* If stats isn't null, we count deleted pending pages into the counts.
*/
void
-ginInsertCleanup(Relation index, GinState *ginstate,
+ginInsertCleanup(GinState *ginstate,
bool vac_delay, IndexBulkDeleteResult *stats)
{
+ Relation index = ginstate->index;
Buffer metabuffer,
buffer;
Page metapage,
@@ -690,7 +734,7 @@ ginInsertCleanup(Relation index, GinState *ginstate,
MemoryContext opCtx,
oldCtx;
BuildAccumulator accum;
- DatumArray datums;
+ KeyArray datums;
BlockNumber blkno;
metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
@@ -726,10 +770,7 @@ ginInsertCleanup(Relation index, GinState *ginstate,
oldCtx = MemoryContextSwitchTo(opCtx);
- datums.maxvalues = 128;
- datums.nvalues = 0;
- datums.values = (Datum *) palloc(sizeof(Datum) * datums.maxvalues);
-
+ initKeyArray(&datums, 128);
ginInitBA(&accum);
accum.ginstate = ginstate;
@@ -748,7 +789,7 @@ ginInsertCleanup(Relation index, GinState *ginstate,
}
/*
- * read page's datums into memory
+ * read page's datums into accum
*/
processPendingPage(&accum, &datums, page, FirstOffsetNumber);
@@ -769,7 +810,8 @@ ginInsertCleanup(Relation index, GinState *ginstate,
{
ItemPointerData *list;
uint32 nlist;
- Datum entry;
+ Datum key;
+ GinNullCategory category;
OffsetNumber maxoff,
attnum;
@@ -787,9 +829,11 @@ ginInsertCleanup(Relation index, GinState *ginstate,
* list.
*/
ginBeginBAScan(&accum);
- while ((list = ginGetEntry(&accum, &attnum, &entry, &nlist)) != NULL)
+ while ((list = ginGetBAEntry(&accum,
+ &attnum, &key, &category, &nlist)) != NULL)
{
- ginEntryInsert(index, ginstate, attnum, entry, list, nlist, NULL);
+ ginEntryInsert(ginstate, attnum, key, category,
+ list, nlist, NULL);
if (vac_delay)
vacuum_delay_point();
}
@@ -822,8 +866,10 @@ ginInsertCleanup(Relation index, GinState *ginstate,
processPendingPage(&accum, &datums, page, maxoff + 1);
ginBeginBAScan(&accum);
- while ((list = ginGetEntry(&accum, &attnum, &entry, &nlist)) != NULL)
- ginEntryInsert(index, ginstate, attnum, entry, list, nlist, NULL);
+ while ((list = ginGetBAEntry(&accum,
+ &attnum, &key, &category, &nlist)) != NULL)
+ ginEntryInsert(ginstate, attnum, key, category,
+ list, nlist, NULL);
}
/*
@@ -857,9 +903,8 @@ ginInsertCleanup(Relation index, GinState *ginstate,
* release memory used so far and reinit state
*/
MemoryContextReset(opCtx);
+ initKeyArray(&datums, datums.maxvalues);
ginInitBA(&accum);
- datums.nvalues = 0;
- datums.values = (Datum *) palloc(sizeof(Datum) * datums.maxvalues);
}
else
{