1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* smgr.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* public interface routines to storage manager switch.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* All file system operations in POSTGRES dispatch through these
|
|
|
|
* routines.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2003-08-04 04:40:20 +02:00
|
|
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2003-11-29 20:52:15 +01:00
|
|
|
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.66 2003/11/29 19:51:57 pgsql Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
#include "storage/bufmgr.h"
|
2001-06-28 01:31:40 +02:00
|
|
|
#include "storage/freespace.h"
|
2001-09-29 06:02:27 +02:00
|
|
|
#include "storage/ipc.h"
|
1996-11-03 06:08:01 +01:00
|
|
|
#include "storage/smgr.h"
|
2000-11-08 23:10:03 +01:00
|
|
|
#include "utils/memutils.h"
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-10-02 23:45:33 +02:00
|
|
|
static void smgrshutdown(void);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
typedef struct f_smgr
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
int (*smgr_init) (void); /* may be NULL */
|
|
|
|
int (*smgr_shutdown) (void); /* may be NULL */
|
2000-04-09 06:43:20 +02:00
|
|
|
int (*smgr_create) (Relation reln);
|
2000-11-08 23:10:03 +01:00
|
|
|
int (*smgr_unlink) (RelFileNode rnode);
|
2001-05-10 22:38:49 +02:00
|
|
|
int (*smgr_extend) (Relation reln, BlockNumber blocknum,
|
2001-10-25 07:50:21 +02:00
|
|
|
char *buffer);
|
2000-04-09 06:43:20 +02:00
|
|
|
int (*smgr_open) (Relation reln);
|
|
|
|
int (*smgr_close) (Relation reln);
|
|
|
|
int (*smgr_read) (Relation reln, BlockNumber blocknum,
|
2001-10-25 07:50:21 +02:00
|
|
|
char *buffer);
|
2000-04-09 06:43:20 +02:00
|
|
|
int (*smgr_write) (Relation reln, BlockNumber blocknum,
|
2001-10-25 07:50:21 +02:00
|
|
|
char *buffer);
|
2001-03-22 05:01:46 +01:00
|
|
|
int (*smgr_blindwrt) (RelFileNode rnode, BlockNumber blkno,
|
2002-08-06 04:36:35 +02:00
|
|
|
char *buffer);
|
2001-10-25 07:50:21 +02:00
|
|
|
BlockNumber (*smgr_nblocks) (Relation reln);
|
|
|
|
BlockNumber (*smgr_truncate) (Relation reln, BlockNumber nblocks);
|
2000-04-12 19:17:23 +02:00
|
|
|
int (*smgr_commit) (void); /* may be NULL */
|
|
|
|
int (*smgr_abort) (void); /* may be NULL */
|
2000-10-28 18:21:00 +02:00
|
|
|
int (*smgr_sync) (void);
|
1997-09-08 23:56:23 +02:00
|
|
|
} f_smgr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* The weird placement of commas in this init block is to keep the compiler
|
|
|
|
* happy, regardless of what storage managers we have (or don't have).
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static f_smgr smgrsw[] = {
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* magnetic disk */
|
|
|
|
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
|
2002-08-06 04:36:35 +02:00
|
|
|
mdread, mdwrite, mdblindwrt,
|
2001-03-22 05:01:46 +01:00
|
|
|
mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
|
2000-11-08 23:10:03 +01:00
|
|
|
},
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
/* main memory */
|
|
|
|
{mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
|
2002-08-06 04:36:35 +02:00
|
|
|
mmread, mmwrite, mmblindwrt,
|
2002-09-04 22:31:48 +02:00
|
|
|
mmnblocks, NULL, mmcommit, mmabort, NULL},
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This array records which storage managers are write-once, and which
|
|
|
|
* support overwrite. A 'true' entry means that the storage manager is
|
|
|
|
* write-once. In the best of all possible worlds, there would be no
|
|
|
|
* write-once storage managers.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
|
1998-10-08 20:30:52 +02:00
|
|
|
#ifdef NOT_USED
|
1997-09-08 04:41:22 +02:00
|
|
|
static bool smgrwo[] = {
|
1997-09-07 07:04:48 +02:00
|
|
|
false, /* magnetic disk */
|
1998-06-23 17:35:48 +02:00
|
|
|
#ifdef STABLE_MEMORY_STORAGE
|
1997-09-07 07:04:48 +02:00
|
|
|
false, /* main memory */
|
1998-06-23 17:35:48 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
};
|
1998-10-08 20:30:52 +02:00
|
|
|
#endif
|
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
static int NSmgr = lengthof(smgrsw);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
|
|
|
* 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
|
2001-03-22 05:01:46 +01:00
|
|
|
* transaction is aborted. Conversely, a deletion request is NOT
|
2000-11-08 23:10:03 +01:00
|
|
|
* 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 */
|
2001-03-22 05:01:46 +01:00
|
|
|
int16 which; /* which storage manager? */
|
2002-08-06 04:36:35 +02:00
|
|
|
bool isTemp; /* is it a temporary relation? */
|
2001-03-22 05:01:46 +01:00
|
|
|
bool atCommit; /* T=delete at commit; F=delete at abort */
|
|
|
|
struct PendingRelDelete *next; /* linked-list link */
|
2000-11-08 23:10:03 +01:00
|
|
|
} PendingRelDelete;
|
|
|
|
|
2001-03-22 05:01:46 +01:00
|
|
|
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
|
2000-11-08 23:10:03 +01:00
|
|
|
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrinit(), smgrshutdown() -- Initialize or shut down all storage
|
|
|
|
* managers.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
int
|
2002-08-06 04:36:35 +02:00
|
|
|
smgrinit(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NSmgr; i++)
|
|
|
|
{
|
|
|
|
if (smgrsw[i].smgr_init)
|
|
|
|
{
|
|
|
|
if ((*(smgrsw[i].smgr_init)) () == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
elog(FATAL, "smgr initialization failed on %s: %m",
|
2000-06-05 09:29:25 +02:00
|
|
|
DatumGetCString(DirectFunctionCall1(smgrout,
|
2001-03-22 05:01:46 +01:00
|
|
|
Int16GetDatum(i))));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/* register the shutdown proc */
|
2000-10-02 21:42:56 +02:00
|
|
|
on_proc_exit(smgrshutdown, 0);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return SM_SUCCESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1997-08-19 23:40:56 +02:00
|
|
|
static void
|
2000-10-02 23:45:33 +02:00
|
|
|
smgrshutdown(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NSmgr; i++)
|
|
|
|
{
|
|
|
|
if (smgrsw[i].smgr_shutdown)
|
|
|
|
{
|
|
|
|
if ((*(smgrsw[i].smgr_shutdown)) () == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
elog(FATAL, "smgr shutdown failed on %s: %m",
|
2000-06-05 09:29:25 +02:00
|
|
|
DatumGetCString(DirectFunctionCall1(smgrout,
|
2001-03-22 05:01:46 +01:00
|
|
|
Int16GetDatum(i))));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrcreate() -- Create a new relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This routine takes a reldesc, creates the relation on the appropriate
|
|
|
|
* device, and returns a file descriptor for it.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
smgrcreate(int16 which, Relation reln)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int fd;
|
2000-11-08 23:10:03 +01:00
|
|
|
PendingRelDelete *pending;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not create relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln))));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/* 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;
|
2002-08-06 04:36:35 +02:00
|
|
|
pending->isTemp = reln->rd_istemp;
|
2000-11-08 23:10:03 +01:00
|
|
|
pending->atCommit = false; /* delete if abort */
|
|
|
|
pending->next = pendingDeletes;
|
|
|
|
pendingDeletes = pending;
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return fd;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrunlink() -- Unlink a relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-11-08 23:10:03 +01:00
|
|
|
* The relation is removed from the store. Actually, we just remember
|
|
|
|
* that we want to do this at transaction commit.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
smgrunlink(int16 which, Relation reln)
|
|
|
|
{
|
2000-11-08 23:10:03 +01:00
|
|
|
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;
|
2002-08-06 04:36:35 +02:00
|
|
|
pending->isTemp = reln->rd_istemp;
|
2000-11-08 23:10:03 +01:00
|
|
|
pending->atCommit = true; /* delete if commit */
|
|
|
|
pending->next = pendingDeletes;
|
|
|
|
pendingDeletes = pending;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: if the relation was created in this transaction, it will now
|
2001-03-22 05:01:46 +01:00
|
|
|
* 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
|
2000-11-08 23:10:03 +01:00
|
|
|
* immediately, but for now I'll keep the logic simple.
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
return SM_SUCCESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrextend() -- Add a new block to a file.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2001-05-10 22:38:49 +02:00
|
|
|
* The semantics are basically the same as smgrwrite(): write at the
|
|
|
|
* specified position. However, we are expecting to extend the
|
|
|
|
* relation (ie, blocknum is the current EOF), and so in case of
|
|
|
|
* failure we clean up by truncating.
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Returns SM_SUCCESS on success; aborts the current transaction on
|
|
|
|
* failure.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2001-05-10 22:38:49 +02:00
|
|
|
smgrextend(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int status;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-05-10 22:38:49 +02:00
|
|
|
status = (*(smgrsw[which].smgr_extend)) (reln, blocknum, buffer);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (status == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not extend relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln)),
|
|
|
|
errhint("Check free disk space.")));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return status;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgropen() -- Open a relation using a particular storage manager.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-11-08 23:10:03 +01:00
|
|
|
* Returns the fd for the open relation on success.
|
|
|
|
*
|
|
|
|
* On failure, returns -1 if failOK, else aborts the transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2000-11-08 23:10:03 +01:00
|
|
|
smgropen(int16 which, Relation reln, bool failOK)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int fd;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-11-13 10:06:36 +01:00
|
|
|
if (reln->rd_rel->relkind == RELKIND_VIEW)
|
|
|
|
return -1;
|
2002-08-15 18:36:08 +02:00
|
|
|
if (reln->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
|
|
|
|
return -1;
|
2000-11-08 23:10:03 +01:00
|
|
|
if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
|
2001-03-22 05:01:46 +01:00
|
|
|
if (!failOK)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not open file \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln))));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return fd;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrclose() -- Close a relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Returns SM_SUCCESS on success, aborts on failure.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
smgrclose(int16 which, Relation reln)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if ((*(smgrsw[which].smgr_close)) (reln) == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not close relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln))));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return SM_SUCCESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrread() -- read a particular block from a relation into the supplied
|
|
|
|
* buffer.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* This routine is called from the buffer manager in order to
|
|
|
|
* instantiate pages in the shared buffer cache. All storage managers
|
|
|
|
* return pages in the format that POSTGRES expects. This routine
|
|
|
|
* dispatches the read. On success, it returns SM_SUCCESS. On failure,
|
|
|
|
* the current transaction is aborted.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int status;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
status = (*(smgrsw[which].smgr_read)) (reln, blocknum, buffer);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (status == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not read block %d of relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
blocknum, RelationGetRelationName(reln))));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return status;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrwrite() -- Write the supplied buffer out.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-08-06 04:36:35 +02:00
|
|
|
* This is not a synchronous write -- the block is not necessarily
|
|
|
|
* on disk at return, only dumped out to the kernel.
|
|
|
|
*
|
|
|
|
* The buffer is written out via the appropriate
|
1997-09-07 07:04:48 +02:00
|
|
|
* storage manager. This routine returns SM_SUCCESS or aborts
|
|
|
|
* the current transaction.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int status;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
status = (*(smgrsw[which].smgr_write)) (reln, blocknum, buffer);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (status == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not write block %d of relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
blocknum, RelationGetRelationName(reln))));
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return status;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrblindwrt() -- Write a page out blind.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* In some cases, we may find a page in the buffer cache that we
|
|
|
|
* can't make a reldesc for. This happens, for example, when we
|
|
|
|
* want to reuse a dirty page that was written by a transaction
|
|
|
|
* that has not yet committed, which created a new relation. In
|
|
|
|
* this case, the buffer manager will call smgrblindwrt() with
|
|
|
|
* the name and OID of the database and the relation to which the
|
2002-08-06 04:36:35 +02:00
|
|
|
* buffer belongs. Every storage manager must be able to write
|
|
|
|
* this page out to stable storage in this circumstance.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-10-16 16:52:28 +02:00
|
|
|
int
|
|
|
|
smgrblindwrt(int16 which,
|
|
|
|
RelFileNode rnode,
|
|
|
|
BlockNumber blkno,
|
2002-08-06 04:36:35 +02:00
|
|
|
char *buffer)
|
2000-10-16 16:52:28 +02:00
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
2002-08-06 04:36:35 +02:00
|
|
|
status = (*(smgrsw[which].smgr_blindwrt)) (rnode, blkno, buffer);
|
2000-10-16 16:52:28 +02:00
|
|
|
|
|
|
|
if (status == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not write block %d of %u/%u blind: %m",
|
|
|
|
blkno, rnode.tblNode, rnode.relNode)));
|
2000-10-16 16:52:28 +02:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrnblocks() -- Calculate the number of POSTGRES blocks in the
|
|
|
|
* supplied relation.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Returns the number of blocks on success, aborts the current
|
|
|
|
* transaction on failure.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2001-06-28 01:31:40 +02:00
|
|
|
BlockNumber
|
1996-07-09 08:22:35 +02:00
|
|
|
smgrnblocks(int16 which, Relation reln)
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
BlockNumber nblocks;
|
2001-06-29 23:08:25 +02:00
|
|
|
|
|
|
|
nblocks = (*(smgrsw[which].smgr_nblocks)) (reln);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-06-29 23:08:25 +02:00
|
|
|
/*
|
|
|
|
* NOTE: if a relation ever did grow to 2^32-1 blocks, this code would
|
|
|
|
* fail --- but that's a good thing, because it would stop us from
|
|
|
|
* extending the rel another block and having a block whose number
|
|
|
|
* actually is InvalidBlockNumber.
|
|
|
|
*/
|
|
|
|
if (nblocks == InvalidBlockNumber)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not count blocks of relation \"%s\": %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln))));
|
2001-06-29 23:08:25 +02:00
|
|
|
|
|
|
|
return nblocks;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1996-11-27 08:25:52 +01:00
|
|
|
/*
|
1997-09-07 07:04:48 +02:00
|
|
|
* smgrtruncate() -- Truncate supplied relation to a specified number
|
|
|
|
* of blocks
|
1996-11-27 08:25:52 +01:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Returns the number of blocks on success, aborts the current
|
|
|
|
* transaction on failure.
|
1996-11-27 08:25:52 +01:00
|
|
|
*/
|
2001-06-28 01:31:40 +02:00
|
|
|
BlockNumber
|
|
|
|
smgrtruncate(int16 which, Relation reln, BlockNumber nblocks)
|
1996-11-27 08:25:52 +01:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
BlockNumber newblks;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
newblks = nblocks;
|
|
|
|
if (smgrsw[which].smgr_truncate)
|
|
|
|
{
|
2001-06-28 01:31:40 +02:00
|
|
|
/*
|
2001-07-02 22:50:46 +02:00
|
|
|
* Tell the free space map to forget anything it may have stored
|
2001-10-25 07:50:21 +02:00
|
|
|
* for the about-to-be-deleted blocks. We want to be sure it
|
|
|
|
* won't return bogus block numbers later on.
|
2001-06-28 01:31:40 +02:00
|
|
|
*/
|
2003-03-04 22:51:22 +01:00
|
|
|
FreeSpaceMapTruncateRel(&reln->rd_node, nblocks);
|
2001-06-28 01:31:40 +02:00
|
|
|
|
|
|
|
newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks);
|
|
|
|
if (newblks == InvalidBlockNumber)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode_for_file_access(),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("could not truncate relation \"%s\" to %u blocks: %m",
|
2003-07-25 00:04:15 +02:00
|
|
|
RelationGetRelationName(reln), nblocks)));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return newblks;
|
1996-11-27 08:25:52 +01:00
|
|
|
}
|
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
|
|
|
* 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
|
2001-03-22 05:01:46 +01:00
|
|
|
* any in the commit case, but there can be in the abort
|
|
|
|
* case).
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
2002-08-06 04:36:35 +02:00
|
|
|
DropRelFileNodeBuffers(pending->relnode, pending->isTemp);
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2001-06-28 01:31:40 +02:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2000-11-08 23:10:03 +01:00
|
|
|
/*
|
|
|
|
* And delete the physical files.
|
|
|
|
*
|
2002-03-06 07:10:59 +01:00
|
|
|
* Note: we treat deletion failure as a WARNING, not an error,
|
2001-03-22 05:01:46 +01:00
|
|
|
* because we've already decided to commit or abort the
|
|
|
|
* current xact.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
if ((*(smgrsw[pending->which].smgr_unlink)) (pending->relnode) == SM_FAIL)
|
2003-07-25 00:04:15 +02:00
|
|
|
ereport(WARNING,
|
|
|
|
(errcode_for_file_access(),
|
|
|
|
errmsg("could not unlink %u/%u: %m",
|
|
|
|
pending->relnode.tblNode,
|
|
|
|
pending->relnode.relNode)));
|
2000-11-08 23:10:03 +01:00
|
|
|
}
|
|
|
|
pfree(pending);
|
|
|
|
}
|
|
|
|
|
|
|
|
return SM_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2002-08-06 04:36:35 +02:00
|
|
|
* smgrcommit() -- Prepare to commit changes made during the current
|
|
|
|
* transaction.
|
|
|
|
*
|
|
|
|
* This is called before we actually commit.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2002-08-06 04:36:35 +02:00
|
|
|
smgrcommit(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NSmgr; i++)
|
|
|
|
{
|
|
|
|
if (smgrsw[i].smgr_commit)
|
|
|
|
{
|
|
|
|
if ((*(smgrsw[i].smgr_commit)) () == SM_FAIL)
|
2000-06-20 01:37:08 +02:00
|
|
|
elog(FATAL, "transaction commit failed on %s: %m",
|
2000-06-05 09:29:25 +02:00
|
|
|
DatumGetCString(DirectFunctionCall1(smgrout,
|
2001-03-22 05:01:46 +01:00
|
|
|
Int16GetDatum(i))));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return SM_SUCCESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-08-06 04:36:35 +02:00
|
|
|
/*
|
|
|
|
* smgrabort() -- Abort changes made during the current transaction.
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
int
|
2002-08-06 04:36:35 +02:00
|
|
|
smgrabort(void)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NSmgr; i++)
|
|
|
|
{
|
|
|
|
if (smgrsw[i].smgr_abort)
|
|
|
|
{
|
|
|
|
if ((*(smgrsw[i].smgr_abort)) () == SM_FAIL)
|
2000-06-20 01:37:08 +02:00
|
|
|
elog(FATAL, "transaction abort failed on %s: %m",
|
2000-06-05 09:29:25 +02:00
|
|
|
DatumGetCString(DirectFunctionCall1(smgrout,
|
2001-03-22 05:01:46 +01:00
|
|
|
Int16GetDatum(i))));
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return SM_SUCCESS;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-08-06 04:36:35 +02:00
|
|
|
/*
|
|
|
|
* Sync files to disk at checkpoint time.
|
|
|
|
*/
|
2000-10-28 18:21:00 +02:00
|
|
|
int
|
2002-08-06 04:36:35 +02:00
|
|
|
smgrsync(void)
|
2000-10-28 18:21:00 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NSmgr; i++)
|
|
|
|
{
|
|
|
|
if (smgrsw[i].smgr_sync)
|
|
|
|
{
|
|
|
|
if ((*(smgrsw[i].smgr_sync)) () == SM_FAIL)
|
Commit to match discussed elog() changes. Only update is that LOG is
now just below FATAL in server_min_messages. Added more text to
highlight ordering difference between it and client_min_messages.
---------------------------------------------------------------------------
REALLYFATAL => PANIC
STOP => PANIC
New INFO level the prints to client by default
New LOG level the prints to server log by default
Cause VACUUM information to print only to the client
NOTICE => INFO where purely information messages are sent
DEBUG => LOG for purely server status messages
DEBUG removed, kept as backward compatible
DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1 added
DebugLvl removed in favor of new DEBUG[1-5] symbols
New server_min_messages GUC parameter with values:
DEBUG[5-1], INFO, NOTICE, ERROR, LOG, FATAL, PANIC
New client_min_messages GUC parameter with values:
DEBUG[5-1], LOG, INFO, NOTICE, ERROR, FATAL, PANIC
Server startup now logged with LOG instead of DEBUG
Remove debug_level GUC parameter
elog() numbers now start at 10
Add test to print error message if older elog() values are passed to elog()
Bootstrap mode now has a -d that requires an argument, like postmaster
2002-03-02 22:39:36 +01:00
|
|
|
elog(PANIC, "storage sync failed on %s: %m",
|
2000-10-28 18:21:00 +02:00
|
|
|
DatumGetCString(DirectFunctionCall1(smgrout,
|
2001-03-22 05:01:46 +01:00
|
|
|
Int16GetDatum(i))));
|
2000-10-28 18:21:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SM_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1998-10-08 20:30:52 +02:00
|
|
|
#ifdef NOT_USED
|
1996-07-09 08:22:35 +02:00
|
|
|
bool
|
|
|
|
smgriswo(int16 smgrno)
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
if (smgrno < 0 || smgrno >= NSmgr)
|
2003-07-25 00:04:15 +02:00
|
|
|
elog(ERROR, "invalid storage manager id: %d", smgrno);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return smgrwo[smgrno];
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1998-10-08 20:30:52 +02:00
|
|
|
#endif
|
2000-10-21 17:43:36 +02:00
|
|
|
|
|
|
|
void
|
|
|
|
smgr_redo(XLogRecPtr lsn, XLogRecord *record)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
smgr_undo(XLogRecPtr lsn, XLogRecord *record)
|
|
|
|
{
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2000-10-21 17:43:36 +02:00
|
|
|
void
|
2001-03-22 05:01:46 +01:00
|
|
|
smgr_desc(char *buf, uint8 xl_info, char *rec)
|
2000-10-21 17:43:36 +02:00
|
|
|
{
|
|
|
|
}
|