aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access')
-rw-r--r--src/backend/access/gin/gininsert.c14
-rw-r--r--src/backend/access/gist/gist.c16
-rw-r--r--src/backend/access/hash/hash.c14
-rw-r--r--src/backend/access/heap/heapam.c155
-rw-r--r--src/backend/access/nbtree/nbtree.c28
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);
}
/*