From ab9a21492991e0f331ac830862ed557ca2574c44 Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Mon, 4 Jul 2016 10:30:37 +0500 Subject: [PATCH] PageIndexTupleOverwrite --- src/backend/access/gist/gist.c | 20 ++++++- src/backend/storage/page/bufpage.c | 104 +++++++++++++++++++++++++++++++++++++ src/include/storage/bufpage.h | 1 + 3 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index fdf0c5a..239971b 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -504,8 +504,24 @@ gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, * gistRedoPageUpdateRecord() */ if (OffsetNumberIsValid(oldoffnum)) - PageIndexTupleDelete(page, oldoffnum); - gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + { + /*if we have just one tuple to update we replace it on-place on page*/ + if(ntup==1) + { + PageIndexTupleOverwrite(page,oldoffnum,*itup); + } + else + { + /*this corner case is here to support mix calls case (see comment above)*/ + PageIndexTupleDelete(page, oldoffnum); + gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + } + } + else + { + /*just append all tuples at the end of a page*/ + gistfillbuffer(page, itup, ntup, InvalidOffsetNumber); + } MarkBufferDirty(buffer); diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index f2a07f2..e75f42d 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -707,6 +707,110 @@ PageGetHeapFreeSpace(Page page) /* + * PageIndexTupleOverwrite + * + * This routine does the work of overwriting a tuple on an index page. + * + * Unlike heap pages, we keep compacted line pointers. + */ +void +PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup) +{ + PageHeader phdr = (PageHeader) page; + char *addr; + ItemId tup; + int size_diff; + int oldsize; + unsigned offset; + int newsize; + int nline; + + /* + * As with PageIndexTupleDelete, paranoia is told to be justified. + */ + if (phdr->pd_lower < SizeOfPageHeaderData || + phdr->pd_lower > phdr->pd_upper || + phdr->pd_upper > phdr->pd_special || + phdr->pd_special > BLCKSZ) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted page pointers: lower = %u, upper = %u, special = %u", + phdr->pd_lower, phdr->pd_upper, phdr->pd_special))); + + + + nline = PageGetMaxOffsetNumber(page); + if ((int) offnum <= 0 || (int) offnum > nline) + elog(ERROR, "invalid index offnum: %u", offnum); + + tup = PageGetItemId(page, offnum); + + + Assert(ItemIdHasStorage(tup)); + + newsize = IndexTupleSize(newtup); + oldsize = ItemIdGetLength(tup); + /*may have negative size here if new tuple is larger*/ + size_diff = oldsize-newsize; + offset = ItemIdGetOffset(tup); + + + if (offset < phdr->pd_upper || (offset + size_diff) > phdr->pd_special || + offset != MAXALIGN(offset) || size_diff != MAXALIGN(size_diff)) + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg("corrupted item pointer: offset = %u, size = %u", + offset, (unsigned int) size_diff))); + + + /* + * Now move everything between the old upper bound (beginning of tuple + * space) and the end of the overwritten tuple forward, so that space in + * the middle of the page is left free. If we've just deleted the tuple + * at the beginning of tuple space, then there's no need to do the copy + * (and bcopy on some architectures SEGV's if asked to move zero bytes). + */ + + /* beginning of tuple space */ + addr = (char *) page + phdr->pd_upper; + + //elog(WARNING,"old %u new %u diff %d offset %u offnum %u movesize %d",oldsize,newsize,size_diff,offset, offnum,(int) (offset - phdr->pd_upper)); + + if (size_diff!=0) + { + int i; + memmove(addr + size_diff, addr, (int) (offset - phdr->pd_upper)); + + /* adjust free space boundary pointers */ + phdr->pd_upper += size_diff; + + /* + * we need to adjust the linp entries that remain. + * + * Anything that used to be before the deleted tuple's data was moved + * forward by the size of the deleted tuple. + */ + + for (i = 1; i <= nline; i++) + { + ItemId ii = PageGetItemId(phdr, i); + + Assert(ItemIdHasStorage(ii)); + if (ItemIdGetOffset(ii) <= offset) + ii->lp_off += size_diff; + } + } + + /*Fix updated tuple length*/ + tup = PageGetItemId(page, offnum); + tup->lp_len = newsize; + + /*now place new tuple on page*/ + memmove((char *) page + offset + size_diff, newtup, newsize); +} + + +/* * PageIndexTupleDelete * * This routine does the work of removing a tuple from an index page. diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h index 15cebfc..780e982 100644 --- a/src/include/storage/bufpage.h +++ b/src/include/storage/bufpage.h @@ -426,6 +426,7 @@ extern Size PageGetFreeSpace(Page page); extern Size PageGetExactFreeSpace(Page page); extern Size PageGetHeapFreeSpace(Page page); extern void PageIndexTupleDelete(Page page, OffsetNumber offset); +extern void PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup); extern void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems); extern void PageIndexDeleteNoCompact(Page page, OffsetNumber *itemnos, int nitems); -- 2.7.0.windows.1