1 /*-------------------------------------------------------------------------
4 * routines for fast build of inverted index
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.15 2009/03/24 20:17:10 tgl Exp $
12 *-------------------------------------------------------------------------
17 #include "access/gin.h"
18 #include "utils/datum.h"
19 #include "utils/memutils.h"
22 #define DEF_NENTRY 2048
26 ginInitBA(BuildAccumulator *accum)
30 accum->entries = NULL;
32 accum->allocatedMemory = 0;
33 accum->entryallocator = NULL;
36 static EntryAccumulator *
37 EAAllocate(BuildAccumulator *accum)
39 if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
41 accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
42 accum->allocatedMemory += GetMemoryChunkSpace(accum->entryallocator);
47 return accum->entryallocator + accum->length - 1;
51 * Stores heap item pointer. For robust, it checks that
52 * item pointer are ordered
55 ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr)
57 if (entry->number >= entry->length)
59 accum->allocatedMemory -= GetMemoryChunkSpace(entry->list);
61 entry->list = (ItemPointerData *) repalloc(entry->list,
62 sizeof(ItemPointerData) * entry->length);
63 accum->allocatedMemory += GetMemoryChunkSpace(entry->list);
66 if (entry->shouldSort == FALSE)
68 int res = compareItemPointers(entry->list + entry->number - 1, heapptr);
73 entry->shouldSort = TRUE;
76 entry->list[entry->number] = *heapptr;
81 * This is basically the same as datumCopy(), but modified to count
82 * palloc'd space in accum.
85 getDatumCopy(BuildAccumulator *accum, OffsetNumber attnum, Datum value)
87 Form_pg_attribute att = accum->ginstate->origTupdesc->attrs[ attnum - 1 ];
94 res = datumCopy(value, false, att->attlen);
95 accum->allocatedMemory += GetMemoryChunkSpace(DatumGetPointer(res));
101 * Find/store one entry from indexed value.
104 ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum entry)
106 EntryAccumulator *ea = accum->entries,
113 res = compareAttEntries(accum->ginstate, attnum, entry, ea->attnum, ea->value);
127 if (depth > accum->maxdepth)
128 accum->maxdepth = depth;
132 ea = EAAllocate(accum);
134 ea->left = ea->right = NULL;
136 ea->value = getDatumCopy(accum, attnum, entry);
137 ea->length = DEF_NPTR;
139 ea->shouldSort = FALSE;
140 ea->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
141 accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
142 ea->list[0] = *heapptr;
156 ginInsertData(accum, ea, heapptr);
160 * insert middle of left part the middle of right one,
161 * then calls itself for each parts
164 ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum,
165 Datum *entries, uint32 nentry,
166 uint32 low, uint32 high, uint32 offset)
169 uint32 middle = (low + high) >> 1;
171 pos = (low + middle) >> 1;
172 if (low != middle && pos >= offset && pos - offset < nentry)
173 ginInsertEntry(accum, heapptr, attnum, entries[pos - offset]);
174 pos = (high + middle + 1) >> 1;
175 if (middle + 1 != high && pos >= offset && pos - offset < nentry)
176 ginInsertEntry(accum, heapptr, attnum, entries[pos - offset]);
179 ginChooseElem(accum, heapptr, attnum, entries, nentry, low, middle, offset);
180 if (high != middle + 1)
181 ginChooseElem(accum, heapptr, attnum, entries, nentry, middle + 1, high, offset);
185 * Insert one heap pointer. Suppose entries is sorted.
186 * Insertion order tries to get binary tree balanced: first insert middle value,
187 * next middle on left part and middle of right part.
190 ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum,
191 Datum *entries, int32 nentry)
200 Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber);
203 for (; i > 0; i >>= 1)
207 offset = (nbit - nentry) / 2;
209 ginInsertEntry(accum, heapptr, attnum, entries[(nbit >> 1) - offset]);
210 ginChooseElem(accum, heapptr, attnum, entries, nentry, 0, nbit, offset);
214 qsortCompareItemPointers(const void *a, const void *b)
216 int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
223 * walk on binary tree and returns ordered nodes
225 static EntryAccumulator *
226 walkTree(BuildAccumulator *accum)
228 EntryAccumulator *entry = accum->stack[accum->stackpos];
230 if (entry->list != NULL)
232 /* return entry itself: we already was at left sublink */
235 else if (entry->right && entry->right != accum->stack[accum->stackpos + 1])
237 /* go on right sublink */
239 entry = entry->right;
241 /* find most-left value */
244 accum->stack[accum->stackpos] = entry;
256 /* we already return all left subtree, itself and right subtree */
257 if (accum->stackpos == 0)
260 return walkTree(accum);
267 ginGetEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *value, uint32 *n)
269 EntryAccumulator *entry;
270 ItemPointerData *list;
272 if (accum->stack == NULL)
275 accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
276 accum->allocatedMemory += GetMemoryChunkSpace(accum->stack);
277 entry = accum->entries;
282 /* find most-left value */
285 accum->stack[accum->stackpos] = entry;
297 accum->allocatedMemory -= GetMemoryChunkSpace(accum->stack[accum->stackpos]->list);
298 pfree(accum->stack[accum->stackpos]->list);
299 accum->stack[accum->stackpos]->list = NULL;
300 entry = walkTree(accum);
307 *attnum = entry->attnum;
308 *value = entry->value;
311 Assert(list != NULL);
313 if (entry->shouldSort && entry->number > 1)
314 qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);