Skip to content

Commit e8cab5f

Browse files
committed
Concurrency for GiST
- full concurrency for insert/update/select/vacuum: - select and vacuum never locks more than one page simultaneously - select (gettuple) hasn't any lock across it's calls - insert never locks more than two page simultaneously: - during search of leaf to insert it locks only one page simultaneously - while walk upward to the root it locked only parent (may be non-direct parent) and child. One of them X-lock, another may be S- or X-lock - 'vacuum full' locks index - improve gistgetmulti - simplify XLOG records Fix bug in index_beginscan_internal: LockRelation may clean rd_aminfo structure, so move GET_REL_PROCEDURE after LockRelation
1 parent c3be085 commit e8cab5f

File tree

12 files changed

+987
-591
lines changed

12 files changed

+987
-591
lines changed

src/backend/access/gist/gist.c

Lines changed: 384 additions & 99 deletions
Large diffs are not rendered by default.

src/backend/access/gist/gistget.c

Lines changed: 204 additions & 122 deletions
Large diffs are not rendered by default.

src/backend/access/gist/gistscan.c

Lines changed: 33 additions & 70 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/gist/gistscan.c,v 1.58 2005/05/17 03:34:18 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.59 2005/06/27 12:45:22 teodor Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -24,11 +24,10 @@
2424
static void gistregscan(IndexScanDesc scan);
2525
static void gistdropscan(IndexScanDesc scan);
2626
static void gistadjone(IndexScanDesc scan, int op, BlockNumber blkno,
27-
OffsetNumber offnum);
28-
static void adjuststack(GISTSTACK *stk, BlockNumber blkno);
29-
static void adjustiptr(IndexScanDesc scan, ItemPointer iptr,
30-
int op, BlockNumber blkno, OffsetNumber offnum);
31-
static void gistfreestack(GISTSTACK *s);
27+
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn);
28+
static void adjustiptr(IndexScanDesc scan, ItemPointer iptr, GISTSearchStack *stk,
29+
int op, BlockNumber blkno, OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn);
30+
static void gistfreestack(GISTSearchStack *s);
3231

3332
/*
3433
* Whenever we start a GiST scan in a backend, we register it in
@@ -139,7 +138,7 @@ gistmarkpos(PG_FUNCTION_ARGS)
139138
{
140139
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
141140
GISTScanOpaque so;
142-
GISTSTACK *o,
141+
GISTSearchStack *o,
143142
*n,
144143
*tmp;
145144

@@ -156,12 +155,13 @@ gistmarkpos(PG_FUNCTION_ARGS)
156155
/* copy the parent stack from the current item data */
157156
while (n != NULL)
158157
{
159-
tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
160-
tmp->offset = n->offset;
158+
tmp = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
159+
tmp->lsn = n->lsn;
160+
tmp->parentlsn = n->parentlsn;
161161
tmp->block = n->block;
162-
tmp->parent = o;
162+
tmp->next = o;
163163
o = tmp;
164-
n = n->parent;
164+
n = n->next;
165165
}
166166

167167
gistfreestack(so->markstk);
@@ -187,7 +187,7 @@ gistrestrpos(PG_FUNCTION_ARGS)
187187
{
188188
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
189189
GISTScanOpaque so;
190-
GISTSTACK *o,
190+
GISTSearchStack *o,
191191
*n,
192192
*tmp;
193193

@@ -204,12 +204,13 @@ gistrestrpos(PG_FUNCTION_ARGS)
204204
/* copy the parent stack from the current item data */
205205
while (n != NULL)
206206
{
207-
tmp = (GISTSTACK *) palloc(sizeof(GISTSTACK));
208-
tmp->offset = n->offset;
207+
tmp = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
208+
tmp->lsn = n->lsn;
209+
tmp->parentlsn = n->parentlsn;
209210
tmp->block = n->block;
210-
tmp->parent = o;
211+
tmp->next = o;
211212
o = tmp;
212-
n = n->parent;
213+
n = n->next;
213214
}
214215

215216
gistfreestack(so->stack);
@@ -253,6 +254,7 @@ gistendscan(PG_FUNCTION_ARGS)
253254
pfree(scan->opaque);
254255
}
255256

