Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 356eea2

Browse files
committed
Fix a serious bug introduced into GIN in 8.4: now that MergeItemPointers()
is supposed to remove duplicate heap TIDs, we have to be sure to reduce the tuple size and posting-item count accordingly in addItemPointersToTuple(). Failing to do so resulted in the effective injection of garbage TIDs into the index contents, ie, whatever happened to be in the memory palloc'd for the new tuple. I'm not sure that this fully explains the index corruption reported by Tatsuo Ishii, but the test case I'm using no longer fails.
1 parent 1978d7f commit 356eea2

File tree

4 files changed

+62
-26
lines changed

4 files changed

+62
-26
lines changed

src/backend/access/gin/gindatapage.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.14 2009/03/24 20:17:10 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.15 2009/06/06 02:39:40 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414

@@ -32,10 +32,14 @@ compareItemPointers(ItemPointer a, ItemPointer b)
3232
}
3333

3434
/*
35-
* Merge two ordered array of itempointer
35+
* Merge two ordered arrays of itempointers, eliminating any duplicates.
36+
* Returns the number of items in the result.
37+
* Caller is responsible that there is enough space at *dst.
3638
*/
37-
void
38-
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb)
39+
uint32
40+
MergeItemPointers(ItemPointerData *dst,
41+
ItemPointerData *a, uint32 na,
42+
ItemPointerData *b, uint32 nb)
3943
{
4044
ItemPointerData *dptr = dst;
4145
ItemPointerData *aptr = a,
@@ -62,6 +66,8 @@ MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPoint
6266

6367
while (bptr - b < nb)
6468
*dptr++ = *bptr++;
69+
70+
return dptr - dst;
6571
}
6672

6773
/*

src/backend/access/gin/ginentrypage.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.19 2009/01/01 17:23:34 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.20 2009/06/06 02:39:40 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414

@@ -20,28 +20,33 @@
2020
#include "utils/rel.h"
2121

2222
/*
23-
* forms tuple for entry tree. On leaf page, Index tuple has
24-
* non-traditional layout. Tuple may contain posting list or
25-
* root blocknumber of posting tree. Macros GinIsPostingTre: (itup) / GinSetPostingTree(itup, blkno)
23+
* Form a tuple for entry tree.
24+
*
25+
* On leaf pages, Index tuple has non-traditional layout. Tuple may contain
26+
* posting list or root blocknumber of posting tree.
27+
* Macros: GinIsPostingTree(itup) / GinSetPostingTree(itup, blkno)
2628
* 1) Posting list
27-
* - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usual
29+
* - itup->t_info & INDEX_SIZE_MASK contains total size of tuple as usual
2830
* - ItemPointerGetBlockNumber(&itup->t_tid) contains original
2931
* size of tuple (without posting list).
30-
* Macroses: GinGetOrigSizePosting(itup) / GinSetOrigSizePosting(itup,n)
32+
* Macros: GinGetOrigSizePosting(itup) / GinSetOrigSizePosting(itup,n)
3133
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains number
32-
* of elements in posting list (number of heap itempointer)
33-
* Macroses: GinGetNPosting(itup) / GinSetNPosting(itup,n)
34-
* - After usual part of tuple there is a posting list
34+
* of elements in posting list (number of heap itempointers)
35+
* Macros: GinGetNPosting(itup) / GinSetNPosting(itup,n)
36+
* - After standard part of tuple there is a posting list, ie, array
37+
* of heap itempointers
3538
* Macros: GinGetPosting(itup)
3639
* 2) Posting tree
3740
* - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usual
3841
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
3942
* root of posting tree
40-
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magic number GIN_TREE_POSTING
43+
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magic number
44+
* GIN_TREE_POSTING, which distinguishes this from posting-list case
4145
*
42-
* Storage of attributes of tuple are different for single and multicolumn index.
43-
* For single-column index tuple stores only value to be indexed and for
44-
* multicolumn variant it stores two attributes: column number of value and value.
46+
* Attributes of an index tuple are different for single and multicolumn index.
47+
* For single-column case, index tuple stores only value to be indexed.
48+
* For multicolumn case, it stores two attributes: column number of value
49+
* and value.
4550
*/
4651
IndexTuple
4752
GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData *ipd, uint32 nipd)
@@ -89,6 +94,28 @@ GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, ItemPointerData
8994
return itup;
9095
}
9196

