1 /*-------------------------------------------------------------------------
4 * routines for fast build of inverted index
7 * Portions Copyright (c) 1996-2008, 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.11 2008/01/01 19:45:46 momjian 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 we duplicate some code
82 * to avoid computing the datum size twice.
85 getDatumCopy(BuildAccumulator *accum, Datum value)
87 Form_pg_attribute *att = accum->ginstate->tupdesc->attrs;
97 realSize = datumGetSize(value, false, att[0]->attlen);
99 s = (char *) palloc(realSize);
100 accum->allocatedMemory += GetMemoryChunkSpace(s);
102 memcpy(s, DatumGetPointer(value), realSize);
103 res = PointerGetDatum(s);
109 * Find/store one entry from indexed value.
112 ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
114 EntryAccumulator *ea = accum->entries,
121 res = compareEntries(accum->ginstate, entry, ea->value);
135 if (depth > accum->maxdepth)
136 accum->maxdepth = depth;
140 ea = EAAllocate(accum);
142 ea->left = ea->right = NULL;
143 ea->value = getDatumCopy(accum, entry);
144 ea->length = DEF_NPTR;
146 ea->shouldSort = FALSE;
147 ea->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
148 accum->allocatedMemory += GetMemoryChunkSpace(ea->list);
149 ea->list[0] = *heapptr;
163 ginInsertData(accum, ea, heapptr);
167 * insert middle of left part the middle of right one,
168 * then calls itself for each parts
171 ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
172 uint32 low, uint32 high, uint32 offset)
175 uint32 middle = (low + high) >> 1;
177 pos = (low + middle) >> 1;
178 if (low != middle && pos >= offset && pos - offset < nentry)
179 ginInsertEntry(accum, heapptr, entries[pos - offset]);
180 pos = (high + middle + 1) >> 1;
181 if (middle + 1 != high && pos >= offset && pos - offset < nentry)
182 ginInsertEntry(accum, heapptr, entries[pos - offset]);
185 ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset);
186 if (high != middle + 1)
187 ginChooseElem(accum, heapptr, entries, nentry, middle + 1, high, offset);
191 * Insert one heap pointer. Suppose entries is sorted.
192 * Insertion order tries to get binary tree balanced: first insert middle value,
193 * next middle on left part and middle of right part.
196 ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, int32 nentry)
206 for (; i > 0; i >>= 1)
210 offset = (nbit - nentry) / 2;
212 ginInsertEntry(accum, heapptr, entries[(nbit >> 1) - offset]);
213 ginChooseElem(accum, heapptr, entries, nentry, 0, nbit, offset);
217 qsortCompareItemPointers(const void *a, const void *b)
219 int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
226 * walk on binary tree and returns ordered nodes
228 static EntryAccumulator *
229 walkTree(BuildAccumulator *accum)
231 EntryAccumulator *entry = accum->stack[accum->stackpos];
233 if (entry->list != NULL)
235 /* return entry itself: we already was at left sublink */
238 else if (entry->right && entry->right != accum->stack[accum->stackpos + 1])
240 /* go on right sublink */
242 entry = entry->right;
244 /* find most-left value */
247 accum->stack[accum->stackpos] = entry;
259 /* we already return all left subtree, itself and right subtree */
260 if (accum->stackpos == 0)
263 return walkTree(accum);
270 ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
272 EntryAccumulator *entry;
273 ItemPointerData *list;
275 if (accum->stack == NULL)
278 accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
279 accum->allocatedMemory += GetMemoryChunkSpace(accum->stack);
280 entry = accum->entries;
285 /* find most-left value */
288 accum->stack[accum->stackpos] = entry;
300 accum->allocatedMemory -= GetMemoryChunkSpace(accum->stack[accum->stackpos]->list);
301 pfree(accum->stack[accum->stackpos]->list);
302 accum->stack[accum->stackpos]->list = NULL;
303 entry = walkTree(accum);
310 *value = entry->value;
313 Assert(list != NULL);
315 if (entry->shouldSort && entry->number > 1)
316 qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);