diff options
Diffstat (limited to 'src/backend/storage/smgr/smgr.c')
-rw-r--r-- | src/backend/storage/smgr/smgr.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c new file mode 100644 index 00000000000..426c3d93480 --- /dev/null +++ b/src/backend/storage/smgr/smgr.c @@ -0,0 +1,371 @@ +/*------------------------------------------------------------------------- + * + * 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.1.1.1 1996/07/09 06:21:59 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <string.h> +#include "postgres.h" + +#include "machine.h" +#include "storage/ipc.h" +#include "storage/smgr.h" +#include "storage/block.h" +#include "utils/rel.h" +#include "utils/elog.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)(); + 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, + mdread, mdwrite, mdflush, mdblindwrt, mdnblocks, mdcommit, mdabort }, + +#ifdef MAIN_MEMORY + /* main memory */ + { mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose, + mmread, mmwrite, mmflush, mmblindwrt, mmnblocks, 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; + extern char *smgrout(); + + 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; + extern char *smgrout(); + + 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", + NAMEDATALEN, &(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", + NAMEDATALEN, &(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", + NAMEDATALEN, &(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", + NAMEDATALEN, &(reln->rd_rel->relname.data[0])); + + return (fd); +} + +/* + * smgrclose() -- Close a relation. + * + * 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", + NAMEDATALEN, &(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, NAMEDATALEN, &(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, NAMEDATALEN, &(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, NAMEDATALEN, &(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", + NAMEDATALEN, &(reln->rd_rel->relname.data[0])); + + return (nblocks); +} + +/* + * smgrcommit(), smgrabort() -- Commit or abort changes made during the + * current transaction. + */ +int +smgrcommit() +{ + int i; + extern char *smgrout(); + + 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; + extern char *smgrout(); + + 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]); +} |