97+
/*
98+
* Sometimes we reduce the number of posting list items in a tuple after
99+
* having built it with GinFormTuple. This function adjusts the size
100+
* fields to match.
101+
*/
102+
void
103+
GinShortenTuple(IndexTuple itup, uint32 nipd)
104+
{
105+
uint32 newsize;
106+
107+
Assert(nipd <= GinGetNPosting(itup));
108+
109+
newsize = MAXALIGN(SHORTALIGN(GinGetOrigSizePosting(itup)) + sizeof(ItemPointerData) * nipd);
110+
111+
Assert(newsize <= (itup->t_info & INDEX_SIZE_MASK));
112+
113+
itup->t_info &= ~INDEX_SIZE_MASK;
114+
itup->t_info |= newsize;
115+
116+
GinSetNPosting(itup, nipd);
117+
}
118+
92119
/*
93120
* Entry tree is a "static", ie tuple never deletes from it,
94121
* so we don't use right bound, we use rightest key instead.

src/backend/access/gin/gininsert.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.20 2009/03/24 22:06:03 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.21 2009/06/06 02:39:40 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414

@@ -102,17 +102,19 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
102102
{
103103
Datum key = gin_index_getattr(ginstate, old);
104104
OffsetNumber attnum = gintuple_get_attrnum(ginstate, old);
105-
IndexTuple res = GinFormTuple(ginstate, attnum, key, NULL, nitem + GinGetNPosting(old));
105+
IndexTuple res = GinFormTuple(ginstate, attnum, key,
106+
NULL, nitem + GinGetNPosting(old));
106107

107108
if (res)
108109
{
109110
/* good, small enough */
110-
MergeItemPointers(GinGetPosting(res),
111-
GinGetPosting(old), GinGetNPosting(old),
112-
items, nitem
113-
);
111+
uint32 newnitem;
114112

115-
GinSetNPosting(res, nitem + GinGetNPosting(old));
113+
newnitem = MergeItemPointers(GinGetPosting(res),
114+
GinGetPosting(old), GinGetNPosting(old),
115+
items, nitem);
116+
/* merge might have eliminated some duplicate items */
117+
GinShortenTuple(res, newnitem);
116118
}
117119
else
118120
{

src/include/access/gin.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*
55
* Copyright (c) 2006-2009, PostgreSQL Global Development Group
66
*
7-
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.32 2009/06/05 18:50:47 tgl Exp $
7+
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.33 2009/06/06 02:39:40 tgl Exp $
88
*--------------------------------------------------------------------------
99
*/
1010
#ifndef GIN_H
@@ -435,14 +435,15 @@ extern void findParents(GinBtree btree, GinBtreeStack *stack, BlockNumber rootBl
435435
/* ginentrypage.c */
436436
extern IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key,
437437
ItemPointerData *ipd, uint32 nipd);
438+
extern void GinShortenTuple(IndexTuple itup, uint32 nipd);
438439
extern void prepareEntryScan(GinBtree btree, Relation index, OffsetNumber attnum,
439440
Datum value, GinState *ginstate);
440441
extern void entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
441442
extern IndexTuple ginPageGetLinkItup(Buffer buf);
442443

443444
/* gindatapage.c */
444445
extern int compareItemPointers(ItemPointer a, ItemPointer b);
445-
extern void MergeItemPointers(ItemPointerData *dst,
446+
extern uint32 MergeItemPointers(ItemPointerData *dst,
446447
ItemPointerData *a, uint32 na,
447448
ItemPointerData *b, uint32 nb);
448449

0 commit comments

Comments
 (0)