<!--
-$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.42 2005/05/02 18:26:52 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/maintenance.sgml,v 1.43 2005/05/10 22:27:29 momjian Exp $
-->
<chapter id="maintenance">
</para>
</sect1>
- <sect1 id="check-files-after-crash">
- <title>Check files after crash</title>
-
- <indexterm zone="check-files-after-crash">
- <primary>stale file</primary>
- </indexterm>
-
- <para>
- <productname>PostgreSQL</productname> recovers automatically after crash
- using the write-ahead log (see <xref linkend="wal">) and no manual
- operations are normally needed. However, if there was a transaction running
- when the crash occured that created or dropped a relation, the
- transaction might have left a stale file in the data directory. If this
- happens, you will get a notice in the log file stating which files can be
- deleted.
- </para>
- </sect1>
<sect1 id="logfile-maintenance">
<title>Log File Maintenance</title>
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.190 2005/05/02 18:26:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.191 2005/05/10 22:27:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/relcache.h"
-#include "utils/flatfiles.h"
/*
CreateCheckPoint(true, true);
- CheckStaleRelFiles();
-
/*
* Close down recovery environment
*/
*/
remove_backup_label();
}
- else
- {
- XLogInitRelationCache();
- CheckStaleRelFiles();
- XLogCloseRelationCache();
- }
/*
* Preallocate additional log files, if wanted.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.60 2005/05/02 18:26:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.61 2005/05/10 22:27:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
return path;
}
-/*
- * GetTablespacePath - construct path to a tablespace symbolic link
- *
- * Result is a palloc'd string.
- *
- * XXX this must agree with relpath and GetDatabasePath!
- */
-char *
-GetTablespacePath(Oid spcNode)
-{
- int pathlen;
- char *path;
-
- Assert(spcNode != GLOBALTABLESPACE_OID);
-
- if (spcNode == DEFAULTTABLESPACE_OID)
- {
- /* The default tablespace is {datadir}/base */
- pathlen = strlen(DataDir) + 5 + 1;
- path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "%s/base",
- DataDir);
- }
- else
- {
- /* All other tablespaces have symlinks in pg_tblspc */
- pathlen = strlen(DataDir) + 11 + OIDCHARS + 1;
- path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "%s/pg_tblspc/%u",
- DataDir, spcNode);
- }
- return path;
-}
/*
* IsSystemRelation
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.18 2005/05/02 18:26:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.19 2005/05/10 22:27:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* All seems well, create the symlink
*/
- linkloc = GetTablespacePath(tablespaceoid);
+ linkloc = (char *) palloc(strlen(DataDir) + 11 + 10 + 1);
+ sprintf(linkloc, "%s/pg_tblspc/%u", DataDir, tablespaceoid);
if (symlink(location, linkloc) < 0)
ereport(ERROR,
char *subfile;
struct stat st;
- location = GetTablespacePath(tablespaceoid);
+ location = (char *) palloc(strlen(DataDir) + 11 + 10 + 1);
+ sprintf(location, "%s/pg_tblspc/%u", DataDir, tablespaceoid);
/*
* Check if the tablespace still contains any files. We try to rmdir
set_short_version(location);
/* Create the symlink if not already present */
- linkloc = GetTablespacePath(xlrec->ts_id);
+ linkloc = (char *) palloc(strlen(DataDir) + 11 + 10 + 1);
+ sprintf(linkloc, "%s/pg_tblspc/%u", DataDir, xlrec->ts_id);
if (symlink(location, linkloc) < 0)
{
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.41 2005/05/02 18:26:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.42 2005/05/10 22:27:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "catalog/pg_tablespace.h"
-#include "catalog/catalog.h"
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
fctx = palloc(sizeof(ts_db_fctx));
+ /*
+ * size = path length + tablespace dirname length + 2 dir sep
+ * chars + oid + terminator
+ */
+ fctx->location = (char *) palloc(strlen(DataDir) + 11 + 10 + 1);
if (tablespaceOid == GLOBALTABLESPACE_OID)
{
fctx->dirdesc = NULL;
}
else
{
- fctx->location = GetTablespacePath(tablespaceOid);
+ if (tablespaceOid == DEFAULTTABLESPACE_OID)
+ sprintf(fctx->location, "%s/base", DataDir);
+ else
+ sprintf(fctx->location, "%s/pg_tblspc/%u", DataDir,
+ tablespaceOid);
+
fctx->dirdesc = AllocateDir(fctx->location);
if (!fctx->dirdesc)
# Makefile for utils/init
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.19 2005/05/02 18:26:53 momjian Exp $
+# $PostgreSQL: pgsql/src/backend/utils/init/Makefile,v 1.20 2005/05/10 22:27:30 momjian Exp $
#
#-------------------------------------------------------------------------
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
-OBJS = flatfiles.o globals.o miscinit.o postinit.o checkfiles.o
+OBJS = flatfiles.o globals.o miscinit.o postinit.o
all: SUBSYS.o
+++ /dev/null
-/*-------------------------------------------------------------------------
- *
- * checkfiles.c
- * check for stale relation files during crash recovery
- *
- * If a backend crashes while in a transaction that has created or
- * deleted a relfilenode, a stale file can be left over in the data
- * directory. This file contains routines to clean up those stale
- * files on recovery.
- *
- * This adds a 17% increase in startup cost for 100 empty databases. bjm
- * One optimization would be to create a 'dirty' file on a postmaster recovery
- * and remove the dirty flag only when a clean startup detects no unreferenced
- * files, and use the 'dirty' flag to determine if we should run this on
- * a clean startup.
- *
- * $PostgreSQL: pgsql/src/backend/utils/init/checkfiles.c,v 1.2 2005/05/05 22:18:27 tgl Exp $
- *
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/heapam.h"
-#include "access/relscan.h"
-#include "access/skey.h"
-#include "catalog/catalog.h"
-#include "catalog/pg_tablespace.h"
-#include "miscadmin.h"
-#include "storage/fd.h"
-#include "utils/flatfiles.h"
-#include "utils/fmgroids.h"
-#include "utils/resowner.h"
-
-
-static void CheckStaleRelFilesFrom(Oid tablespaceoid, Oid dboid);
-static void CheckStaleRelFilesFromTablespace(Oid tablespaceoid);
-
-/* Like AllocateDir, but ereports on failure */
-static DIR *
-AllocateDirChecked(char *path)
-{
- DIR *dirdesc = AllocateDir(path);
-
- if (dirdesc == NULL)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not open directory \"%s\": %m",
- path)));
- return dirdesc;
-}
-
-/*
- * Scan through all tablespaces for relations left over
- * by aborted transactions.
- */
-void
-CheckStaleRelFiles(void)
-{
- DIR *dirdesc;
- struct dirent *de;
- char *path;
- int pathlen;
-
- pathlen = strlen(DataDir) + 11 + 1;
- path = (char *) palloc(pathlen);
- snprintf(path, pathlen, "%s/pg_tblspc/", DataDir);
- dirdesc = AllocateDirChecked(path);
- while ((de = readdir(dirdesc)) != NULL)
- {
- char *invalid;
- Oid tablespaceoid;
-
- /* Check that the directory name looks like valid tablespace link. */
- tablespaceoid = (Oid) strtol(de->d_name, &invalid, 10);
- if (invalid[0] == '\0')
- CheckStaleRelFilesFromTablespace(tablespaceoid);
- }
- FreeDir(dirdesc);
- pfree(path);
-
- CheckStaleRelFilesFromTablespace(DEFAULTTABLESPACE_OID);
-}
-
-/* Scan a specific tablespace for stale relations */
-static void
-CheckStaleRelFilesFromTablespace(Oid tablespaceoid)
-{
- DIR *dirdesc;
- struct dirent *de;
- char *path;
-
- path = GetTablespacePath(tablespaceoid);
-
- dirdesc = AllocateDirChecked(path);
- while ((de = readdir(dirdesc)) != NULL)
- {
- char *invalid;
- Oid dboid;
-
- dboid = (Oid) strtol(de->d_name, &invalid, 10);
- if (invalid[0] == '\0')
- CheckStaleRelFilesFrom(tablespaceoid, dboid);
- }
- FreeDir(dirdesc);
- pfree(path);
-}
-
-/* Scan a specific database in a specific tablespace for stale relations.
- *
- * First, pg_class for the database is opened, and the relfilenodes of all
- * relations mentioned there are stored in a hash table.
- *
- * Then the directory is scanned. Every file in the directory that's not
- * found in pg_class (the hash table) is logged.
- */
-static void
-CheckStaleRelFilesFrom(Oid tablespaceoid, Oid dboid)
-{
- DIR *dirdesc;
- struct dirent *de;
- HASHCTL hashctl;
- HTAB *relfilenodeHash;
- RelFileNode rnode;
- char *path;
-
- /*
- * The entry contents is not used for anything, we just check if an oid is
- * in the hash table or not.
- */
- hashctl.keysize = sizeof(Oid);
- hashctl.entrysize = sizeof(Oid);
- hashctl.hash = tag_hash;
- relfilenodeHash = hash_create("relfilenodeHash", 100, &hashctl,
- HASH_FUNCTION | HASH_ELEM);
-
- /* Read all relfilenodes from pg_class into the hash table */
- {
- ResourceOwner owner,
- oldowner;
- Relation rel;
- HeapScanDesc scan;
- HeapTuple tuple;
-
- /* Need a resowner to keep the heapam and buffer code happy */
- owner = ResourceOwnerCreate(NULL, "CheckStaleRelFiles");
- oldowner = CurrentResourceOwner;
- CurrentResourceOwner = owner;
-
- rnode.spcNode = tablespaceoid;
- rnode.dbNode = dboid;
- rnode.relNode = RelationRelationId;
- rel = XLogOpenRelation(true, 0, rnode);
-
- scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
- while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
- {
- Form_pg_class classform = (Form_pg_class) GETSTRUCT(tuple);
-
- hash_search(relfilenodeHash, &classform->relfilenode,
- HASH_ENTER, NULL);
- }
- heap_endscan(scan);
-
- XLogCloseRelation(rnode);
- CurrentResourceOwner = oldowner;
- ResourceOwnerDelete(owner);
- }
-
- /* Scan the directory */
- path = GetDatabasePath(dboid, tablespaceoid);
-
- dirdesc = AllocateDirChecked(path);
- while ((de = readdir(dirdesc)) != NULL)
- {
- char *invalid;
- Oid relfilenode;
-
- relfilenode = strtol(de->d_name, &invalid, 10);
- if (invalid[0] == '\0')
- {
- /*
- * Filename was a valid number, check if pg_class knows about it
- */
- if (hash_search(relfilenodeHash, &relfilenode,
- HASH_FIND, NULL) == NULL)
- {
- char *filepath;
-
- rnode.spcNode = tablespaceoid;
- rnode.dbNode = dboid;
- rnode.relNode = relfilenode;
-
- filepath = relpath(rnode);
- ereport(LOG,
- (errcode_for_file_access(),
- errmsg("table or index file \"%s\" is stale and can safely be removed",
- filepath)));
- pfree(filepath);
- }
- }
- }
- FreeDir(dirdesc);
- pfree(path);
- hash_destroy(relfilenodeHash);
-}
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.31 2005/05/02 18:26:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.32 2005/05/10 22:27:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
extern char *relpath(RelFileNode rnode);
extern char *GetDatabasePath(Oid dbNode, Oid spcNode);
-extern char *GetTablespacePath(Oid spcNode);
extern bool IsSystemRelation(Relation relation);
extern bool IsToastRelation(Relation relation);
* Routines for maintaining "flat file" images of the shared catalogs.
*
*
- * $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.2 2005/05/02 18:26:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/flatfiles.h,v 1.3 2005/05/10 22:27:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum flatfile_update_trigger(PG_FUNCTION_ARGS);
-/* from checkfiles.c */
-extern void CheckStaleRelFiles(void);
-
#endif /* FLATFILES_H */