257+
256258
gistdropscan(scan);
257259

258260
PG_RETURN_VOID();
@@ -331,16 +333,19 @@ ReleaseResources_gist(void)
331333
}
332334

333335
void
334-
gistadjscans(Relation rel, int op, BlockNumber blkno, OffsetNumber offnum)
336+
gistadjscans(Relation rel, int op, BlockNumber blkno, OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn)
335337
{
336338
GISTScanList l;
337339
Oid relid;
338340

341+
if ( XLogRecPtrIsInvalid(newlsn) || XLogRecPtrIsInvalid(oldlsn) )
342+
return;
343+
339344
relid = RelationGetRelid(rel);
340345
for (l = GISTScans; l != NULL; l = l->gsl_next)
341346
{
342347
if (l->gsl_scan->indexRelation->rd_id == relid)
343-
gistadjone(l->gsl_scan, op, blkno, offnum);
348+
gistadjone(l->gsl_scan, op, blkno, offnum, newlsn, oldlsn);
344349
}
345350
}
346351

@@ -358,20 +363,12 @@ static void
358363
gistadjone(IndexScanDesc scan,
359364
int op,
360365
BlockNumber blkno,
361-
OffsetNumber offnum)
366+
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn)
362367
{
363-
GISTScanOpaque so;
364-
365-
adjustiptr(scan, &(scan->currentItemData), op, blkno, offnum);
366-
adjustiptr(scan, &(scan->currentMarkData), op, blkno, offnum);
367-
368-
so = (GISTScanOpaque) scan->opaque;
368+
GISTScanOpaque so = (GISTScanOpaque) scan->opaque ;
369369

370-
if (op == GISTOP_SPLIT)
371-
{
372-
adjuststack(so->stack, blkno);
373-
adjuststack(so->markstk, blkno);
374-
}
370+
adjustiptr(scan, &(scan->currentItemData), so->stack, op, blkno, offnum, newlsn, oldlsn);
371+
adjustiptr(scan, &(scan->currentMarkData), so->markstk, op, blkno, offnum, newlsn, oldlsn);
375372
}
376373

377374
/*
@@ -383,10 +380,10 @@ gistadjone(IndexScanDesc scan,
383380
*/
384381
static void
385382
adjustiptr(IndexScanDesc scan,
386-
ItemPointer iptr,
383+
ItemPointer iptr, GISTSearchStack *stk,
387384
int op,
388385
BlockNumber blkno,
389-
OffsetNumber offnum)
386+
OffsetNumber offnum, XLogRecPtr newlsn, XLogRecPtr oldlsn)
390387
{
391388
OffsetNumber curoff;
392389
GISTScanOpaque so;
@@ -402,7 +399,7 @@ adjustiptr(IndexScanDesc scan,
402399
{
403400
case GISTOP_DEL:
404401
/* back up one if we need to */
405-
if (curoff >= offnum)
402+
if (curoff >= offnum && XLByteEQ(stk->lsn, oldlsn) ) /* the same vesrion of page */
406403
{
407404
if (curoff > FirstOffsetNumber)
408405
{
@@ -421,56 +418,22 @@ adjustiptr(IndexScanDesc scan,
421418
else
422419
so->flags |= GS_MRKBEFORE;
423420
}
421+
stk->lsn = newlsn;
424422
}
425423
break;
426-
427-
case GISTOP_SPLIT:
428-
/* back to start of page on split */
429-
ItemPointerSet(iptr, blkno, FirstOffsetNumber);
430-
if (iptr == &(scan->currentItemData))
431-
so->flags &= ~GS_CURBEFORE;
432-
else
433-
so->flags &= ~GS_MRKBEFORE;
434-
break;
435-
436424
default:
437425
elog(ERROR, "Bad operation in GiST scan adjust: %d", op);
438426
}
439427
}
440428
}
441429
}
442430

