/* * Merge two ordered arrays of itempointers, eliminating any duplicates. * * Returns a palloc'd array, and *nmerged is set to the number of items in * the result, after eliminating duplicates. */ ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged) { ItemPointerData *dst; dst = (ItemPointer) palloc((na + nb) * sizeof(ItemPointerData)); /* * If the argument arrays don't overlap, we can just append them to each * other. */ if (na == 0 || nb == 0 || ginCompareItemPointers(&a[na - 1], &b[0]) < 0) { memcpy(dst, a, na * sizeof(ItemPointerData)); memcpy(&dst[na], b, nb * sizeof(ItemPointerData)); *nmerged = na + nb; } else if (ginCompareItemPointers(&b[nb - 1], &a[0]) < 0) { memcpy(dst, b, nb * sizeof(ItemPointerData)); memcpy(&dst[nb], a, na * sizeof(ItemPointerData)); *nmerged = na + nb; } else { ItemPointerData *dptr = dst; ItemPointerData *aptr = a; ItemPointerData *bptr = b; while (aptr - a < na && bptr - b < nb) { int cmp = ginCompareItemPointers(aptr, bptr); if (cmp > 0) *dptr++ = *bptr++; else if (cmp == 0) { /* only keep one copy of the identical items */ *dptr++ = *bptr++; aptr++; } else *dptr++ = *aptr++; } while (aptr - a < na) *dptr++ = *aptr++; while (bptr - b < nb) *dptr++ = *bptr++; *nmerged = dptr - dst; } return dst; }
/* * Merge two ordered arrays of itempointers, eliminating any duplicates. * Returns the number of items in the result. * Caller is responsible that there is enough space at *dst. * * It's OK if 'dst' overlaps with the *beginning* of one of the arguments. */ int ginMergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) { ItemPointerData *dptr = dst; ItemPointerData *aptr = a, *bptr = b; int result; /* * If the argument arrays don't overlap, we can just append them to * each other. */ if (na == 0 || nb == 0 || ginCompareItemPointers(&a[na - 1], &b[0]) < 0) { memmove(dst, a, na * sizeof(ItemPointerData)); memmove(&dst[na], b, nb * sizeof(ItemPointerData)); result = na + nb; } else if (ginCompareItemPointers(&b[nb - 1], &a[0]) < 0) { memmove(dst, b, nb * sizeof(ItemPointerData)); memmove(&dst[nb], a, na * sizeof(ItemPointerData)); result = na + nb; } else { while (aptr - a < na && bptr - b < nb) { int cmp = ginCompareItemPointers(aptr, bptr); if (cmp > 0) *dptr++ = *bptr++; else if (cmp == 0) { /* only keep one copy of the identical items */ *dptr++ = *bptr++; aptr++; } else *dptr++ = *aptr++; } while (aptr - a < na) *dptr++ = *aptr++; while (bptr - b < nb) *dptr++ = *bptr++; result = dptr - dst; } return result; }
/* * Merge two ordered arrays of itempointers, eliminating any duplicates. * Returns the number of items in the result. * Caller is responsible that there is enough space at *dst. */ uint32 ginMergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) { ItemPointerData *dptr = dst; ItemPointerData *aptr = a, *bptr = b; while (aptr - a < na && bptr - b < nb) { int cmp = ginCompareItemPointers(aptr, bptr); if (cmp > 0) *dptr++ = *bptr++; else if (cmp == 0) { /* we want only one copy of the identical items */ *dptr++ = *bptr++; aptr++; } else *dptr++ = *aptr++; } while (aptr - a < na) *dptr++ = *aptr++; while (bptr - b < nb) *dptr++ = *bptr++; return dptr - dst; }
/* Combiner function for rbtree.c */ static void ginCombineData(RBNode *existing, const RBNode *newdata, void *arg) { GinEntryAccumulator *eo = (GinEntryAccumulator *) existing; const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata; BuildAccumulator *accum = (BuildAccumulator *) arg; /* * Note this code assumes that newdata contains only one itempointer. */ if (eo->count >= eo->maxcount) { accum->allocatedMemory -= GetMemoryChunkSpace(eo->list); eo->maxcount *= 2; eo->list = (ItemPointerData *) repalloc(eo->list, sizeof(ItemPointerData) * eo->maxcount); accum->allocatedMemory += GetMemoryChunkSpace(eo->list); } /* If item pointers are not ordered, they will need to be sorted later */ if (eo->shouldSort == FALSE) { int res; res = ginCompareItemPointers(eo->list + eo->count - 1, en->list); Assert(res != 0); if (res > 0) eo->shouldSort = TRUE; } eo->list[eo->count] = en->list[0]; eo->count++; }
static int qsortCompareItemPointers(const void *a, const void *b) { int res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b); Assert(res != 0); return res; }
static int qsortCompareItemPointers(const void *a, const void *b) { int res = ginCompareItemPointers((ItemPointer) a, (ItemPointer) b); /* Assert that there are no equal item pointers being sorted */ Assert(res != 0); return res; }
/* * Decode multiple posting list segments into an array of item pointers. * The number of items is returned in *ndecoded_out. The segments are stored * one after each other, with total size 'len' bytes. */ ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out) { ItemPointer result; int nallocated; uint64 val; char *endseg = ((char *) segment) + len; int ndecoded; unsigned char *ptr; unsigned char *endptr; /* * Guess an initial size of the array. */ nallocated = segment->nbytes * 2 + 1; result = palloc(nallocated * sizeof(ItemPointerData)); ndecoded = 0; while ((char *) segment < endseg) { /* enlarge output array if needed */ if (ndecoded >= nallocated) { nallocated *= 2; result = repalloc(result, nallocated * sizeof(ItemPointerData)); } /* copy the first item */ Assert(OffsetNumberIsValid(ItemPointerGetOffsetNumber(&segment->first))); Assert(ndecoded == 0 || ginCompareItemPointers(&segment->first, &result[ndecoded - 1]) > 0); result[ndecoded] = segment->first; ndecoded++; val = itemptr_to_uint64(&segment->first); ptr = segment->bytes; endptr = segment->bytes + segment->nbytes; while (ptr < endptr) { /* enlarge output array if needed */ if (ndecoded >= nallocated) { nallocated *= 2; result = repalloc(result, nallocated * sizeof(ItemPointerData)); } val += decode_varbyte(&ptr); uint64_to_itemptr(val, &result[ndecoded]); ndecoded++; } segment = GinNextPostingListSegment(segment); } if (ndecoded_out) *ndecoded_out = ndecoded; return result; }
/* * Checks, should we move to right link... * Compares inserting itemp pointer with right bound of current page */ static bool dataIsMoveRight(GinBtree btree, Page page) { ItemPointer iptr = GinDataPageGetRightBound(page); if (GinPageRightMost(page)) return FALSE; return (ginCompareItemPointers(btree->items + btree->curitem, iptr) > 0) ? TRUE : FALSE; }
/* * Searches correct position for value on leaf page. * Page should be correctly chosen. * Returns true if value found on page. */ static bool dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) { Page page = BufferGetPage(stack->buffer); OffsetNumber low, high; int result; Assert(GinPageIsLeaf(page)); Assert(GinPageIsData(page)); if (btree->fullScan) { stack->off = FirstOffsetNumber; return TRUE; } low = FirstOffsetNumber; high = GinPageGetOpaque(page)->maxoff; if (high < low) { stack->off = FirstOffsetNumber; return false; } high++; while (high > low) { OffsetNumber mid = low + ((high - low) / 2); result = ginCompareItemPointers(&btree->itemptr, GinDataPageGetItemPointer(page, mid)); if (result == 0) { stack->off = mid; return true; } else if (result > 0) low = mid + 1; else high = mid; } stack->off = high; return false; }
/* Combiner function for rbtree.c */ static void ginCombineData(RBNode *existing, const RBNode *newdata, void *arg) { GinEntryAccumulator *eo = (GinEntryAccumulator *) existing; const GinEntryAccumulator *en = (const GinEntryAccumulator *) newdata; BuildAccumulator *accum = (BuildAccumulator *) arg; /* * Note this code assumes that newdata contains only one itempointer. */ if (eo->count >= eo->maxcount) { if (eo->maxcount > INT_MAX) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("posting list is too long"), errhint("Reduce maintenance_work_mem."))); accum->allocatedMemory -= GetMemoryChunkSpace(eo->list); eo->maxcount *= 2; eo->list = (ItemPointerData *) repalloc_huge(eo->list, sizeof(ItemPointerData) * eo->maxcount); accum->allocatedMemory += GetMemoryChunkSpace(eo->list); } /* If item pointers are not ordered, they will need to be sorted later */ if (eo->shouldSort == FALSE) { int res; res = ginCompareItemPointers(eo->list + eo->count - 1, en->list); Assert(res != 0); if (res > 0) eo->shouldSort = TRUE; } eo->list[eo->count] = en->list[0]; eo->count++; }
/* * Find correct PostingItem in non-leaf page. It supposed that page * correctly chosen and searching value SHOULD be on page */ static BlockNumber dataLocateItem(GinBtree btree, GinBtreeStack *stack) { OffsetNumber low, high, maxoff; PostingItem *pitem = NULL; int result; Page page = BufferGetPage(stack->buffer); Assert(!GinPageIsLeaf(page)); Assert(GinPageIsData(page)); if (btree->fullScan) { stack->off = FirstOffsetNumber; stack->predictNumber *= GinPageGetOpaque(page)->maxoff; return btree->getLeftMostPage(btree, page); } low = FirstOffsetNumber; maxoff = high = GinPageGetOpaque(page)->maxoff; Assert(high >= low); high++; while (high > low) { OffsetNumber mid = low + ((high - low) / 2); pitem = (PostingItem *) GinDataPageGetItem(page, mid); if (mid == maxoff) { /* * Right infinity, page already correctly chosen with a help of * dataIsMoveRight */ result = -1; } else { pitem = (PostingItem *) GinDataPageGetItem(page, mid); result = ginCompareItemPointers(btree->items + btree->curitem, &(pitem->key)); } if (result == 0) { stack->off = mid; return PostingItemGetBlockNumber(pitem); } else if (result > 0) low = mid + 1; else high = mid; } Assert(high >= FirstOffsetNumber && high <= maxoff); stack->off = high; pitem = (PostingItem *) GinDataPageGetItem(page, high); return PostingItemGetBlockNumber(pitem); }