diff options
Diffstat (limited to 'src/backend/access')
-rw-r--r-- | src/backend/access/gin/gininsert.c | 14 | ||||
-rw-r--r-- | src/backend/access/gist/gist.c | 16 | ||||
-rw-r--r-- | src/backend/access/hash/hash.c | 14 | ||||
-rw-r--r-- | src/backend/access/heap/heapam.c | 155 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtree.c | 28 |
5 files changed, 199 insertions, 28 deletions
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index fd7fc9f823b..a4416a94cb3 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.1 2006/05/02 11:28:54 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.2 2006/05/10 23:18:38 tgl Exp $ *------------------------------------------------------------------------- */ @@ -242,6 +242,7 @@ ginbuild(PG_FUNCTION_ARGS) { Relation heap = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(1); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); + IndexBuildResult *result; double reltuples; GinBuildState buildstate; Buffer buffer; @@ -310,10 +311,15 @@ ginbuild(PG_FUNCTION_ARGS) { MemoryContextDelete(buildstate.tmpCtx); - /* since we just counted the # of tuples, may as well update stats */ - IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples); + /* + * Return statistics + */ + result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); + + result->heap_tuples = reltuples; + result->index_tuples = buildstate.indtuples; - PG_RETURN_VOID(); + PG_RETURN_POINTER(result); } /* diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 2272e3339d1..4ce461d4463 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.133 2006/05/10 09:19:54 teodor Exp $ + * $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.134 2006/05/10 23:18:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -89,6 +89,7 @@ gistbuild(PG_FUNCTION_ARGS) Relation heap = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(1); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); + IndexBuildResult *result; double reltuples; GISTBuildState buildstate; Buffer buffer; @@ -154,12 +155,17 @@ gistbuild(PG_FUNCTION_ARGS) /* okay, all heap tuples are indexed */ MemoryContextDelete(buildstate.tmpCtx); - /* since we just counted the # of tuples, may as well update stats */ - IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples); - freeGISTstate(&buildstate.giststate); - PG_RETURN_VOID(); + /* + * Return statistics + */ + result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); + + result->heap_tuples = reltuples; + result->index_tuples = buildstate.indtuples; + + PG_RETURN_POINTER(result); } /* diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index ff54052f6de..d94104854e9 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.89 2006/05/02 22:25:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.90 2006/05/10 23:18:38 tgl Exp $ * * NOTES * This file contains only the public interface routines. @@ -51,6 +51,7 @@ hashbuild(PG_FUNCTION_ARGS) Relation heap = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(1); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); + IndexBuildResult *result; double reltuples; HashBuildState buildstate; @@ -72,10 +73,15 @@ hashbuild(PG_FUNCTION_ARGS) reltuples = IndexBuildHeapScan(heap, index, indexInfo, hashbuildCallback, (void *) &buildstate); - /* since we just counted the # of tuples, may as well update stats */ - IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples); + /* + * Return statistics + */ + result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); - PG_RETURN_VOID(); + result->heap_tuples = reltuples; + result->index_tuples = buildstate.indtuples; + + PG_RETURN_POINTER(result); } /* diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 779e86a3894..dcb9fc8fb64 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.211 2006/03/31 23:32:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.212 2006/05/10 23:18:39 tgl Exp $ * * * INTERFACE ROUTINES @@ -2673,6 +2673,97 @@ l3: return HeapTupleMayBeUpdated; } + +/* + * heap_inplace_update - update a tuple "in place" (ie, overwrite it) + * + * Overwriting violates both MVCC and transactional safety, so the uses + * of this function in Postgres are extremely limited. Nonetheless we + * find some places to use it. + * + * The tuple cannot change size, and therefore it's reasonable to assume + * that its null bitmap (if any) doesn't change either. So we just + * overwrite the data portion of the tuple without touching the null + * bitmap or any of the header fields. + * + * tuple is an in-memory tuple structure containing the data to be written + * over the target tuple. Also, tuple->t_self identifies the target tuple. + */ +void +heap_inplace_update(Relation relation, HeapTuple tuple) +{ + Buffer buffer; + Page page; + OffsetNumber offnum; + ItemId lp = NULL; + HeapTupleHeader htup; + uint32 oldlen; + uint32 newlen; + + buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self))); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + page = (Page) BufferGetPage(buffer); + + offnum = ItemPointerGetOffsetNumber(&(tuple->t_self)); + if (PageGetMaxOffsetNumber(page) >= offnum) + lp = PageGetItemId(page, offnum); + + if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp)) + elog(ERROR, "heap_inplace_update: invalid lp"); + + htup = (HeapTupleHeader) PageGetItem(page, lp); + + oldlen = ItemIdGetLength(lp) - htup->t_hoff; + newlen = tuple->t_len - tuple->t_data->t_hoff; + if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff) + elog(ERROR, "heap_inplace_update: wrong tuple length"); + + /* NO EREPORT(ERROR) from here till changes are logged */ + START_CRIT_SECTION(); + + memcpy((char *) htup + htup->t_hoff, + (char *) tuple->t_data + tuple->t_data->t_hoff, + newlen); + + MarkBufferDirty(buffer); + + /* XLOG stuff */ + if (!relation->rd_istemp) + { + xl_heap_inplace xlrec; + XLogRecPtr recptr; + XLogRecData rdata[2]; + + xlrec.target.node = relation->rd_node; + xlrec.target.tid = tuple->t_self; + + rdata[0].data = (char *) &xlrec; + rdata[0].len = SizeOfHeapInplace; + rdata[0].buffer = InvalidBuffer; + rdata[0].next = &(rdata[1]); + + rdata[1].data = (char *) htup + htup->t_hoff; + rdata[1].len = newlen; + rdata[1].buffer = buffer; + rdata[1].buffer_std = true; + rdata[1].next = NULL; + + recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE, rdata); + + PageSetLSN(page, recptr); + PageSetTLI(page, ThisTimeLineID); + } + + END_CRIT_SECTION(); + + UnlockReleaseBuffer(buffer); + + /* Send out shared cache inval if necessary */ + if (!IsBootstrapProcessingMode()) + CacheInvalidateHeapTuple(relation, tuple); +} + + /* ---------------- * heap_markpos - mark scan position * ---------------- @@ -3329,6 +3420,59 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record) UnlockReleaseBuffer(buffer); } +static void +heap_xlog_inplace(XLogRecPtr lsn, XLogRecord *record) +{ + xl_heap_inplace *xlrec = (xl_heap_inplace *) XLogRecGetData(record); + Relation reln = XLogOpenRelation(xlrec->target.node); + Buffer buffer; + Page page; + OffsetNumber offnum; + ItemId lp = NULL; + HeapTupleHeader htup; + uint32 oldlen; + uint32 newlen; + + if (record->xl_info & XLR_BKP_BLOCK_1) + return; + + buffer = XLogReadBuffer(reln, + ItemPointerGetBlockNumber(&(xlrec->target.tid)), + false); + if (!BufferIsValid(buffer)) + return; + page = (Page) BufferGetPage(buffer); + + if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */ + { + UnlockReleaseBuffer(buffer); + return; + } + + offnum = ItemPointerGetOffsetNumber(&(xlrec->target.tid)); + if (PageGetMaxOffsetNumber(page) >= offnum) + lp = PageGetItemId(page, offnum); + + if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsUsed(lp)) + elog(PANIC, "heap_inplace_redo: invalid lp"); + + htup = (HeapTupleHeader) PageGetItem(page, lp); + + oldlen = ItemIdGetLength(lp) - htup->t_hoff; + newlen = record->xl_len - SizeOfHeapInplace; + if (oldlen != newlen) + elog(PANIC, "heap_inplace_redo: wrong tuple length"); + + memcpy((char *) htup + htup->t_hoff, + (char *) xlrec + SizeOfHeapInplace, + newlen); + + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); + UnlockReleaseBuffer(buffer); +} + void heap_redo(XLogRecPtr lsn, XLogRecord *record) { @@ -3349,6 +3493,8 @@ heap_redo(XLogRecPtr lsn, XLogRecord *record) heap_xlog_newpage(lsn, record); else if (info == XLOG_HEAP_LOCK) heap_xlog_lock(lsn, record); + else if (info == XLOG_HEAP_INPLACE) + heap_xlog_inplace(lsn, record); else elog(PANIC, "heap_redo: unknown op code %u", info); } @@ -3442,6 +3588,13 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec) appendStringInfo(buf, "%u ", xlrec->locking_xid); out_target(buf, &(xlrec->target)); } + else if (info == XLOG_HEAP_INPLACE) + { + xl_heap_inplace *xlrec = (xl_heap_inplace *) rec; + + appendStringInfo(buf, "inplace: "); + out_target(buf, &(xlrec->target)); + } else appendStringInfo(buf, "UNKNOWN"); } diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index d501249a7a6..3329321c0ff 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -12,21 +12,18 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.148 2006/05/08 00:00:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.149 2006/05/10 23:18:39 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" -#include "access/heapam.h" #include "access/nbtree.h" #include "catalog/index.h" #include "commands/vacuum.h" -#include "miscadmin.h" #include "storage/freespace.h" -#include "storage/smgr.h" -#include "utils/inval.h" +#include "storage/lmgr.h" #include "utils/memutils.h" @@ -84,6 +81,7 @@ btbuild(PG_FUNCTION_ARGS) Relation heap = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(1); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); + IndexBuildResult *result; double reltuples; BTBuildState buildstate; @@ -149,18 +147,20 @@ btbuild(PG_FUNCTION_ARGS) /* * If we are reindexing a pre-existing index, it is critical to send out * a relcache invalidation SI message to ensure all backends re-read the - * index metapage. In most circumstances the update-stats operation will - * cause that to happen, but at the moment there are corner cases where - * no pg_class update will occur, so force an inval here. XXX FIXME: - * the upper levels of CREATE INDEX should handle the stats update as - * well as guaranteeing relcache inval. + * index metapage. We expect that the caller will ensure that happens + * (typically as a side effect of updating index stats, but it must + * happen even if the stats don't change!) */ - CacheInvalidateRelcache(index); - /* since we just counted the # of tuples, may as well update stats */ - IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples); + /* + * Return statistics + */ + result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); - PG_RETURN_VOID(); + result->heap_tuples = reltuples; + result->index_tuples = buildstate.indtuples; + + PG_RETURN_POINTER(result); } /* |