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

Commit 3fdeb18

Browse files
committed
Clean up code associated with updating pg_class statistics columns
(relpages/reltuples). To do this, create formal support in heapam.c for "overwrite" tuple updates (including xlog replay capability) and use that instead of the ad-hoc overwrites we'd been using in VACUUM and CREATE INDEX. Take the responsibility for updating stats during CREATE INDEX out of the individual index AMs, and do it where it belongs, in catalog/index.c. Aside from being more modular, this avoids having to update the same tuple twice in some paths through CREATE INDEX. It's probably not measurably faster, but for sure it's a lot cleaner than before.
1 parent c1f3943 commit 3fdeb18

File tree

17 files changed

+519
-404
lines changed

17 files changed

+519
-404
lines changed

doc/src/sgml/indexam.sgml

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.10 2006/05/02 22:25:09 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.11 2006/05/10 23:18:38 tgl Exp $ -->
22

33
<chapter id="indexam">
44
<title>Index Access Method Interface Definition</title>
@@ -144,7 +144,7 @@
144144

145145
<para>
146146
<programlisting>
147-
void
147+
IndexBuildResult *
148148
ambuild (Relation heapRelation,
149149
Relation indexRelation,
150150
IndexInfo *indexInfo);
@@ -155,6 +155,8 @@ ambuild (Relation heapRelation,
155155
in the table. Ordinarily the <function>ambuild</> function will call
156156
<function>IndexBuildHeapScan()</> to scan the table for existing tuples
157157
and compute the keys that need to be inserted into the index.
158+
The function must return a palloc'd struct containing statistics about
159+
the new index.
158160
</para>
159161

160162
<para>

src/backend/access/gin/gininsert.c

+10-4
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.1 2006/05/02 11:28:54 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.2 2006/05/10 23:18:38 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414

@@ -242,6 +242,7 @@ ginbuild(PG_FUNCTION_ARGS) {
242242
Relation heap = (Relation) PG_GETARG_POINTER(0);
243243
Relation index = (Relation) PG_GETARG_POINTER(1);
244244
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
245+
IndexBuildResult *result;
245246
double reltuples;
246247
GinBuildState buildstate;
247248
Buffer buffer;
@@ -310,10 +311,15 @@ ginbuild(PG_FUNCTION_ARGS) {
310311

311312
MemoryContextDelete(buildstate.tmpCtx);
312313

313-
/* since we just counted the # of tuples, may as well update stats */
314-
IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);
314+
/*
315+
* Return statistics
316+
*/
317+
result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
318+
319+
result->heap_tuples = reltuples;
320+
result->index_tuples = buildstate.indtuples;
315321

316-
PG_RETURN_VOID();
322+
PG_RETURN_POINTER(result);
317323
}
318324

319325
/*

src/backend/access/gist/gist.c

+11-5
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/gist.c,v 1.133 2006/05/10 09:19:54 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.134 2006/05/10 23:18:38 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -89,6 +89,7 @@ gistbuild(PG_FUNCTION_ARGS)
8989
Relation heap = (Relation) PG_GETARG_POINTER(0);
9090
Relation index = (Relation) PG_GETARG_POINTER(1);
9191
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
92+
IndexBuildResult *result;
9293
double reltuples;
9394
GISTBuildState buildstate;
9495
Buffer buffer;
@@ -154,12 +155,17 @@ gistbuild(PG_FUNCTION_ARGS)
154155
/* okay, all heap tuples are indexed */
155156
MemoryContextDelete(buildstate.tmpCtx);
156157

157-
/* since we just counted the # of tuples, may as well update stats */
158-
IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);
159-
160158
freeGISTstate(&buildstate.giststate);
161159

162-
PG_RETURN_VOID();
160+
/*
161+
* Return statistics
162+
*/
163+
result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
164+
165+
result->heap_tuples = reltuples;
166+
result->index_tuples = buildstate.indtuples;
167+
168+
PG_RETURN_POINTER(result);
163169
}
164170

165171
/*

src/backend/access/hash/hash.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.89 2006/05/02 22:25:10 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.90 2006/05/10 23:18:38 tgl Exp $
1212
*
1313
* NOTES
1414
* This file contains only the public interface routines.
@@ -51,6 +51,7 @@ hashbuild(PG_FUNCTION_ARGS)
5151
Relation heap = (Relation) PG_GETARG_POINTER(0);
5252
Relation index = (Relation) PG_GETARG_POINTER(1);
5353
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
54+
IndexBuildResult *result;
5455
double reltuples;
5556
HashBuildState buildstate;
5657

@@ -72,10 +73,15 @@ hashbuild(PG_FUNCTION_ARGS)
7273
reltuples = IndexBuildHeapScan(heap, index, indexInfo,
7374
hashbuildCallback, (void *) &buildstate);
7475

75-
/* since we just counted the # of tuples, may as well update stats */
76-
IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);
76+
/*
77+
* Return statistics
78+
*/
79+
result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
7780

