aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/smgr/smgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/smgr/smgr.c')
-rw-r--r--src/backend/storage/smgr/smgr.c134
1 files changed, 112 insertions, 22 deletions
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index d2a940a76e5..01a7877e80a 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -11,13 +11,16 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.42 2000/10/28 16:20:57 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.43 2000/11/08 22:10:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "storage/bufmgr.h"
#include "storage/smgr.h"
+#include "utils/memutils.h"
+
static void smgrshutdown(void);
@@ -26,7 +29,7 @@ typedef struct f_smgr
int (*smgr_init) (void); /* may be NULL */
int (*smgr_shutdown) (void); /* may be NULL */
int (*smgr_create) (Relation reln);
- int (*smgr_unlink) (Relation reln);
+ int (*smgr_unlink) (RelFileNode rnode);
int (*smgr_extend) (Relation reln, char *buffer);
int (*smgr_open) (Relation reln);
int (*smgr_close) (Relation reln);
@@ -60,10 +63,11 @@ static f_smgr smgrsw[] = {
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
mdread, mdwrite, mdflush, mdblindwrt, mdmarkdirty, mdblindmarkdirty,
#ifdef XLOG
- mdnblocks, mdtruncate, mdcommit, mdabort, mdsync},
+ mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
#else
- mdnblocks, mdtruncate, mdcommit, mdabort},
+ mdnblocks, mdtruncate, mdcommit, mdabort
#endif
+ },
#ifdef STABLE_MEMORY_STORAGE
/* main memory */
@@ -94,6 +98,31 @@ static bool smgrwo[] = {
static int NSmgr = lengthof(smgrsw);
/*
+ * We keep a list of all relations (represented as RelFileNode values)
+ * that have been created or deleted in the current transaction. When
+ * a relation is created, we create the physical file immediately, but
+ * remember it so that we can delete the file again if the current
+ * transaction is aborted. Conversely, a deletion request is NOT
+ * executed immediately, but is just entered in the list. When and if
+ * the transaction commits, we can delete the physical file.
+ *
+ * NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
+ * unbetimes. It'd probably be OK to keep it in TopTransactionContext,
+ * but I'm being paranoid.
+ */
+
+typedef struct PendingRelDelete
+{
+ RelFileNode relnode; /* relation that may need to be deleted */
+ int16 which; /* which storage manager? */
+ bool atCommit; /* T=delete at commit; F=delete at abort */
+ struct PendingRelDelete *next; /* linked-list link */
+} PendingRelDelete;
+
+static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
+
+
+/*
* smgrinit(), smgrshutdown() -- Initialize or shut down all storage
* managers.
*
@@ -147,27 +176,58 @@ int
smgrcreate(int16 which, Relation reln)
{
int fd;
+ PendingRelDelete *pending;
if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0)
elog(ERROR, "cannot create %s: %m", RelationGetRelationName(reln));
+ /* Add the relation to the list of stuff to delete at abort */
+ pending = (PendingRelDelete *)
+ MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
+ pending->relnode = reln->rd_node;
+ pending->which = which;
+ pending->atCommit = false; /* delete if abort */
+ pending->next = pendingDeletes;
+ pendingDeletes = pending;
+
return fd;
}
/*
* smgrunlink() -- Unlink a relation.
*
- * The relation is removed from the store.
+ * The relation is removed from the store. Actually, we just remember
+ * that we want to do this at transaction commit.
*/
int
smgrunlink(int16 which, Relation reln)
{
- int status;
-
- if ((status = (*(smgrsw[which].smgr_unlink)) (reln)) == SM_FAIL)
- elog(ERROR, "cannot unlink %s: %m", RelationGetRelationName(reln));
+ PendingRelDelete *pending;
+
+ /* Make sure the file is closed */
+ if (reln->rd_fd >= 0)
+ smgrclose(which, reln);
+
+ /* Add the relation to the list of stuff to delete at commit */
+ pending = (PendingRelDelete *)
+ MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
+ pending->relnode = reln->rd_node;
+ pending->which = which;
+ pending->atCommit = true; /* delete if commit */
+ pending->next = pendingDeletes;
+ pendingDeletes = pending;
+
+ /*
+ * NOTE: if the relation was created in this transaction, it will now
+ * be present in the pending-delete list twice, once with atCommit true
+ * and once with atCommit false. Hence, it will be physically deleted
+ * at end of xact in either case (and the other entry will be ignored
+ * by smgrDoPendingDeletes, so no error will occur). We could instead
+ * remove the existing list entry and delete the physical file
+ * immediately, but for now I'll keep the logic simple.
+ */
- return status;
+ return SM_SUCCESS;
}
/*
@@ -193,17 +253,18 @@ smgrextend(int16 which, Relation reln, char *buffer)
/*
* smgropen() -- Open a relation using a particular storage manager.
*
- * Returns the fd for the open relation on success, aborts the
- * transaction on failure.
+ * Returns the fd for the open relation on success.
+ *
+ * On failure, returns -1 if failOK, else aborts the transaction.
*/
int
-smgropen(int16 which, Relation reln)
+smgropen(int16 which, Relation reln, bool failOK)
{
int fd;
- if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0 &&
- !reln->rd_unlinked)
- elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
+ if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
+ if (! failOK)
+ elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
return fd;
}
@@ -211,12 +272,6 @@ smgropen(int16 which, Relation reln)
/*
* smgrclose() -- Close a relation.
*
- * NOTE: underlying manager should allow case where relation is
- * already closed. Indeed relation may have been unlinked!
- * This is currently called only from RelationFlushRelation() when
- * the relation cache entry is about to be dropped; could be doing
- * simple relation cache clear, or finishing up DROP TABLE.
- *
* Returns SM_SUCCESS on success, aborts on failure.
*/
int
@@ -412,6 +467,41 @@ smgrtruncate(int16 which, Relation reln, int nblocks)
}
/*
+ * smgrDoPendingDeletes() -- take care of relation deletes at end of xact.
+ */
+int
+smgrDoPendingDeletes(bool isCommit)
+{
+ while (pendingDeletes != NULL)
+ {
+ PendingRelDelete *pending = pendingDeletes;
+
+ pendingDeletes = pending->next;
+ if (pending->atCommit == isCommit)
+ {
+ /*
+ * Get rid of any leftover buffers for the rel (shouldn't be
+ * any in the commit case, but there can be in the abort case).
+ */
+ DropRelFileNodeBuffers(pending->relnode);
+ /*
+ * And delete the physical files.
+ *
+ * Note: we treat deletion failure as a NOTICE, not an error,
+ * because we've already decided to commit or abort the current
+ * xact.
+ */
+ if ((*(smgrsw[pending->which].smgr_unlink)) (pending->relnode) == SM_FAIL)
+ elog(NOTICE, "cannot unlink %u/%u: %m",
+ pending->relnode.tblNode, pending->relnode.relNode);
+ }
+ pfree(pending);
+ }
+
+ return SM_SUCCESS;
+}
+
+/*
* smgrcommit(), smgrabort() -- Commit or abort changes made during the
* current transaction.
*/