postgresql/src/backend/storage/smgr/smgr.c

399 lines
9.3 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* smgr.c--
* public interface routines to storage manager switch.
*
* All file system operations in POSTGRES dispatch through these
* routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.7 1997/08/18 20:53:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "storage/ipc.h"
#include "storage/block.h"
#include "storage/smgr.h"
#include "utils/rel.h"
#include "utils/palloc.h"
typedef struct f_smgr {
int (*smgr_init)(); /* may be NULL */
int (*smgr_shutdown)(); /* may be NULL */
int (*smgr_create)();
int (*smgr_unlink)();
int (*smgr_extend)();
int (*smgr_open)();
int (*smgr_close)();
int (*smgr_read)();
int (*smgr_write)();
int (*smgr_flush)();
int (*smgr_blindwrt)();
int (*smgr_nblocks)();
1996-11-27 08:25:52 +01:00
int (*smgr_truncate)();
int (*smgr_commit)(); /* may be NULL */
int (*smgr_abort)(); /* may be NULL */
} f_smgr;
/*
* 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).
*/
static f_smgr smgrsw[] = {
/* magnetic disk */
{ mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
1996-11-27 08:25:52 +01:00
mdread, mdwrite, mdflush, mdblindwrt, mdnblocks, mdtruncate,
mdcommit, mdabort },
#ifdef MAIN_MEMORY
/* main memory */
{ mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
1996-11-27 08:25:52 +01:00
mmread, mmwrite, mmflush, mmblindwrt, mmnblocks, NULL,
mmcommit, mmabort },
#endif /* MAIN_MEMORY */
};
/*
* 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.
*/
static bool smgrwo[] = {
false, /* magnetic disk */
#ifdef MAIN_MEMORY
false, /* main memory*/
#endif /* MAIN_MEMORY */
};
static int NSmgr = lengthof(smgrsw);
/*
* smgrinit(), smgrshutdown() -- Initialize or shut down all storage
* managers.
*
*/
int
smgrinit()
{
int i;
for (i = 0; i < NSmgr; i++) {
if (smgrsw[i].smgr_init) {
if ((*(smgrsw[i].smgr_init))() == SM_FAIL)
elog(FATAL, "initialization failed on %s", smgrout(i));
}
}
/* register the shutdown proc */
on_exitpg(smgrshutdown, 0);
return (SM_SUCCESS);
}
void
smgrshutdown(int dummy)
{
int i;
for (i = 0; i < NSmgr; i++) {
if (smgrsw[i].smgr_shutdown) {
if ((*(smgrsw[i].smgr_shutdown))() == SM_FAIL)
elog(FATAL, "shutdown failed on %s", smgrout(i));
}
}
}
/*
* smgrcreate() -- Create a new relation.
*
* This routine takes a reldesc, creates the relation on the appropriate
* device, and returns a file descriptor for it.
*/
int
smgrcreate(int16 which, Relation reln)
{
int fd;
if ((fd = (*(smgrsw[which].smgr_create))(reln)) < 0)
elog(WARN, "cannot open %s",
&(reln->rd_rel->relname.data[0]));
return (fd);
}
/*
* smgrunlink() -- Unlink a relation.
*
* The relation is removed from the store.
*/
int
smgrunlink(int16 which, Relation reln)
{
int status;
if ((status = (*(smgrsw[which].smgr_unlink))(reln)) == SM_FAIL)
elog(WARN, "cannot unlink %s",
&(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrextend() -- Add a new block to a file.
*
* Returns SM_SUCCESS on success; aborts the current transaction on
* failure.
*/
int
smgrextend(int16 which, Relation reln, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_extend))(reln, buffer);
if (status == SM_FAIL)
elog(WARN, "%s: cannot extend",
&(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgropen() -- Open a relation using a particular storage manager.
*
* Returns the fd for the open relation on success, aborts the
* transaction on failure.
*/
int
smgropen(int16 which, Relation reln)
{
int fd;
if ((fd = (*(smgrsw[which].smgr_open))(reln)) < 0)
elog(WARN, "cannot open %s",
&(reln->rd_rel->relname.data[0]));
return (fd);
}
/*
* smgrclose() -- Close a relation.
*
* NOTE: mdclose frees fd vector! It may be re-used for other relation!
* reln should be flushed from cache after closing !..
* Currently, smgrclose is calling by
* relcache.c:RelationPurgeLocalRelation() only.
* It would be nice to have smgrfree(), but because of
* smgrclose is called from single place... - vadim 05/22/97
*
* Returns SM_SUCCESS on success, aborts on failure.
*/
int
smgrclose(int16 which, Relation reln)
{
if ((*(smgrsw[which].smgr_close))(reln) == SM_FAIL)
elog(WARN, "cannot close %s",
&(reln->rd_rel->relname.data[0]));
return (SM_SUCCESS);
}
/*
* smgrread() -- read a particular block from a relation into the supplied
* buffer.
*
* 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.
*/
int
smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_read))(reln, blocknum, buffer);
if (status == SM_FAIL)
elog(WARN, "cannot read block %d of %s",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrwrite() -- Write the supplied buffer out.
*
* This is not a synchronous write -- the interface for that is
* smgrflush(). The buffer is written out via the appropriate
* storage manager. This routine returns SM_SUCCESS or aborts
* the current transaction.
*/
int
smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_write))(reln, blocknum, buffer);
if (status == SM_FAIL)
elog(WARN, "cannot write block %d of %s",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrflush() -- A synchronous smgrwrite().
*/
int
smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
int status;
status = (*(smgrsw[which].smgr_flush))(reln, blocknum, buffer);
if (status == SM_FAIL)
elog(WARN, "cannot flush block %d of %s to stable store",
blocknum, &(reln->rd_rel->relname.data[0]));
return (status);
}
/*
* smgrblindwrt() -- Write a page out blind.
*
* 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
* buffer belongs. Every storage manager must be able to force
* this page down to stable storage in this circumstance.
*/
int
smgrblindwrt(int16 which,
char *dbname,
char *relname,
Oid dbid,
Oid relid,
BlockNumber blkno,
char *buffer)
{
char *dbstr;
char *relstr;
int status;
dbstr = pstrdup(dbname);
relstr = pstrdup(relname);
status = (*(smgrsw[which].smgr_blindwrt))(dbstr, relstr, dbid, relid,
blkno, buffer);
if (status == SM_FAIL)
elog(WARN, "cannot write block %d of %s [%s] blind",
blkno, relstr, dbstr);
pfree(dbstr);
pfree(relstr);
return (status);
}
/*
* smgrnblocks() -- Calculate the number of POSTGRES blocks in the
* supplied relation.
*
* Returns the number of blocks on success, aborts the current
* transaction on failure.
*/
int
smgrnblocks(int16 which, Relation reln)
{
int nblocks;
if ((nblocks = (*(smgrsw[which].smgr_nblocks))(reln)) < 0)
elog(WARN, "cannot count blocks for %s",
&(reln->rd_rel->relname.data[0]));
return (nblocks);
}
1996-11-27 08:25:52 +01:00
/*
* smgrtruncate() -- Truncate supplied relation to a specified number
* of blocks
*
* Returns the number of blocks on success, aborts the current
* transaction on failure.
*/
int
smgrtruncate(int16 which, Relation reln, int nblocks)
{
int newblks;
newblks = nblocks;
if (smgrsw[which].smgr_truncate)
{
if ((newblks = (*(smgrsw[which].smgr_truncate))(reln, nblocks)) < 0)
elog(WARN, "cannot truncate %s to %d blocks",
&(reln->rd_rel->relname.data[0]), nblocks);
1996-11-27 08:25:52 +01:00
}
return (newblks);
}
/*
* smgrcommit(), smgrabort() -- Commit or abort changes made during the
* current transaction.
*/
int
smgrcommit()
{
int i;
for (i = 0; i < NSmgr; i++) {
if (smgrsw[i].smgr_commit) {
if ((*(smgrsw[i].smgr_commit))() == SM_FAIL)
elog(FATAL, "transaction commit failed on %s", smgrout(i));
}
}
return (SM_SUCCESS);
}
int
smgrabort()
{
int i;
for (i = 0; i < NSmgr; i++) {
if (smgrsw[i].smgr_abort) {
if ((*(smgrsw[i].smgr_abort))() == SM_FAIL)
elog(FATAL, "transaction abort failed on %s", smgrout(i));
}
}
return (SM_SUCCESS);
}
bool
smgriswo(int16 smgrno)
{
if (smgrno < 0 || smgrno >= NSmgr)
elog(WARN, "illegal storage manager number %d", smgrno);
return (smgrwo[smgrno]);
}