diff options
Diffstat (limited to 'src/backend/commands/copy.c')
-rw-r--r-- | src/backend/commands/copy.c | 112 |
1 files changed, 57 insertions, 55 deletions
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index a2e1939ea25..99d347f5907 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.278 2007/03/13 00:33:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.279 2007/03/29 00:15:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1125,11 +1125,10 @@ DoCopy(const CopyStmt *stmt, const char *queryString) cstate->copy_dest = COPY_FILE; /* default */ cstate->filename = stmt->filename; - if (is_from) /* copy from file to database */ - CopyFrom(cstate); + if (is_from) + CopyFrom(cstate); /* copy from file to database */ else - /* copy from database to file */ - DoCopyTo(cstate); + DoCopyTo(cstate); /* copy from database to file */ /* * Close the relation or query. If reading, we can release the @@ -1640,7 +1639,9 @@ CopyFrom(CopyState cstate) 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 */ + CommandId mycid = GetCurrentCommandId(); + bool use_wal = true; /* by default, use WAL logging */ + bool use_fsm = true; /* by default, use FSM for free space */ Assert(cstate->rel); @@ -1663,6 +1664,48 @@ CopyFrom(CopyState cstate) RelationGetRelationName(cstate->rel)))); } + /*---------- + * Check to see if we can avoid writing WAL + * + * If archive logging is not enabled *and* either + * - table was created in same transaction as this COPY + * - data is being written to relfilenode created in this transaction + * then we can skip writing WAL. It's safe because if the transaction + * doesn't commit, we'll discard the table (or the new relfilenode file). + * If it does commit, we'll have done the heap_sync at the bottom of this + * routine first. + * + * As mentioned in comments in utils/rel.h, the in-same-transaction test + * is not completely reliable, since in rare cases rd_createSubid or + * rd_newRelfilenodeSubid can be cleared before the end of the transaction. + * However this is OK since at worst we will fail to make the optimization. + * + * When skipping WAL it's entirely possible that COPY itself will write no + * WAL records at all. This is of concern because RecordTransactionCommit + * might decide it doesn't need to log our eventual commit, which we + * certainly need it to do. However, we need no special action here for + * that, because if we have a new table or new relfilenode then there + * must have been a WAL-logged pg_class update earlier in the transaction. + * + * Also, if the target file is new-in-transaction, we assume that checking + * FSM for free space is a waste of time, even if we must use WAL because + * of archiving. This could possibly be wrong, but it's unlikely. + * + * The comments for heap_insert and RelationGetBufferForTuple specify that + * skipping WAL logging is only safe if we ensure that our tuples do not + * go into pages containing tuples from any other transactions --- but this + * must be the case if we have a new table or new relfilenode, so we need + * no additional work to enforce that. + *---------- + */ + if (cstate->rel->rd_createSubid != InvalidSubTransactionId || + cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId) + { + use_fsm = false; + if (!XLogArchivingActive()) + use_wal = false; + } + if (pipe) { if (whereToSendOutput == DestRemote) @@ -1832,28 +1875,6 @@ CopyFrom(CopyState cstate) 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. If we have PITR enabled, then we *must* use_wal - */ - if ((cstate->rel->rd_createSubid != InvalidSubTransactionId || - cstate->rel->rd_newRelfilenodeSubid != InvalidSubTransactionId) - && !XLogArchivingActive()) - use_wal = false; - /* Initialize state variables */ cstate->fe_eof = false; cstate->eol_type = EOL_UNKNOWN; @@ -2087,7 +2108,7 @@ CopyFrom(CopyState cstate) ExecConstraints(resultRelInfo, slot, estate); /* OK, store the tuple and create index entries for it */ - fast_heap_insert(cstate->rel, tuple, use_wal); + heap_insert(cstate->rel, tuple, mycid, use_wal, use_fsm); if (resultRelInfo->ri_NumIndices > 0) ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false); @@ -2104,32 +2125,6 @@ CopyFrom(CopyState cstate) } } - /* - * 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; @@ -2164,6 +2159,13 @@ CopyFrom(CopyState cstate) errmsg("could not read from file \"%s\": %m", cstate->filename))); } + + /* + * If we skipped writing WAL, then we need to sync the heap (but not + * indexes since those use WAL anyway) + */ + if (!use_wal) + heap_sync(cstate->rel); } |