http://archives.postgresql.org/pgsql-hackers/2006-10/msg01172.php
As discussed on -hackers, its possible to avoid writing any WAL at all
for COPY in these circumstances:
BEGIN;
CREATE TABLE foo..
COPY foo...
COMMIT;
BEGIN;
TRUNCATE foo..
COPY foo...
COMMIT;
The enclosed patch implements this, as discussed. There is no user
interface to enable/disable, just as with CTAS and CREATE INDEX; no
docs, just code comments.
This plays nicely with the --single-transaction option in psql to allow
fast restores/upgrades.
YMMV but disk bound COPY will benefit greatly from this patch, some
tests showing 100% gain. COPY is still *very* CPU intensive, so some
tests have shown negligible benefit, fyi, but that isn't the typical
case.
Applies cleanly to CVS HEAD, passes make check.
--
Simon Riggs
EnterpriseDB http://www.enterprisedb.com
Index: src/backend/access/heap/heapam.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/heap/heapam.c,v
retrieving revision 1.222
diff -c -r1.222 heapam.c
*** src/backend/access/heap/heapam.c 17 Nov 2006 18:00:14 -0000 1.222
--- src/backend/access/heap/heapam.c 4 Jan 2007 15:24:03 -0000
***************
*** 28,33 ****
--- 28,34 ----
* heap_update - replace a tuple in a relation with another tuple
* heap_markpos - mark scan position
* heap_restrpos - restore position to marked location
+ * heap_sync - sync heap, for when no WAL has been written
*
* NOTES
* This file contains the heap_ routines which implement
***************
*** 50,55 ****
--- 51,57 ----
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/procarray.h"
+ #include "storage/smgr.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/relcache.h"
***************
*** 1357,1364 ****
* non-temp relation. Safe usage of this behavior requires that we arrange
* that all new tuples go into new pages not containing any tuples from other
* transactions, that the relation gets fsync'd before commit, and that the
! * transaction emits at least one WAL record to ensure RecordTransactionCommit
! * will decide to WAL-log the commit.
*
* use_fsm is passed directly to RelationGetBufferForTuple, which see for
* more info.
--- 1359,1367 ----
* non-temp relation. Safe usage of this behavior requires that we arrange
* that all new tuples go into new pages not containing any tuples from other
* transactions, that the relation gets fsync'd before commit, and that the
! * transaction emits at least one WAL record or must mark
! * MyXactMadeXLogEntry=true to ensure RecordTransactionCommit will
! * decide to WAL-log the commit. (see heap_sync() comments also)
*
* use_fsm is passed directly to RelationGetBufferForTuple, which see for
* more info.
***************
*** 1371,1377 ****
*/
Oid
heap_insert(Relation relation, HeapTuple tup, CommandId cid,
! bool use_wal, bool use_fsm)
{
TransactionId xid = GetCurrentTransactionId();
HeapTuple heaptup;
--- 1374,1380 ----
*/
Oid
heap_insert(Relation relation, HeapTuple tup, CommandId cid,
! bool use_wal, bool use_fsm, bool force_committed)
{
TransactionId xid = GetCurrentTransactionId();
HeapTuple heaptup;
***************
*** 1408,1413 ****
--- 1411,1419 ----
HeapTupleHeaderSetXmax(tup->t_data, 0); /* zero out Datum fields */
HeapTupleHeaderSetCmax(tup->t_data, 0); /* for cleanliness */
tup->t_tableOid = RelationGetRelid(relation);
+ if (force_committed)
+ tup->t_data->t_infomask |= HEAP_XMIN_COMMITTED;
+
/*
* If the new tuple is too big for storage or contains already toasted
***************
*** 1418,1424 ****
*/
if (HeapTupleHasExternal(tup) ||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
! heaptup = toast_insert_or_update(relation, tup, NULL);
else
heaptup = tup;
--- 1424,1430 ----
*/
if (HeapTupleHasExternal(tup) ||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
! heaptup = toast_insert_or_update(relation, tup, NULL, use_wal);
else
heaptup = tup;
***************
*** 1532,1538 ****
Oid
simple_heap_insert(Relation relation, HeapTuple tup)
{
! return heap_insert(relation, tup, GetCurrentCommandId(), true, true);
}
/*
--- 1538,1556 ----
Oid
simple_heap_insert(Relation relation, HeapTuple tup)
{
! return heap_insert(relation, tup, GetCurrentCommandId(), true, true, false);
! }
!
! /*
! * fast_heap_insert - insert a tuple with options to improve speed
! *
! * Currently, this routine allows specifying additional options for speed
! * in certain cases, such as WAL-avoiding COPY command
! */
! Oid
! fast_heap_insert(Relation relation, HeapTuple tup, bool use_wal, bool force_committed)
! {
! return heap_insert(relation, tup, GetCurrentCommandId(), use_wal, use_wal, force_committed);
}
/*
***************
*** 2086,2096 ****
*
* Note: below this point, heaptup is the data we actually intend to
* store into the relation; newtup is the caller's original untoasted
! * data.
*/
if (need_toast)
{
! heaptup = toast_insert_or_update(relation, newtup, &oldtup);
newtupsize = MAXALIGN(heaptup->t_len);
}
else
--- 2104,2114 ----
*
* Note: below this point, heaptup is the data we actually intend to
* store into the relation; newtup is the caller's original untoasted
! * data. (We always use WAL for toast table updates.)
*/
if (need_toast)
{
! heaptup = toast_insert_or_update(relation, newtup, &oldtup, true);
newtupsize = MAXALIGN(heaptup->t_len);
}
else
***************
*** 3966,3968 ****
--- 3984,4007 ----
else
appendStringInfo(buf, "UNKNOWN");
}
+
+ /* ----------------
+ * heap_sync - sync a heap, for use when no WAL has been written
+ *
+ * ----------------
+ */
+ void
+ heap_sync(Relation rel)
+ {
+ if (!rel->rd_istemp)
+ {
+ /*
+ * If we skipped using WAL, and it's not a temp relation,
+ * we must force the relation down to disk before it's
+ * safe to commit the transaction. This requires forcing
+ * out any dirty buffers and then doing a forced fsync.
+ */
+ FlushRelationBuffers(rel);
+ smgrimmedsync(rel->rd_smgr);
+ }
+ }
Index: src/backend/access/heap/tuptoaster.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v
retrieving revision 1.66
diff -c -r1.66 tuptoaster.c
*** src/backend/access/heap/tuptoaster.c 5 Oct 2006 23:33:33 -0000 1.66
--- src/backend/access/heap/tuptoaster.c 4 Jan 2007 15:24:04 -0000
***************
*** 42,48 ****
#undef TOAST_DEBUG
static void toast_delete_datum(Relation rel, Datum value);
! static Datum toast_save_datum(Relation rel, Datum value);
static varattrib *toast_fetch_datum(varattrib *attr);
static varattrib *toast_fetch_datum_slice(varattrib *attr,
int32 sliceoffset, int32 length);
--- 42,48 ----
#undef TOAST_DEBUG
static void toast_delete_datum(Relation rel, Datum value);
! static Datum toast_save_datum(Relation rel, Datum value, bool use_wal);
static varattrib *toast_fetch_datum(varattrib *attr);
static varattrib *toast_fetch_datum_slice(varattrib *attr,
int32 sliceoffset, int32 length);
***************
*** 342,348 ****
* ----------
*/
HeapTuple
! toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
{
HeapTuple result_tuple;
TupleDesc tupleDesc;
--- 342,348 ----
* ----------
*/
HeapTuple
! toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, bool use_wal)
{
HeapTuple result_tuple;
TupleDesc tupleDesc;
***************
*** 612,618 ****
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
! toast_values[i] = toast_save_datum(rel, toast_values[i]);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
--- 612,618 ----
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
! toast_values[i] = toast_save_datum(rel, toast_values[i], use_wal);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
***************
*** 724,730 ****
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
! toast_values[i] = toast_save_datum(rel, toast_values[i]);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
--- 724,730 ----
i = biggest_attno;
old_value = toast_values[i];
toast_action[i] = 'p';
! toast_values[i] = toast_save_datum(rel, toast_values[i], use_wal);
if (toast_free[i])
pfree(DatumGetPointer(old_value));
***************
*** 972,978 ****
* ----------
*/
static Datum
! toast_save_datum(Relation rel, Datum value)
{
Relation toastrel;
Relation toastidx;
--- 972,978 ----
* ----------
*/
static Datum
! toast_save_datum(Relation rel, Datum value, bool use_wal)
{
Relation toastrel;
Relation toastidx;
***************
*** 1057,1063 ****
if (!HeapTupleIsValid(toasttup))
elog(ERROR, "failed to build TOAST tuple");
! simple_heap_insert(toastrel, toasttup);
/*
* Create the index entry. We cheat a little here by not using
--- 1057,1064 ----
if (!HeapTupleIsValid(toasttup))
elog(ERROR, "failed to build TOAST tuple");
! /* not worried about forcing commit bits to be set for TOAST */
! fast_heap_insert(toastrel, toasttup, use_wal, !use_wal);
/*
* Create the index entry. We cheat a little here by not using
Index: src/backend/catalog/index.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.274
diff -c -r1.274 index.c
*** src/backend/catalog/index.c 4 Oct 2006 00:29:50 -0000 1.274
--- src/backend/catalog/index.c 4 Jan 2007 15:24:06 -0000
***************
*** 1238,1243 ****
--- 1238,1246 ----
heap_close(pg_class, RowExclusiveLock);
+ /* Remember we did this in current transaction, to allow later optimisations */
+ relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();
+
/* Make sure the relfilenode change is visible */
CommandCounterIncrement();
}
Index: src/backend/commands/copy.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/copy.c,v
retrieving revision 1.273
diff -c -r1.273 copy.c
*** src/backend/commands/copy.c 6 Oct 2006 17:13:58 -0000 1.273
--- src/backend/commands/copy.c 4 Jan 2007 15:24:08 -0000
***************
*** 1652,1657 ****
--- 1652,1659 ----
ExprContext *econtext; /* used for ExecEvalExpr for default atts */
MemoryContext oldcontext = CurrentMemoryContext;
ErrorContextCallback errcontext;
+ bool use_wal = true; /* By default, we use WAL to log db changes */
+ bool force_committed = false;
Assert(cstate->rel);
***************
*** 1843,1848 ****
--- 1845,1878 ----
nfields = file_has_oids ? (attr_count + 1) : attr_count;
field_strings = (char **) palloc(nfields * sizeof(char *));
+ /*
+ * Check for performance optimization by avoiding WAL writes
+ *
+ * If archive logging is not be enabled *and* either
+ * - table is created in same transaction as this COPY
+ * - table data is now being written to new relfilenode
+ * then we can safely avoid writing WAL. Why?
+ * The data files for the table plus toast table/index, plus any indexes
+ * will all be dropped at the end of the transaction if it fails, so we
+ * do not need to worry about inconsistent states.
+ * As mentioned in comments in utils/rel.h, the in-same-transaction test is
+ * not completely reliable, since rd_createSubId can be reset to zero in
+ * certain cases before the end of the creating transaction.
+ * We are doing this for performance only, so we only need to know:
+ * if rd_createSubid != InvalidSubTransactionId then it is *always* just
+ * created.
+ * We also want to set HEAP_XMIN_COMMITTED for these tuples, so we
+ * can only do this when we don't have a previously open portal.
+ * COPY itself open a portal, so we check for just a single portal.
+ * If we have PITR enabled, then we must use_wal
+ */
+ if (NumAccessiblePortals() == 1 &&
+ (cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+ cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId))
+ force_committed = true;
+ if (force_committed && !XLogArchivingActive())
+ use_wal = false;
+
/* Initialize state variables */
cstate->fe_eof = false;
cstate->eol_type = EOL_UNKNOWN;
***************
*** 2076,2082 ****
ExecConstraints(resultRelInfo, slot, estate);
/* OK, store the tuple and create index entries for it */
! simple_heap_insert(cstate->rel, tuple);
if (resultRelInfo->ri_NumIndices > 0)
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
--- 2106,2112 ----
ExecConstraints(resultRelInfo, slot, estate);
/* OK, store the tuple and create index entries for it */
! fast_heap_insert(cstate->rel, tuple, use_wal, force_committed);
if (resultRelInfo->ri_NumIndices > 0)
ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);
***************
*** 2093,2098 ****
--- 2123,2154 ----
}
}
+ /*
+ * If we skipped writing WAL for heaps, then we need to sync
+ */
+ if (!use_wal)
+ {
+ /* main heap */
+ heap_sync(cstate->rel);
+
+ /* main heap indexes, if any */
+ /* we always use WAL for index inserts, so no need to sync */
+
+ /* toast heap, if any */
+ if (OidIsValid(cstate->rel->rd_rel->reltoastrelid))
+ {
+ Relation toastrel;
+
+ toastrel = heap_open(cstate->rel->rd_rel->reltoastrelid,
+ AccessShareLock);
+ heap_sync(toastrel);
+ heap_close(toastrel, AccessShareLock);
+ }
+
+ /* toast index, if toast heap */
+ /* we always use WAL for index inserts, so no need to sync */
+ }
+
/* Done, clean up */
error_context_stack = errcontext.previous;
Index: src/backend/executor/execMain.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/execMain.c,v
retrieving revision 1.282
diff -c -r1.282 execMain.c
*** src/backend/executor/execMain.c 26 Dec 2006 21:37:19 -0000 1.282
--- src/backend/executor/execMain.c 4 Jan 2007 15:24:08 -0000
***************
*** 1410,1416 ****
*/
newId = heap_insert(resultRelationDesc, tuple,
estate->es_snapshot->curcid,
! true, true);
IncrAppended();
(estate->es_processed)++;
--- 1410,1416 ----
*/
newId = heap_insert(resultRelationDesc, tuple,
estate->es_snapshot->curcid,
! true, true, false);
IncrAppended();
(estate->es_processed)++;
***************
*** 2516,2526 ****
*/
if (!estate->es_into_relation_use_wal &&
!estate->es_into_relation_descriptor->rd_istemp)
! {
! FlushRelationBuffers(estate->es_into_relation_descriptor);
! /* FlushRelationBuffers will have opened rd_smgr */
! smgrimmedsync(estate->es_into_relation_descriptor->rd_smgr);
! }
/* close rel, but keep lock until commit */
heap_close(estate->es_into_relation_descriptor, NoLock);
--- 2516,2522 ----
*/
if (!estate->es_into_relation_use_wal &&
!estate->es_into_relation_descriptor->rd_istemp)
! heap_sync(estate->es_into_relation_descriptor);
/* close rel, but keep lock until commit */
heap_close(estate->es_into_relation_descriptor, NoLock);
***************
*** 2577,2583 ****
tuple,
estate->es_snapshot->curcid,
estate->es_into_relation_use_wal,
! false); /* never any point in using FSM */
/* We know this is a newly created relation, so there are no indexes */
--- 2573,2580 ----
tuple,
estate->es_snapshot->curcid,
estate->es_into_relation_use_wal,
! false, /* never any point in using FSM */
! true);
/* We know this is a newly created relation, so there are no indexes */
Index: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/relcache.c,v
retrieving revision 1.252
diff -c -r1.252 relcache.c
*** src/backend/utils/cache/relcache.c 31 Dec 2006 20:32:04 -0000 1.252
--- src/backend/utils/cache/relcache.c 4 Jan 2007 15:24:10 -0000
***************
*** 836,841 ****
--- 836,842 ----
relation->rd_refcnt = 0;
relation->rd_isnailed = false;
relation->rd_createSubid = InvalidSubTransactionId;
+ relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace);
/*
***************
*** 1342,1347 ****
--- 1343,1349 ----
*/
relation->rd_isnailed = true;
relation->rd_createSubid = InvalidSubTransactionId;
+ relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
relation->rd_istemp = false;
/*
***************
*** 1753,1758 ****
--- 1755,1761 ----
Oid save_relid = RelationGetRelid(relation);
int old_refcnt = relation->rd_refcnt;
SubTransactionId old_createSubid = relation->rd_createSubid;
+ SubTransactionId old_newRelfilenodeSubid = relation->rd_newRelfilenodeSubid;
TupleDesc old_att = relation->rd_att;
RuleLock *old_rules = relation->rd_rules;
MemoryContext old_rulescxt = relation->rd_rulescxt;
***************
*** 1771,1776 ****
--- 1774,1781 ----
}
relation->rd_refcnt = old_refcnt;
relation->rd_createSubid = old_createSubid;
+ relation->rd_newRelfilenodeSubid = old_newRelfilenodeSubid;
+
if (equalTupleDescs(old_att, relation->rd_att))
{
/* needn't flush typcache here */
***************
*** 1811,1817 ****
{
bool rebuild;
! if (relation->rd_createSubid != InvalidSubTransactionId)
{
/*
* New relcache entries are always rebuilt, not flushed; else we'd
--- 1816,1823 ----
{
bool rebuild;
! if (relation->rd_createSubid != InvalidSubTransactionId ||
! relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
{
/*
* New relcache entries are always rebuilt, not flushed; else we'd
***************
*** 1893,1898 ****
--- 1899,1907 ----
* so we do not touch new-in-transaction relations; they cannot be targets
* of cross-backend SI updates (and our own updates now go through a
* separate linked list that isn't limited by the SI message buffer size).
+ * We don't do anything special for newRelfilenode-in-transaction relations,
+ * though since we have a lock on the relation nobody else should be
+ * generating cache invalidation messages for it anyhow.
*
* We do this in two phases: the first pass deletes deletable items, and
* the second one rebuilds the rebuildable items. This is essential for
***************
*** 2069,2074 ****
--- 2078,2084 ----
continue;
}
}
+ relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
/*
* Flush any temporary index list.
***************
*** 2130,2135 ****
--- 2140,2152 ----
continue;
}
}
+ if (relation->rd_newRelfilenodeSubid == mySubid)
+ {
+ if (isCommit)
+ relation->rd_newRelfilenodeSubid = parentSubid;
+ else
+ relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
+ }
/*
* Flush any temporary index list.
***************
*** 2219,2224 ****
--- 2236,2242 ----
/* it's being created in this transaction */
rel->rd_createSubid = GetCurrentSubTransactionId();
+ rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
/* must flag that we have rels created in this transaction */
need_eoxact_work = true;
***************
*** 3364,3369 ****
--- 3382,3388 ----
rel->rd_indexlist = NIL;
rel->rd_oidindex = InvalidOid;
rel->rd_createSubid = InvalidSubTransactionId;
+ rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;
rel->rd_amcache = NULL;
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
Index: src/backend/utils/mmgr/portalmem.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v
retrieving revision 1.97
diff -c -r1.97 portalmem.c
*** src/backend/utils/mmgr/portalmem.c 23 Nov 2006 01:14:59 -0000 1.97
--- src/backend/utils/mmgr/portalmem.c 4 Jan 2007 15:24:12 -0000
***************
*** 88,94 ****
} while(0)
static MemoryContext PortalMemory = NULL;
!
/* ----------------------------------------------------------------
* public portal interface functions
--- 88,94 ----
} while(0)
static MemoryContext PortalMemory = NULL;
! static int NPortals = 0;
/* ----------------------------------------------------------------
* public portal interface functions
***************
*** 227,232 ****
--- 227,234 ----
/* put portal in table (sets portal->name) */
PortalHashTableInsert(portal, name);
+ ++NPortals;
+
return portal;
}
***************
*** 410,415 ****
--- 412,420 ----
/* release portal struct (it's in PortalMemory) */
pfree(portal);
+
+ if (--NPortals < 0)
+ elog(ERROR, "error in number of portals");
}
/*
***************
*** 548,554 ****
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
! hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
{
--- 553,559 ----
HASH_SEQ_STATUS status;
PortalHashEnt *hentry;
! hash_seq_init(&status, PortalHashTable);
while ((hentry = (PortalHashEnt *) hash_seq_search(&status)) != NULL)
{
***************
*** 802,807 ****
--- 807,823 ----
}
}
+ /*
+ * Get the number of portals from which the backend *could* retrieve
+ * tuples. This is an important number for the safe use of some
+ * performance optimizations.
+ */
+ int
+ NumAccessiblePortals(void)
+ {
+ return NPortals;
+ }
+
/* Find all available cursors */
Datum
pg_cursor(PG_FUNCTION_ARGS)
Index: src/include/miscadmin.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/miscadmin.h,v
retrieving revision 1.190
diff -c -r1.190 miscadmin.h
*** src/include/miscadmin.h 19 Oct 2006 18:32:47 -0000 1.190
--- src/include/miscadmin.h 4 Jan 2007 15:24:13 -0000
***************
*** 216,221 ****
--- 216,224 ----
/* in tcop/postgres.c */
extern void check_stack_depth(void);
+ /* in utils/mmgr/portalmem.c */
+ extern int NumAccessiblePortals(void);
+
/*****************************************************************************
* pdir.h -- *
Index: src/include/access/heapam.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/access/heapam.h,v
retrieving revision 1.117
diff -c -r1.117 heapam.h
*** src/include/access/heapam.h 5 Nov 2006 22:42:10 -0000 1.117
--- src/include/access/heapam.h 4 Jan 2007 15:24:13 -0000
***************
*** 157,163 ****
extern void setLastTid(const ItemPointer tid);
extern Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid,
! bool use_wal, bool use_fsm);
extern HTSU_Result heap_delete(Relation relation, ItemPointer tid,
ItemPointer ctid, TransactionId *update_xmax,
CommandId cid, Snapshot crosscheck, bool wait);
--- 157,163 ----
extern void setLastTid(const ItemPointer tid);
extern Oid heap_insert(Relation relation, HeapTuple tup, CommandId cid,
! bool use_wal, bool use_fsm, bool force_committed);
extern HTSU_Result heap_delete(Relation relation, ItemPointer tid,
ItemPointer ctid, TransactionId *update_xmax,
CommandId cid, Snapshot crosscheck, bool wait);
***************
*** 178,183 ****
--- 178,186 ----
extern void simple_heap_update(Relation relation, ItemPointer otid,
HeapTuple tup);
+ extern Oid fast_heap_insert(Relation relation, HeapTuple tup, bool use_wal,
+ bool force_committed);
+
extern void heap_markpos(HeapScanDesc scan);
extern void heap_restrpos(HeapScanDesc scan);
***************
*** 236,239 ****
--- 239,244 ----
extern HeapTuple heap_addheader(int natts, bool withoid,
Size structlen, void *structure);
+ extern void heap_sync(Relation relation);
+
#endif /* HEAPAM_H */
Index: src/include/access/tuptoaster.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/access/tuptoaster.h,v
retrieving revision 1.28
diff -c -r1.28 tuptoaster.h
*** src/include/access/tuptoaster.h 13 Jul 2006 17:47:01 -0000 1.28
--- src/include/access/tuptoaster.h 4 Jan 2007 15:24:13 -0000
***************
*** 69,75 ****
* ----------
*/
extern HeapTuple toast_insert_or_update(Relation rel,
! HeapTuple newtup, HeapTuple oldtup);
/* ----------
* toast_delete -
--- 69,75 ----
* ----------
*/
extern HeapTuple toast_insert_or_update(Relation rel,
! HeapTuple newtup, HeapTuple oldtup, bool use_wal);
/* ----------
* toast_delete -
Index: src/include/utils/rel.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/rel.h,v
retrieving revision 1.93
diff -c -r1.93 rel.h
*** src/include/utils/rel.h 23 Dec 2006 00:43:13 -0000 1.93
--- src/include/utils/rel.h 4 Jan 2007 15:24:13 -0000
***************
*** 137,142 ****
--- 137,144 ----
char rd_indexvalid; /* state of rd_indexlist: 0 = not valid, 1 =
* valid, 2 = temporarily forced */
SubTransactionId rd_createSubid; /* rel was created in current xact */
+ SubTransactionId rd_newRelfilenodeSubid; /* rel had new relfilenode in current xact */
+
/*
* rd_createSubid is the ID of the highest subtransaction the rel has
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings