diff -cr --exclude=CVS 01trivial/src/backend/access/transam/xact.c 02smgr/src/backend/access/transam/xact.c *** 01trivial/src/backend/access/transam/xact.c 2004-01-15 23:34:42.000000000 -0300 --- 02smgr/src/backend/access/transam/xact.c 2004-01-19 19:37:54.000000000 -0300 *************** *** 865,870 **** --- 865,875 ---- DeferredTriggerBeginXact(); /* + * Initialize the smgr subsystem + */ + PendingDeletesBeginXact(); + + /* * done with start processing, set current transaction state to "in * progress" */ diff -cr --exclude=CVS 01trivial/src/backend/storage/smgr/smgr.c 02smgr/src/backend/storage/smgr/smgr.c *** 01trivial/src/backend/storage/smgr/smgr.c 2004-01-15 23:33:55.000000000 -0300 --- 02smgr/src/backend/storage/smgr/smgr.c 2004-01-19 19:37:54.000000000 -0300 *************** *** 97,105 **** * 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 --- 97,104 ---- * 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 TopTransactionContext, so the items will ! * automatically disappear when the transaction ends. */ typedef struct PendingRelDelete *************** *** 108,118 **** int16 which; /* which storage manager? */ bool isTemp; /* is it a temporary relation? */ 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 --- 107,118 ---- int16 which; /* which storage manager? */ bool isTemp; /* is it a temporary relation? */ bool atCommit; /* T=delete at commit; F=delete at abort */ } PendingRelDelete; ! static List *pendingDeletes; + static void smgrDeleteItem(PendingRelDelete *pending); + static void addPendingDelete(int16 which, Relation reln, bool atCommit); /* * smgrinit(), smgrshutdown() -- Initialize or shut down all storage *************** *** 168,174 **** smgrcreate(int16 which, Relation reln) { int fd; - PendingRelDelete *pending; if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0) ereport(ERROR, --- 168,173 ---- *************** *** 177,190 **** 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->isTemp = reln->rd_istemp; ! pending->atCommit = false; /* delete if abort */ ! pending->next = pendingDeletes; ! pendingDeletes = pending; return fd; } --- 176,182 ---- RelationGetRelationName(reln)))); /* Add the relation to the list of stuff to delete at abort */ ! addPendingDelete(which, reln, false); return fd; } *************** *** 198,218 **** int smgrunlink(int16 which, Relation 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->isTemp = reln->rd_istemp; ! pending->atCommit = true; /* delete if commit */ ! pending->next = pendingDeletes; ! pendingDeletes = pending; /* * NOTE: if the relation was created in this transaction, it will now --- 190,202 ---- int smgrunlink(int16 which, Relation reln) { /* 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 */ ! addPendingDelete(which, reln, true); /* * NOTE: if the relation was created in this transaction, it will now *************** *** 444,496 **** } /* * 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, pending->isTemp); ! ! /* ! * Tell the free space map to forget this relation. It won't ! * be accessed any more anyway, but we may as well recycle the ! * map space quickly. ! */ ! FreeSpaceMapForgetRel(&pending->relnode); ! ! /* ! * And delete the physical files. ! * ! * Note: we treat deletion failure as a WARNING, 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) ! ereport(WARNING, ! (errcode_for_file_access(), ! errmsg("could not unlink %u/%u: %m", ! pending->relnode.tblNode, ! pending->relnode.relNode))); ! } ! pfree(pending); } return SM_SUCCESS; } /* * smgrcommit() -- Prepare to commit changes made during the current * transaction. * --- 428,519 ---- } /* + * Add a relation to delete at transaction end. + */ + void + addPendingDelete(int16 which, Relation reln, bool atCommit) + { + MemoryContext old_cxt = MemoryContextSwitchTo(TopTransactionContext); + PendingRelDelete *pending = (PendingRelDelete *) palloc(sizeof(PendingRelDelete)); + + pending->relnode = reln->rd_node; + pending->which = which; + pending->isTemp = reln->rd_istemp; + pending->atCommit = atCommit; + pendingDeletes = lcons(pending, pendingDeletes); + + MemoryContextSwitchTo(old_cxt); + } + + /* + * Delete a pending relation. + */ + void + smgrDeleteItem(PendingRelDelete *pending) + { + /* + * 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, pending->isTemp); + + /* + * Tell the free space map to forget this relation. It won't + * be accessed any more anyway, but we may as well recycle the + * map space quickly. + */ + FreeSpaceMapForgetRel(&pending->relnode); + + /* + * And delete the physical files. + * + * Note: we treat deletion failure as a WARNING, 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) + ereport(WARNING, + (errcode_for_file_access(), + errmsg("could not unlink %u/%u: %m", + pending->relnode.tblNode, + pending->relnode.relNode))); + } + + /* * smgrDoPendingDeletes() -- Take care of relation deletes at end of xact. */ int smgrDoPendingDeletes(bool isCommit) { ! List *p; ! foreach (p, pendingDeletes) { ! PendingRelDelete *pending = (PendingRelDelete *)lfirst(p); if (pending->atCommit == isCommit) ! smgrDeleteItem(pending); ! ! /* ! * The structs will be freed at the end of the transaction, ! * no need to free them individually. ! */ } + pendingDeletes = NIL; return SM_SUCCESS; } /* + * Initializes the smgr pending deletes queue. + */ + void + PendingDeletesBeginXact(void) + { + pendingDeletes = NIL; + } + + /* * smgrcommit() -- Prepare to commit changes made during the current * transaction. * diff -cr --exclude=CVS 01trivial/src/include/storage/smgr.h 02smgr/src/include/storage/smgr.h *** 01trivial/src/include/storage/smgr.h 2004-01-15 23:34:12.000000000 -0300 --- 02smgr/src/include/storage/smgr.h 2004-01-19 19:37:54.000000000 -0300 *************** *** 43,48 **** --- 43,50 ---- extern BlockNumber smgrtruncate(int16 which, Relation reln, BlockNumber nblocks); extern int smgrDoPendingDeletes(bool isCommit); + extern void PendingDeletesBeginXact(void); + extern int smgrcommit(void); extern int smgrabort(void); extern int smgrsync(void);