home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / storage / smgr / md.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-11  |  9.5 KB  |  483 lines

  1. /*
  2.  *  md.c -- magnetic disk storage manager.
  3.  *
  4.  *    This code manages relations that reside on magnetic disk.
  5.  */
  6.  
  7. #include <sys/file.h>
  8.  
  9. #include "tmp/c.h"
  10. #include "tmp/postgres.h"
  11.  
  12. #include "machine.h"
  13. #include "storage/smgr.h"
  14. #include "storage/block.h"
  15. #include "storage/fd.h"
  16. #include "utils/rel.h"
  17.  
  18. RcsId("$Header: /private/postgres/src/storage/smgr/RCS/md.c,v 1.13 1992/08/13 22:53:01 mao Exp $");
  19.  
  20. /*
  21.  *  Need to keep track of open file descriptors under the magnetic disk
  22.  *  storage manager.
  23.  */
  24.  
  25. static int    Nfds = 100;    /* must be same as in storage/file/fd.c */
  26. static char    *Md_fdvec;
  27.  
  28. #define MDFD_CLEAN    (char) 0
  29. #define MDFD_DIRTY    (char) 1
  30.  
  31. /*
  32.  *  mdinit() -- Initialize private state for magnetic disk storage manager.
  33.  *
  34.  *    We keep a private table of all file descriptors.  Whenever we do
  35.  *    a write to one, we mark it dirty in our table.  Whenever we force
  36.  *    changes to disk, we mark the file descriptor clean.  At transaction
  37.  *    commit, we force changes to disk for all dirty file descriptors.
  38.  *    This routine allocates and initializes the table.
  39.  *
  40.  *    Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  41.  */
  42.  
  43. int
  44. mdinit()
  45. {
  46.     if ((Md_fdvec = (char *) malloc(Nfds)) == (char *) NULL)
  47.     return (SM_FAIL);
  48.  
  49.     (void) bzero(Md_fdvec, Nfds);
  50.  
  51.     return (SM_SUCCESS);
  52. }
  53.  
  54. int
  55. mdcreate(reln)
  56.     Relation reln;
  57. {
  58.     int fd;
  59.     int tmp;
  60.     char *path;
  61.     extern char *relpath();
  62.     extern bool IsBootstrapProcessingMode();
  63.  
  64.     path = relpath(&(reln->rd_rel->relname.data[0]));
  65.     fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
  66.  
  67.     /*
  68.      *  If the file already exists and is empty, we pretend that the
  69.      *  create succeeded.  During bootstrap processing, we skip that check,
  70.      *  because pg_time, pg_variable, and pg_log get created before their
  71.      *  .bki file entries are processed.
  72.      */
  73.  
  74.     if (fd < 0) {
  75.     if ((fd = FileNameOpenFile(path, O_RDWR, 0600)) >= 0) {
  76.         if (!IsBootstrapProcessingMode() &&
  77.         FileRead(fd, (char *) &tmp, sizeof(tmp)) != 0) {
  78.         FileClose(fd);
  79.         return (-1);
  80.         }
  81.     }
  82.     }
  83.  
  84.     if (fd >= Nfds)
  85.     if (_fdvec_ext(fd) == SM_FAIL)
  86.         return (-1);
  87.  
  88.     return (fd);
  89. }
  90.  
  91. /*
  92.  *  mdunlink() -- Unlink a relation.
  93.  */
  94.  
  95. int
  96. mdunlink(reln)
  97.     Relation reln;
  98. {
  99.     FileUnlink(RelationGetFile(reln));
  100.  
  101.     return (SM_SUCCESS);
  102. }
  103.  
  104. /*
  105.  *  mdextend() -- Add a block to the specified relation.
  106.  *
  107.  *    This routine returns SM_FAIL or SM_SUCCESS, with errno set as
  108.  *    appropriate.
  109.  */
  110.  
  111. int
  112. mdextend(reln, buffer)
  113.     Relation reln;
  114.     char *buffer;
  115. {
  116.     long pos;
  117.     File vfd;
  118.  
  119.     vfd = RelationGetFile(reln);
  120.  
  121.     if ((pos = FileSeek(vfd, 0L, L_XTND)) < 0)
  122.     return (SM_FAIL);
  123.  
  124.     if (FileWrite(vfd, buffer, BLCKSZ) != BLCKSZ)
  125.     return (SM_FAIL);
  126.  
  127.     /* remember that we did a write, so we can sync at xact commit */
  128.     Md_fdvec[vfd] = MDFD_DIRTY;
  129.  
  130.     return (SM_SUCCESS);
  131. }
  132.  
  133. /*
  134.  *  mdopen() -- Open the specified relation.
  135.  *
  136.  *    The magnetic disk storage manager uses one file descriptor per open
  137.  *    relation.  This routine returns the open file descriptor.
  138.  */
  139.  
  140. int
  141. mdopen(reln)
  142.     Relation reln;
  143. {
  144.     char *path;
  145.     int fd;
  146.     extern char *relpath();
  147.  
  148.     path = relpath(&(reln->rd_rel->relname.data[0]));
  149.  
  150.     fd = FileNameOpenFile(path, O_RDWR, 0600);
  151.  
  152.     /* this should only happen during bootstrap processing */
  153.     if (fd < 0)
  154.     fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
  155.  
  156.     if (fd >= Nfds)
  157.     if (_fdvec_ext(fd) == SM_FAIL)
  158.         return (-1);
  159.  
  160.     return (fd);
  161. }
  162.  
  163. /*
  164.  *  mdclose() -- Close the specified relation.
  165.  *
  166.  *    Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  167.  */
  168.  
  169. int
  170. mdclose(reln)
  171.     Relation reln;
  172. {
  173.     File vfd;
  174.     int status;
  175.  
  176.     /* maybe it's already closed... */
  177.     if ((vfd = RelationGetFile(reln)) < 0)
  178.     return (SM_SUCCESS);
  179.  
  180.     /*
  181.      *  Need to do it here.  We sync the file descriptor so that we don't
  182.      *  need to reopen it at transaction commit to force changes to disk.
  183.      */
  184.  
  185.     FileSync(vfd);
  186.     FileClose(vfd);
  187.  
  188.     /* mark this file descriptor as clean in our private table */
  189.     Md_fdvec[vfd] = MDFD_CLEAN;
  190.  
  191.     return (SM_SUCCESS);
  192. }
  193.  
  194. /*
  195.  *  mdread() -- Read the specified block from a relation.
  196.  *
  197.  *    Returns SM_SUCCESS or SM_FAIL.
  198.  */
  199.  
  200. int
  201. mdread(reln, blocknum, buffer)
  202.     Relation reln;
  203.     BlockNumber blocknum;
  204.     char *buffer;
  205. {
  206.     int status;
  207.     File vfd;
  208.     long seekpos;
  209.     int nbytes;
  210.  
  211.     if ((vfd = RelationGetFile(reln)) < 0) {
  212.     if ((vfd = mdopen(reln)) < 0)
  213.         return (SM_FAIL);
  214.     reln->rd_fd = vfd;
  215.     }
  216.  
  217.     seekpos = (long) (BLCKSZ * blocknum);
  218.     if (FileSeek(vfd, seekpos, L_SET) != seekpos) {
  219.     return (SM_FAIL);
  220.     }
  221.  
  222.     status = SM_SUCCESS;
  223.     if ((nbytes = FileRead(vfd, buffer, BLCKSZ)) != BLCKSZ) {
  224.     if (nbytes == 0) {
  225.         (void) bzero(buffer, BLCKSZ);
  226.     } else {
  227.         status = SM_FAIL;
  228.     }
  229.     }
  230.  
  231.     return (status);
  232. }
  233.  
  234. /*
  235.  *  mdwrite() -- Write the supplied block at the appropriate location.
  236.  *
  237.  *    Returns SM_SUCCESS or SM_FAIL.
  238.  */
  239.  
  240. int
  241. mdwrite(reln, blocknum, buffer)
  242.     Relation reln;
  243.     BlockNumber blocknum;
  244.     char *buffer;
  245. {
  246.     int status;
  247.     bool found;
  248.     File vfd;
  249.     long seekpos;
  250.  
  251.     found = true;
  252.     if ((vfd = RelationGetFile(reln)) < 0) {
  253.     found = false;
  254.     if ((vfd = mdopen(reln)) < 0)
  255.         return (SM_FAIL);
  256.     }
  257.  
  258.     seekpos = (long) (BLCKSZ * blocknum);
  259.     if (FileSeek(vfd, seekpos, L_SET) != seekpos) {
  260.     if (!found)
  261.         (void) FileClose(vfd);
  262.  
  263.     return (SM_FAIL);
  264.     }
  265.  
  266.     status = SM_SUCCESS;
  267.     if (FileWrite(vfd, buffer, BLCKSZ) != BLCKSZ)
  268.     status = SM_FAIL;
  269.  
  270.     /*
  271.      *  If we opened this file descriptor especially to write this one block,
  272.      *  force the change to disk and mark the descriptor as clean.  If we
  273.      *  had an open descriptor for the file already, mark it as dirty so
  274.      *  we'll flush it at commit time.
  275.      */
  276.  
  277.     if (!found) {
  278.     FileSync(vfd);
  279.     FileClose(vfd);
  280.     Md_fdvec[vfd] = MDFD_CLEAN;
  281.     } else {
  282.     Md_fdvec[vfd] = MDFD_DIRTY;
  283.     }
  284.  
  285.     return (status);
  286. }
  287.  
  288. /*
  289.  *  mdflush() -- Synchronously write a block to disk.
  290.  *
  291.  *    This is exactly like mdwrite(), but doesn't return until the file
  292.  *    system buffer cache has been flushed.
  293.  */
  294.  
  295. int
  296. mdflush(reln, blocknum, buffer)
  297.     Relation reln;
  298.     BlockNumber blocknum;
  299.     char *buffer;
  300. {
  301.     int status;
  302.     bool found;
  303.     File vfd;
  304.     long seekpos;
  305.  
  306.     found = true;
  307.     if ((vfd = RelationGetFile(reln)) < 0) {
  308.     found = false;
  309.     if ((vfd = mdopen(reln)) < 0)
  310.         return (SM_FAIL);
  311.     }
  312.  
  313.     seekpos = (long) (BLCKSZ * blocknum);
  314.     if (FileSeek(vfd, seekpos, L_SET) != seekpos) {
  315.     if (!found)
  316.         (void) FileClose(vfd);
  317.  
  318.     return (SM_FAIL);
  319.     }
  320.  
  321.     status = SM_SUCCESS;
  322.  
  323.     /* write and sync the block */
  324.     if (FileWrite(vfd, buffer, BLCKSZ) != BLCKSZ || FileSync(vfd) < 0)
  325.     status = SM_FAIL;
  326.  
  327.     /*
  328.      *  By here, the block is written and changes have been forced to stable
  329.      *  storage.  Mark the descriptor as clean until the next write, so we
  330.      *  don't sync it again unnecessarily at transaction commit.
  331.      */
  332.  
  333.     Md_fdvec[vfd] = MDFD_CLEAN;
  334.  
  335.     if (!found)
  336.     FileClose(vfd);
  337.  
  338.     return (status);
  339. }
  340.  
  341. /*
  342.  *  mdblindwrt() -- Write a block to disk blind.
  343.  *
  344.  *    We have to be able to do this using only the name and OID of
  345.  *    the database and relation in which the block belongs.  This
  346.  *    is a synchronous write.
  347.  */
  348.  
  349. int
  350. mdblindwrt(dbstr, relstr, dbid, relid, blkno, buffer)
  351.     char *dbstr;
  352.     char *relstr;
  353.     OID dbid;
  354.     OID relid;
  355.     BlockNumber blkno;
  356.     char *buffer;
  357. {
  358.     int fd;
  359.     long seekpos;
  360.     int status;
  361.     char path[64];
  362.  
  363.     /* construct the path to the file and open it */
  364.     sprintf(path, "../%s/%s", (dbid == (OID) 0 ? ".." : dbstr), relstr);
  365.     if ((fd = open(path, O_RDWR, 0600)) < 0)
  366.     return (SM_FAIL);
  367.  
  368.     /* seek to the right spot */
  369.     seekpos = (long) (BLCKSZ * blkno);
  370.     if (lseek(fd, seekpos, L_SET) != seekpos) {
  371.     (void) close(fd);
  372.     return (SM_FAIL);
  373.     }
  374.  
  375.     status = SM_SUCCESS;
  376.  
  377.     /* write and sync the block */
  378. #ifdef linux
  379.     if (write(fd, buffer, BLCKSZ) != BLCKSZ)
  380.     status = SM_FAIL;
  381. #else
  382.     if (write(fd, buffer, BLCKSZ) != BLCKSZ || fsync(fd) < 0)
  383.     status = SM_FAIL;
  384. #endif
  385.  
  386.     if (close(fd) < 0)
  387.     status = SM_FAIL;
  388.  
  389.     return (status);
  390. }
  391.  
  392. /*
  393.  *  mdnblocks() -- Get the number of blocks stored in a relation.
  394.  *
  395.  *    Returns # of blocks or -1 on error.
  396.  */
  397.  
  398. int
  399. mdnblocks(reln)
  400.     Relation reln;
  401. {
  402.     File vfd;
  403.  
  404.     vfd = RelationGetFile(reln);
  405.  
  406.     return (FileGetNumberOfBlocks(vfd));
  407. }
  408.  
  409. /*
  410.  *  mdcommit() -- Commit a transaction.
  411.  *
  412.  *    All changes to magnetic disk relations must be forced to stable
  413.  *    storage.  This routine makes a pass over the private table of
  414.  *    file descriptors.  Any descriptors to which we have done writes,
  415.  *    but not synced, are synced here.
  416.  *
  417.  *    Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  418.  */
  419.  
  420. int
  421. mdcommit()
  422. {
  423.     int i;
  424.  
  425.     for (i = 0; i < Nfds; i++) {
  426.     if (Md_fdvec[i] == MDFD_DIRTY) {
  427.         if (FileSync(i) < 0)
  428.         return (SM_FAIL);
  429.  
  430.         Md_fdvec[i] = MDFD_CLEAN;
  431.     }
  432.     }
  433.  
  434.     return (SM_SUCCESS);
  435. }
  436.  
  437. /*
  438.  *  mdabort() -- Abort a transaction.
  439.  *
  440.  *    Changes need not be forced to disk at transaction abort.  We mark
  441.  *    all file descriptors as clean here.  Always returns SM_SUCCESS.
  442.  */
  443.  
  444. int
  445. mdabort()
  446. {
  447.     bzero(Md_fdvec, Nfds * sizeof(int));
  448.     return (SM_SUCCESS);
  449. }
  450.  
  451. /*
  452.  *  _fdvec_ext() -- Extend the md file descriptor vector.
  453.  *
  454.  *    The file descriptor vector must be large enough to hold at least
  455.  *    'fd' entries.
  456.  */
  457.  
  458. int
  459. _fdvec_ext(fd)
  460.     int fd;
  461. {
  462.     char *nvec;
  463.     int orig;
  464.  
  465.     orig = Nfds;
  466.  
  467.     do
  468.     Nfds *= 2;
  469.     while (Nfds <= fd);
  470.  
  471.     if ((nvec = (char *) malloc(Nfds)) == (char *) NULL)
  472.     return (SM_FAIL);
  473.  
  474.     (void) bzero(nvec, Nfds);
  475.     (void) bcopy(Md_fdvec, nvec, orig);
  476.  
  477.     free(Md_fdvec);
  478.  
  479.     Md_fdvec = nvec;
  480.  
  481.     return (SM_SUCCESS);
  482. }
  483.