78-
PG_RETURN_VOID();
81+
result->heap_tuples = reltuples;
82+
result->index_tuples = buildstate.indtuples;
83+
84+
PG_RETURN_POINTER(result);
7985
}
8086

8187
/*

src/backend/access/heap/heapam.c

+154-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.211 2006/03/31 23:32:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.212 2006/05/10 23:18:39 tgl Exp $
1212
*
1313
*
1414
* INTERFACE ROUTINES
@@ -2673,6 +2673,97 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, Buffer *buffer,
26732673
return HeapTupleMayBeUpdated;
26742674
}
26752675

2676+
2677+
/*
2678+
* heap_inplace_update - update a tuple "in place" (ie, overwrite it)
2679+
*
2680+
* Overwriting violates both MVCC and transactional safety, so the uses
2681+
* of this function in Postgres are extremely limited. Nonetheless we
2682+
* find some places to use it.
2683+
*
2684+
* The tuple cannot change size, and therefore it's reasonable to assume
2685+
* that its null bitmap (if any) doesn't change either. So we just
2686+
* overwrite the data portion of the tuple without touching the null
2687+
* bitmap or any of the header fields.
2688+
*
2689+
* tuple is an in-memory tuple structure containing the data to be written
2690+
* over the target tuple. Also, tuple->t_self identifies the target tuple.
2691+
*/
2692+
void
2693+
heap_inplace_update(Relation relation, HeapTuple tuple)
2694+
{
2695+
Buffer buffer;
2696+
Page page;
2697+
OffsetNumber offnum;
2698+
ItemId lp = NULL;
2699+
HeapTupleHeader htup;
2700+
uint32 oldlen;
2701+
uint32 newlen;
2702+
2703+
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
2704+
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
2705+
page = (Page) BufferGetPage(buffer);
2706+
2707+
offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
2708+
if (PageGetMaxOffsetNumber(page) >= offnum)
2709+
lp = PageGetItemId(page, offnum);
2710+
2711+
if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
2712+
elog(ERROR, "heap_inplace_update: invalid lp");
2713+
2714+
htup = (HeapTupleHeader) PageGetItem(page, lp);
2715+
2716+
oldlen = ItemIdGetLength(lp) - htup->t_hoff;
2717+
newlen = tuple->t_len - tuple->t_data->t_hoff;
2718+
if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
2719+
elog(ERROR, "heap_inplace_update: wrong tuple length");
2720+
2721+
/* NO EREPORT(ERROR) from here till changes are logged */
2722+
START_CRIT_SECTION();
2723+
2724+
memcpy((char *) htup + htup->t_hoff,
2725+
(char *) tuple->t_data + tuple->t_data->t_hoff,
2726+
newlen);
2727+
2728+
MarkBufferDirty(buffer);
2729+
2730+
/* XLOG stuff */
2731+
if (!relation->rd_istemp)
2732+
{
2733+
xl_heap_inplace xlrec;
2734+
XLogRecPtr recptr;
2735+
XLogRecData rdata[2];
2736+
2737+
xlrec.target.node = relation->rd_node;
2738+
xlrec.target.tid = tuple->t_self;
2739+
2740+
rdata[0].data = (char *) &xlrec;
2741+
rdata[0].len = SizeOfHeapInplace;
2742+
rdata[0].buffer = InvalidBuffer;
2743+
rdata[0].next = &(rdata[1]);
2744+
2745+
rdata[1].data = (char *) htup + htup->t_hoff;
2746+
rdata[1].len = newlen;
2747+
rdata[1].buffer = buffer;
2748+
rdata[1].buffer_std = true;
2749+
rdata[1].next = NULL;
2750+
2751+
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE, rdata);
2752+
2753+
PageSetLSN(page, recptr);
2754+
PageSetTLI(page, ThisTimeLineID);
2755+
}
2756+
2757+
END_CRIT_SECTION();
2758+
2759+
UnlockReleaseBuffer(buffer);
2760+
2761+
/* Send out shared cache inval if necessary */
2762+
if (!IsBootstrapProcessingMode())
2763+
CacheInvalidateHeapTuple(relation, tuple);
2764+
}
2765+
2766+
26762767
/* ----------------
26772768
* heap_markpos - mark scan position
26782769
* ----------------
@@ -3329,6 +3420,59 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
33293420
UnlockReleaseBuffer(buffer);
33303421
}
33313422

3423+
static void
3424+
heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record)
3425+
{
3426+
xl_heap_inplace *xlrec = (xl_heap_inplace *) XLogRecGetData(record);
3427+
Relation reln = XLogOpenRelation(xlrec->target.node);
3428+
Buffer buffer;
3429+
Page page;
3430+
OffsetNumber offnum;
3431+
ItemId lp = NULL;
3432+
HeapTupleHeader htup;
3433+
uint32 oldlen;
3434+
uint32 newlen;
3435+
3436+
if (record->xl_info & XLR_BKP_BLOCK_1)
3437+
return;
3438+
3439+
buffer = XLogReadBuffer(reln,
3440+
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
3441+
false);
3442+
if (!BufferIsValid(buffer))
3443+
return;
3444+
page = (Page) BufferGetPage(buffer);
3445+
3446+
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
3447+
{
3448+
UnlockReleaseBuffer(buffer);
3449+
return;
3450+
}
3451+
3452+
offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid));
3453+
if (PageGetMaxOffsetNumber(page) >= offnum)
3454+
lp = PageGetItemId(page, offnum);
3455+
3456+
if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp))
3457+
elog(PANIC, "heap_inplace_redo: invalid lp");
3458+
3459+
htup = (HeapTupleHeader) PageGetItem(page, lp);
3460+
3461+
oldlen = ItemIdGetLength(lp) - htup->t_hoff;
3462+
newlen = record->xl_len - SizeOfHeapInplace;
3463+
if (oldlen != newlen)
3464+
elog(PANIC, "heap_inplace_redo: wrong tuple length");
3465+
3466+
memcpy((char *) htup + htup->t_hoff,
3467+
(char *) xlrec + SizeOfHeapInplace,
3468+
newlen);
3469+
3470+
PageSetLSN(page, lsn);
3471+
PageSetTLI(page, ThisTimeLineID);
3472+
MarkBufferDirty(buffer);
3473+
UnlockReleaseBuffer(buffer);
3474+
}
3475+
33323476
void
33333477
heap_redo(XLogRecPtr lsn, XLogRecord *record)
33343478
{
@@ -3349,6 +3493,8 @@ heap_redo(XLogRecPtr lsn, XLogRecord *record)
33493493
heap_xlog_newpage(lsn, record);
33503494
else if (info == XLOG_HEAP_LOCK)
33513495
heap_xlog_lock(lsn, record);
3496+
else if (info == XLOG_HEAP_INPLACE)
3497+
heap_xlog_inplace(lsn, record);
33523498
else
33533499
elog(PANIC, "heap_redo: unknown op code %u", info);
33543500
}
@@ -3442,6 +3588,13 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
34423588
appendStringInfo(buf, "%u ", xlrec->locking_xid);
34433589
out_target(buf, &(xlrec->target));
34443590
}
3591+
else if (info == XLOG_HEAP_INPLACE)
3592+
{
3593+
xl_heap_inplace *xlrec = (xl_heap_inplace *) rec;
3594+
3595+
appendStringInfo(buf, "inplace: ");
3596+
out_target(buf, &(xlrec->target));
3597+
}
34453598
else
34463599
appendStringInfo(buf, "UNKNOWN");
34473600
}

src/backend/access/nbtree/nbtree.c

+14-14
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,18 @@
1212
* Portions Copyright (c) 1994, Regents of the University of California
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.148 2006/05/08 00:00:10 tgl Exp $
15+
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.149 2006/05/10 23:18:39 tgl Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
1919
#include "postgres.h"
2020

2121
#include "access/genam.h"
22-
#include "access/heapam.h"
2322
#include "access/nbtree.h"
2423
#include "catalog/index.h"
2524
#include "commands/vacuum.h"
26-
#include "miscadmin.h"
2725
#include "storage/freespace.h"
28-
#include "storage/smgr.h"
29-
#include "utils/inval.h"
26+
#include "storage/lmgr.h"
3027
#include "utils/memutils.h"
3128

3229

@@ -84,6 +81,7 @@ btbuild(PG_FUNCTION_ARGS)
8481
Relation heap = (Relation) PG_GETARG_POINTER(0);
8582
Relation index = (Relation) PG_GETARG_POINTER(1);
8683
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
84+
IndexBuildResult *result;
8785
double reltuples;
8886
BTBuildState buildstate;
8987

@@ -149,18 +147,20 @@ btbuild(PG_FUNCTION_ARGS)
149147
/*
150148
* If we are reindexing a pre-existing index, it is critical to send out
151149
* a relcache invalidation SI message to ensure all backends re-read the
152-
* index metapage. In most circumstances the update-stats operation will
153-
* cause that to happen, but at the moment there are corner cases where
154-
* no pg_class update will occur, so force an inval here. XXX FIXME:
155-
* the upper levels of CREATE INDEX should handle the stats update as
156-
* well as guaranteeing relcache inval.
150+
* index metapage. We expect that the caller will ensure that happens
151+
* (typically as a side effect of updating index stats, but it must
152+
* happen even if the stats don't change!)
157153
*/
158-
CacheInvalidateRelcache(index);
159154

160-
/* since we just counted the # of tuples, may as well update stats */
161-
IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);
155+
/*
156+
* Return statistics
157+
*/
158+
result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
162159

163-
PG_RETURN_VOID();
160+
result->heap_tuples = reltuples;
161+
result->index_tuples = buildstate.indtuples;
162+
163+
PG_RETURN_POINTER(result);
164164
}
165165

166166
/*

0 commit comments

Comments
 (0)