diff options
| author | Tom Lane | 2008-04-16 23:59:40 +0000 |
|---|---|---|
| committer | Tom Lane | 2008-04-16 23:59:40 +0000 |
| commit | d1cbd26ded664bf2d3ace87036b822dedba28077 (patch) | |
| tree | b991c0196d5abe92d4d77e79449b44ced35b7d5f /src/backend | |
| parent | 74be86847c8cdd274a274fc9384988cb81756d87 (diff) | |
Repair two places where SIGTERM exit could leave shared memory state
corrupted. (Neither is very important if SIGTERM is used to shut down the
whole database cluster together, but there's a problem if someone tries to
SIGTERM individual backends.) To do this, introduce new infrastructure
macros PG_ENSURE_ERROR_CLEANUP/PG_END_ENSURE_ERROR_CLEANUP that take care
of transiently pushing an on_shmem_exit cleanup hook. Also use this method
for createdb cleanup --- that wasn't a shared-memory-corruption problem,
but SIGTERM abort of createdb could leave orphaned files lying around.
Backpatch as far as 8.2. The shmem corruption cases don't exist in 8.1,
and the createdb usage doesn't seem important enough to risk backpatching
further.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/access/nbtree/nbtree.c | 17 | ||||
| -rw-r--r-- | src/backend/access/nbtree/nbtutils.c | 18 | ||||
| -rw-r--r-- | src/backend/access/transam/xlog.c | 32 | ||||
| -rw-r--r-- | src/backend/commands/dbcommands.c | 45 | ||||
| -rw-r--r-- | src/backend/port/ipc_test.c | 12 | ||||
| -rw-r--r-- | src/backend/storage/ipc/ipc.c | 26 |
6 files changed, 98 insertions, 52 deletions
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 24f9b4c77b..06278afc6a 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -12,7 +12,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.158 2008/04/13 19:18:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.159 2008/04/16 23:59:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -24,6 +24,7 @@ #include "commands/vacuum.h" #include "miscadmin.h" #include "storage/freespace.h" +#include "storage/ipc.h" #include "storage/lmgr.h" #include "utils/memutils.h" @@ -530,21 +531,15 @@ btbulkdelete(PG_FUNCTION_ARGS) stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); /* Establish the vacuum cycle ID to use for this scan */ - PG_TRY(); + /* The ENSURE stuff ensures we clean up shared memory on failure */ + PG_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)); { cycleid = _bt_start_vacuum(rel); btvacuumscan(info, stats, callback, callback_state, cycleid); - - _bt_end_vacuum(rel); - } - PG_CATCH(); - { - /* Make sure shared memory gets cleaned up */ - _bt_end_vacuum(rel); - PG_RE_THROW(); } - PG_END_TRY(); + PG_END_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)); + _bt_end_vacuum(rel); PG_RETURN_POINTER(stats); } diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index 6f88a34488..6759ce6f2b 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.88 2008/01/01 19:45:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.89 2008/04/16 23:59:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1252,8 +1252,11 @@ _bt_vacuum_cycleid(Relation rel) /* * _bt_start_vacuum --- assign a cycle ID to a just-starting VACUUM operation * - * Note: the caller must guarantee (via PG_TRY) that it will eventually call - * _bt_end_vacuum, else we'll permanently leak an array slot. + * Note: the caller must guarantee that it will eventually call + * _bt_end_vacuum, else we'll permanently leak an array slot. To ensure + * that this happens even in elog(FATAL) scenarios, the appropriate coding + * is not just a PG_TRY, but + * PG_ENSURE_ERROR_CLEANUP(_bt_end_vacuum_callback, PointerGetDatum(rel)) */ BTCycleId _bt_start_vacuum(Relation rel) @@ -1338,6 +1341,15 @@ _bt_end_vacuum(Relation rel) } /* + * _bt_end_vacuum wrapped as an on_shmem_exit callback function + */ +void +_bt_end_vacuum_callback(int code, Datum arg) +{ + _bt_end_vacuum((Relation) DatumGetPointer(arg)); +} + +/* * BTreeShmemSize --- report amount of shared memory space needed */ Size diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b059e49bc3..bb8f3d4761 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.296 2008/04/05 01:34:06 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.297 2008/04/16 23:59:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,6 +43,7 @@ #include "postmaster/bgwriter.h" #include "storage/bufpage.h" #include "storage/fd.h" +#include "storage/ipc.h" #include "storage/pmsignal.h" #include "storage/procarray.h" #include "storage/smgr.h" @@ -419,11 +420,11 @@ static void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, static void WriteControlFile(void); static void ReadControlFile(void); static char *str_time(pg_time_t tnow); -static void issue_xlog_fsync(void); - #ifdef WAL_DEBUG static void xlog_outrec(StringInfo buf, XLogRecord *record); #endif +static void issue_xlog_fsync(void); +static void pg_start_backup_callback(int code, Datum arg); static bool read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc); static void rm_redo_error_callback(void *arg); @@ -6442,8 +6443,8 @@ pg_start_backup(PG_FUNCTION_ARGS) XLogCtl->Insert.forcePageWrites = true; LWLockRelease(WALInsertLock); - /* Use a TRY block to ensure we release forcePageWrites if fail below */ - PG_TRY(); + /* Ensure we release forcePageWrites if fail below */ + PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0); { /* * Force a CHECKPOINT. Aside from being necessary to prevent torn @@ -6515,16 +6516,7 @@ pg_start_backup(PG_FUNCTION_ARGS) errmsg("could not write file \"%s\": %m", BACKUP_LABEL_FILE))); } - PG_CATCH(); - { - /* Turn off forcePageWrites on failure */ - LWLockAcquire(WALInsertLock, LW_EXCLUSIVE); - XLogCtl->Insert.forcePageWrites = false; - LWLockRelease(WALInsertLock); - - PG_RE_THROW(); - } - PG_END_TRY(); + PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0); /* * We're done. As a convenience, return the starting WAL location. @@ -6534,6 +6526,16 @@ pg_start_backup(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); } +/* Error cleanup callback for pg_start_backup */ +static void +pg_start_backup_callback(int code, Datum arg) +{ + /* Turn off forcePageWrites on failure */ + LWLockAcquire(WALInsertLock, LW_EXCLUSIVE); + XLogCtl->Insert.forcePageWrites = false; + LWLockRelease(WALInsertLock); +} + /* * pg_stop_backup: finish taking an on-line backup dump * diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index b7bd041e3a..857db388a8 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.205 2008/03/26 21:10:37 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.206 2008/04/16 23:59:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,6 +41,7 @@ #include "pgstat.h" #include "postmaster/bgwriter.h" #include "storage/freespace.h" +#include "storage/ipc.h" #include "storage/procarray.h" #include "storage/smgr.h" #include "utils/acl.h" @@ -53,7 +54,14 @@ #include "utils/tqual.h" +typedef struct +{ + Oid src_dboid; /* source (template) DB */ + Oid dest_dboid; /* DB we are trying to create */ +} createdb_failure_params; + /* non-export function prototypes */ +static void createdb_failure_callback(int code, Datum arg); static bool get_db_info(const char *name, LOCKMODE lockmode, Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, @@ -99,6 +107,7 @@ createdb(const CreatedbStmt *stmt) int encoding = -1; int dbconnlimit = -1; int ctype_encoding; + createdb_failure_params fparms; /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -449,12 +458,15 @@ createdb(const CreatedbStmt *stmt) /* * Once we start copying subdirectories, we need to be able to clean 'em - * up if we fail. Establish a TRY block to make sure this happens. (This + * up if we fail. Use an ENSURE block to make sure this happens. (This * is not a 100% solution, because of the possibility of failure during * transaction commit after we leave this routine, but it should handle * most scenarios.) */ - PG_TRY(); + fparms.src_dboid = src_dboid; + fparms.dest_dboid = dboid; + PG_ENSURE_ERROR_CLEANUP(createdb_failure_callback, + PointerGetDatum(&fparms)); { /* * Iterate through all tablespaces of the template database, and copy @@ -565,18 +577,25 @@ createdb(const CreatedbStmt *stmt) */ database_file_update_needed(); } - PG_CATCH(); - { - /* Release lock on source database before doing recursive remove */ - UnlockSharedObject(DatabaseRelationId, src_dboid, 0, - ShareLock); + PG_END_ENSURE_ERROR_CLEANUP(createdb_failure_callback, + PointerGetDatum(&fparms)); +} + +/* Error cleanup callback for createdb */ +static void +createdb_failure_callback(int code, Datum arg) +{ + createdb_failure_params *fparms = (createdb_failure_params *) DatumGetPointer(arg); - /* Throw away any successfully copied subdirectories */ - remove_dbtablespaces(dboid); + /* + * Release lock on source database before doing recursive remove. + * This is not essential but it seems desirable to release the lock + * as soon as possible. + */ + UnlockSharedObject(DatabaseRelationId, fparms->src_dboid, 0, ShareLock); - PG_RE_THROW(); - } - PG_END_TRY(); + /* Throw away any successfully copied subdirectories */ + remove_dbtablespaces(fparms->dest_dboid); } diff --git a/src/backend/port/ipc_test.c b/src/backend/port/ipc_test.c index c4a6f487db..a9e133a265 100644 --- a/src/backend/port/ipc_test.c +++ b/src/backend/port/ipc_test.c @@ -21,7 +21,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/ipc_test.c,v 1.24 2008/03/24 18:08:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/port/ipc_test.c,v 1.25 2008/04/16 23:59:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,7 +58,7 @@ char *DataDir = "."; static struct ONEXIT { - void (*function) (int code, Datum arg); + pg_on_exit_callback function; Datum arg; } on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS]; @@ -85,7 +85,7 @@ shmem_exit(int code) } void - on_shmem_exit(void (*function) (int code, Datum arg), Datum arg) +on_shmem_exit(pg_on_exit_callback function, Datum arg) { if (on_shmem_exit_index >= MAX_ON_EXITS) elog(FATAL, "out of on_shmem_exit slots"); @@ -114,9 +114,9 @@ ProcessInterrupts(void) } int -ExceptionalCondition(char *conditionName, - char *errorType, - char *fileName, +ExceptionalCondition(const char *conditionName, + const char *errorType, + const char *fileName, int lineNumber) { fprintf(stderr, "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n", diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index 91fbea2ea4..ccfa8a27bf 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/ipc.c,v 1.100 2008/01/01 19:45:51 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/ipc.c,v 1.101 2008/04/16 23:59:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,7 +56,7 @@ bool proc_exit_inprogress = false; static struct ONEXIT { - void (*function) (int code, Datum arg); + pg_on_exit_callback function; Datum arg; } on_proc_exit_list[MAX_ON_EXITS], on_shmem_exit_list[MAX_ON_EXITS]; @@ -184,7 +184,7 @@ shmem_exit(int code) * ---------------------------------------------------------------- */ void - on_proc_exit(void (*function) (int code, Datum arg), Datum arg) +on_proc_exit(pg_on_exit_callback function, Datum arg) { if (on_proc_exit_index >= MAX_ON_EXITS) ereport(FATAL, @@ -205,7 +205,7 @@ void * ---------------------------------------------------------------- */ void - on_shmem_exit(void (*function) (int code, Datum arg), Datum arg) +on_shmem_exit(pg_on_exit_callback function, Datum arg) { if (on_shmem_exit_index >= MAX_ON_EXITS) ereport(FATAL, @@ -219,6 +219,24 @@ void } /* ---------------------------------------------------------------- + * cancel_shmem_exit + * + * this function removes an entry, if present, from the list of + * functions to be invoked by shmem_exit(). For simplicity, + * only the latest entry can be removed. (We could work harder + * but there is no need for current uses.) + * ---------------------------------------------------------------- + */ +void +cancel_shmem_exit(pg_on_exit_callback function, Datum arg) +{ + if (on_shmem_exit_index > 0 && + on_shmem_exit_list[on_shmem_exit_index - 1].function == function && + on_shmem_exit_list[on_shmem_exit_index - 1].arg == arg) + --on_shmem_exit_index; +} + +/* ---------------------------------------------------------------- * on_exit_reset * * this function clears all on_proc_exit() and on_shmem_exit() |