443-
/*
444-
* adjuststack() -- adjust the supplied stack for a split on a page in
445-
* the index we're scanning.
446-
*
447-
* If a page on our parent stack has split, we need to back up to the
448-
* beginning of the page and rescan it. The reason for this is that
449-
* the split algorithm for GiSTs doesn't order tuples in any useful
450-
* way on a single page. This means on that a split, we may wind up
451-
* looking at some heap tuples more than once. This is handled in the
452-
* access method update code for heaps; if we've modified the tuple we
453-
* are looking at already in this transaction, we ignore the update
454-
* request.
455-
*/
456-
static void
457-
adjuststack(GISTSTACK *stk, BlockNumber blkno)
458-
{
459-
while (stk != NULL)
460-
{
461-
if (stk->block == blkno)
462-
stk->offset = FirstOffsetNumber;
463-
464-
stk = stk->parent;
465-
}
466-
}
467-
468431
static void
469-
gistfreestack(GISTSTACK *s)
432+
gistfreestack(GISTSearchStack *s)
470433
{
471434
while (s != NULL)
472435
{
473-
GISTSTACK *p = s->parent;
436+
GISTSearchStack *p = s->next;
474437
pfree(s);
475438
s = p;
476439
}

src/backend/access/gist/gistutil.c

Lines changed: 30 additions & 18 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/gist/gistutil.c,v 1.2 2005/06/20 10:29:36 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.3 2005/06/27 12:45:22 teodor Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
@@ -803,8 +803,12 @@ GISTInitBuffer(Buffer b, uint32 f)
803803
page = BufferGetPage(b);
804804
PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
805805

806-
opaque = (GISTPageOpaque) PageGetSpecialPointer(page);
806+
opaque = GistPageGetOpaque(page);
807807
opaque->flags = f;
808+
opaque->nsplited = 0;
809+
opaque->level = 0;
810+
opaque->rightlink = InvalidBlockNumber;
811+
memset( &(opaque->nsn), 0, sizeof(GistNSN) );
808812
}
809813

810814
void
@@ -856,30 +860,38 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
856860
}
857861

858862
Buffer
859-
gistReadBuffer(Relation r, BlockNumber blkno) {
863+
gistNewBuffer(Relation r) {
860864
Buffer buffer = InvalidBuffer;
865+
bool needLock;
861866

862-
if ( blkno != P_NEW ) {
863-
buffer = ReadBuffer(r, blkno);
864-
} else {
865-
Page page;
866-
867-
while(true) {
868-
blkno = GetFreeIndexPage(&r->rd_node);
869-
if (blkno == InvalidBlockNumber)
870-
break;
867+
while(true) {
868+
BlockNumber blkno = GetFreeIndexPage(&r->rd_node);
869+
if (blkno == InvalidBlockNumber)
870+
break;
871871

872-
buffer = ReadBuffer(r, blkno);
873-
page = BufferGetPage(buffer);
872+
buffer = ReadBuffer(r, blkno);
873+
if ( ConditionalLockBuffer(buffer) ) {
874+
Page page = BufferGetPage(buffer);
874875
if ( GistPageIsDeleted( page ) ) {
875876
GistPageSetNonDeleted( page );
876877
return buffer;
877-
}
878-
ReleaseBuffer( buffer );
878+
} else
879+
LockBuffer(buffer, GIST_UNLOCK);
879880
}
880881

881-
buffer = ReadBuffer(r, P_NEW);
882+
ReleaseBuffer( buffer );
882883
}
883-
884+
885+
needLock = !RELATION_IS_LOCAL(r);
886+
887+
if (needLock)
888+
LockRelationForExtension(r, ExclusiveLock);
889+
890+
buffer = ReadBuffer(r, P_NEW);
891+
LockBuffer(buffer, GIST_EXCLUSIVE);
892+
893+
if (needLock)
894+
UnlockRelationForExtension(r, ExclusiveLock);
895+
884896
return buffer;
885897
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy