md.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:25k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * md.c
  4.  *   This code manages relations that reside on magnetic disk.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.46.2.2 1999/09/06 20:00:15 tgl Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <unistd.h>
  15. #include <fcntl.h>
  16. #include <sys/file.h>
  17. #include "postgres.h"
  18. #include "catalog/catalog.h"
  19. #include "miscadmin.h"
  20. #include "storage/smgr.h"
  21. #undef DIAGNOSTIC
  22. /*
  23.  * The magnetic disk storage manager keeps track of open file descriptors
  24.  * in its own descriptor pool.  This happens for two reasons. First, at
  25.  * transaction boundaries, we walk the list of descriptors and flush
  26.  * anything that we've dirtied in the current transaction.  Second, we want
  27.  * to support relations larger than the OS' file size limit (often 2GBytes).
  28.  * In order to do that, we break relations up into chunks of < 2GBytes
  29.  * and store one chunk in each of several files that represent the relation.
  30.  * See the BLCKSZ and RELSEG_SIZE configuration constants in include/config.h.
  31.  *
  32.  * The file descriptor stored in the relation cache (see RelationGetFile())
  33.  * is actually an index into the Md_fdvec array.  -1 indicates not open.
  34.  *
  35.  * When a relation is broken into multiple chunks, only the first chunk
  36.  * has its own entry in the Md_fdvec array; the remaining chunks have
  37.  * palloc'd MdfdVec objects that are chained onto the first chunk via the
  38.  * mdfd_chain links.  All chunks except the last MUST have size exactly
  39.  * equal to RELSEG_SIZE blocks --- see mdnblocks() and mdtruncate().
  40.  */
  41. typedef struct _MdfdVec
  42. {
  43. int mdfd_vfd; /* fd number in vfd pool */
  44. uint16 mdfd_flags; /* clean, dirty, free */
  45. int mdfd_lstbcnt; /* most recent block count */
  46. int mdfd_nextFree; /* next free vector */
  47. #ifndef LET_OS_MANAGE_FILESIZE
  48. struct _MdfdVec *mdfd_chain;/* for large relations */
  49. #endif
  50. } MdfdVec;
  51. static int Nfds = 100; /* initial/current size of Md_fdvec array */
  52. static MdfdVec *Md_fdvec = (MdfdVec *) NULL;
  53. static int Md_Free = -1; /* head of freelist of unused fdvec entries */
  54. static int CurFd = 0; /* first never-used fdvec index */
  55. static MemoryContext MdCxt; /* context for all my allocations */
  56. #define MDFD_DIRTY (uint16) 0x01
  57. #define MDFD_FREE (uint16) 0x02
  58. /* routines declared here */
  59. static int _mdfd_getrelnfd(Relation reln);
  60. static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
  61. static MdfdVec *_mdfd_getseg(Relation reln, int blkno);
  62. static int _fdvec_alloc(void);
  63. static void _fdvec_free(int);
  64. static BlockNumber _mdnblocks(File file, Size blcksz);
  65. /*
  66.  * mdinit() -- Initialize private state for magnetic disk storage manager.
  67.  *
  68.  * We keep a private table of all file descriptors.  Whenever we do
  69.  * a write to one, we mark it dirty in our table. Whenever we force
  70.  * changes to disk, we mark the file descriptor clean.  At transaction
  71.  * commit, we force changes to disk for all dirty file descriptors.
  72.  * This routine allocates and initializes the table.
  73.  *
  74.  * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  75.  */
  76. int
  77. mdinit()
  78. {
  79. MemoryContext oldcxt;
  80. int i;
  81. MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
  82. if (MdCxt == (MemoryContext) NULL)
  83. return SM_FAIL;
  84. oldcxt = MemoryContextSwitchTo(MdCxt);
  85. Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
  86. MemoryContextSwitchTo(oldcxt);
  87. if (Md_fdvec == (MdfdVec *) NULL)
  88. return SM_FAIL;
  89. MemSet(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
  90. /* Set free list */
  91. for (i = 0; i < Nfds; i++)
  92. {
  93. Md_fdvec[i].mdfd_nextFree = i + 1;
  94. Md_fdvec[i].mdfd_flags = MDFD_FREE;
  95. }
  96. Md_Free = 0;
  97. Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
  98. return SM_SUCCESS;
  99. }
  100. int
  101. mdcreate(Relation reln)
  102. {
  103. int fd,
  104. vfd;
  105. char    *path;
  106. path = relpath(reln->rd_rel->relname.data);
  107. #ifndef __CYGWIN32__
  108. fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL, 0600);
  109. #else
  110. fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
  111. #endif
  112. /*
  113.  * If the file already exists and is empty, we pretend that the create
  114.  * succeeded.  During bootstrap processing, we skip that check,
  115.  * because pg_time, pg_variable, and pg_log get created before their
  116.  * .bki file entries are processed.
  117.  *
  118.  * As the result of this pretence it was possible to have in pg_class > 1
  119.  * records with the same relname. Actually, it should be fixed in
  120.  * upper levels, too, but... - vadim 05/06/97
  121.  */
  122. if (fd < 0)
  123. {
  124. if (!IsBootstrapProcessingMode())
  125. return -1;
  126. #ifndef __CYGWIN32__
  127. fd = FileNameOpenFile(path, O_RDWR, 0600); /* Bootstrap */
  128. #else
  129. fd = FileNameOpenFile(path, O_RDWR | O_BINARY, 0600); /* Bootstrap */
  130. #endif
  131. if (fd < 0)
  132. return -1;
  133. }
  134. vfd = _fdvec_alloc();
  135. if (vfd < 0)
  136. return -1;
  137. Md_fdvec[vfd].mdfd_vfd = fd;
  138. Md_fdvec[vfd].mdfd_flags = (uint16) 0;
  139. #ifndef LET_OS_MANAGE_FILESIZE
  140. Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
  141. #endif
  142. Md_fdvec[vfd].mdfd_lstbcnt = 0;
  143. return vfd;
  144. }
  145. /*
  146.  * mdunlink() -- Unlink a relation.
  147.  */
  148. int
  149. mdunlink(Relation reln)
  150. {
  151. int nblocks;
  152. int fd;
  153. MdfdVec    *v;
  154. MemoryContext oldcxt;
  155. /*
  156.  * Force all segments of the relation to be opened, so that we
  157.  * won't miss deleting any of them.
  158.  */
  159. nblocks = mdnblocks(reln);
  160. /*
  161.  * Clean out the mdfd vector, letting fd.c unlink the physical files.
  162.  *
  163.  * NOTE: We truncate the file(s) before deleting 'em, because if other
  164.  * backends are holding the files open, the unlink will fail on some
  165.  * platforms (think Microsoft).  Better a zero-size file gets left around
  166.  * than a big file.  Those other backends will be forced to close the
  167.  * relation by cache invalidation, but that probably hasn't happened yet.
  168.  */
  169. fd = RelationGetFile(reln);
  170. if (fd < 0) /* should not happen */
  171. elog(ERROR, "mdunlink: mdnblocks didn't open relation");
  172. Md_fdvec[fd].mdfd_flags = (uint16) 0;
  173. oldcxt = MemoryContextSwitchTo(MdCxt);
  174. #ifndef LET_OS_MANAGE_FILESIZE
  175. for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
  176. {
  177. MdfdVec    *ov = v;
  178. FileTruncate(v->mdfd_vfd, 0);
  179. FileUnlink(v->mdfd_vfd);
  180. v = v->mdfd_chain;
  181. if (ov != &Md_fdvec[fd])
  182. pfree(ov);
  183. }
  184. Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
  185. #else
  186. v = &Md_fdvec[fd];
  187. FileTruncate(v->mdfd_vfd, 0);
  188. FileUnlink(v->mdfd_vfd);
  189. #endif
  190. MemoryContextSwitchTo(oldcxt);
  191. _fdvec_free(fd);
  192. /* be sure to mark relation closed */
  193. reln->rd_fd = -1;
  194. return SM_SUCCESS;
  195. }
  196. /*
  197.  * mdextend() -- Add a block to the specified relation.
  198.  *
  199.  * This routine returns SM_FAIL or SM_SUCCESS, with errno set as
  200.  * appropriate.
  201.  */
  202. int
  203. mdextend(Relation reln, char *buffer)
  204. {
  205. long pos;
  206. int nblocks;
  207. MdfdVec    *v;
  208. nblocks = mdnblocks(reln);
  209. v = _mdfd_getseg(reln, nblocks);
  210. if ((pos = FileSeek(v->mdfd_vfd, 0L, SEEK_END)) < 0)
  211. return SM_FAIL;
  212. if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
  213. return SM_FAIL;
  214. /* remember that we did a write, so we can sync at xact commit */
  215. v->mdfd_flags |= MDFD_DIRTY;
  216. /* try to keep the last block count current, though it's just a hint */
  217. #ifndef LET_OS_MANAGE_FILESIZE
  218. if ((v->mdfd_lstbcnt = (++nblocks % RELSEG_SIZE)) == 0)
  219. v->mdfd_lstbcnt = RELSEG_SIZE;
  220. #ifdef DIAGNOSTIC
  221. if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE
  222. || v->mdfd_lstbcnt > RELSEG_SIZE)
  223. elog(FATAL, "segment too big!");
  224. #endif
  225. #else
  226. v->mdfd_lstbcnt = ++nblocks;
  227. #endif
  228. return SM_SUCCESS;
  229. }
  230. /*
  231.  * mdopen() -- Open the specified relation.
  232.  */
  233. int
  234. mdopen(Relation reln)
  235. {
  236. char    *path;
  237. int fd;
  238. int vfd;
  239. path = relpath(reln->rd_rel->relname.data);
  240. #ifndef __CYGWIN32__
  241. fd = FileNameOpenFile(path, O_RDWR, 0600);
  242. #else
  243. fd = FileNameOpenFile(path, O_RDWR | O_BINARY, 0600);
  244. #endif
  245. if (fd < 0)
  246. {
  247. /* in bootstrap mode, accept mdopen as substitute for mdcreate */
  248. if (IsBootstrapProcessingMode())
  249. {
  250. #ifndef __CYGWIN32__
  251. fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL, 0600);
  252. #else
  253. fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
  254. #endif
  255. }
  256. if (fd < 0)
  257. {
  258. elog(ERROR, "mdopen: couldn't open %s: %m", path);
  259. return -1;
  260. }
  261. }
  262. vfd = _fdvec_alloc();
  263. if (vfd < 0)
  264. return -1;
  265. Md_fdvec[vfd].mdfd_vfd = fd;
  266. Md_fdvec[vfd].mdfd_flags = (uint16) 0;
  267. Md_fdvec[vfd].mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
  268. #ifndef LET_OS_MANAGE_FILESIZE
  269. Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
  270. #ifdef DIAGNOSTIC
  271. if (Md_fdvec[vfd].mdfd_lstbcnt > RELSEG_SIZE)
  272. elog(FATAL, "segment too big on relopen!");
  273. #endif
  274. #endif
  275. return vfd;
  276. }
  277. /*
  278.  * mdclose() -- Close the specified relation, if it isn't closed already.
  279.  *
  280.  * AND FREE fd vector! It may be re-used for other relation!
  281.  * reln should be flushed from cache after closing !..
  282.  *
  283.  * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  284.  */
  285. int
  286. mdclose(Relation reln)
  287. {
  288. int fd;
  289. MdfdVec    *v;
  290. MemoryContext oldcxt;
  291. fd = RelationGetFile(reln);
  292. if (fd < 0)
  293. return SM_SUCCESS; /* already closed, so no work */
  294. oldcxt = MemoryContextSwitchTo(MdCxt);
  295. #ifndef LET_OS_MANAGE_FILESIZE
  296. for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
  297. {
  298. MdfdVec    *ov = v;
  299. /* if not closed already */
  300. if (v->mdfd_vfd >= 0)
  301. {
  302. /*
  303.  * We sync the file descriptor so that we don't need to reopen
  304.  * it at transaction commit to force changes to disk.
  305.  */
  306. FileSync(v->mdfd_vfd);
  307. FileClose(v->mdfd_vfd);
  308. /* mark this file descriptor as clean in our private table */
  309. v->mdfd_flags &= ~MDFD_DIRTY;
  310. }
  311. /* Now free vector */
  312. v = v->mdfd_chain;
  313. if (ov != &Md_fdvec[fd])
  314. pfree(ov);
  315. }
  316. Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
  317. #else
  318. v = &Md_fdvec[fd];
  319. if (v != (MdfdVec *) NULL)
  320. {
  321. if (v->mdfd_vfd >= 0)
  322. {
  323. /*
  324.  * We sync the file descriptor so that we don't need to reopen
  325.  * it at transaction commit to force changes to disk.
  326.  */
  327. FileSync(v->mdfd_vfd);
  328. FileClose(v->mdfd_vfd);
  329. /* mark this file descriptor as clean in our private table */
  330. v->mdfd_flags &= ~MDFD_DIRTY;
  331. }
  332. }
  333. #endif
  334. MemoryContextSwitchTo(oldcxt);
  335. _fdvec_free(fd);
  336. /* be sure to mark relation closed */
  337. reln->rd_fd = -1;
  338. return SM_SUCCESS;
  339. }
  340. /*
  341.  * mdread() -- Read the specified block from a relation.
  342.  *
  343.  * Returns SM_SUCCESS or SM_FAIL.
  344.  */
  345. int
  346. mdread(Relation reln, BlockNumber blocknum, char *buffer)
  347. {
  348. int status;
  349. long seekpos;
  350. int nbytes;
  351. MdfdVec    *v;
  352. v = _mdfd_getseg(reln, blocknum);
  353. #ifndef LET_OS_MANAGE_FILESIZE
  354. seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
  355. #ifdef DIAGNOSTIC
  356. if (seekpos >= BLCKSZ * RELSEG_SIZE)
  357. elog(FATAL, "seekpos too big!");
  358. #endif
  359. #else
  360. seekpos = (long) (BLCKSZ * (blocknum));
  361. #endif
  362. if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
  363. return SM_FAIL;
  364. status = SM_SUCCESS;
  365. if ((nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
  366. {
  367. if (nbytes == 0)
  368. MemSet(buffer, 0, BLCKSZ);
  369. else
  370. status = SM_FAIL;
  371. }
  372. return status;
  373. }
  374. /*
  375.  * mdwrite() -- Write the supplied block at the appropriate location.
  376.  *
  377.  * Returns SM_SUCCESS or SM_FAIL.
  378.  */
  379. int
  380. mdwrite(Relation reln, BlockNumber blocknum, char *buffer)
  381. {
  382. int status;
  383. long seekpos;
  384. MdfdVec    *v;
  385. v = _mdfd_getseg(reln, blocknum);
  386. #ifndef LET_OS_MANAGE_FILESIZE
  387. seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
  388. #ifdef DIAGNOSTIC
  389. if (seekpos >= BLCKSZ * RELSEG_SIZE)
  390. elog(FATAL, "seekpos too big!");
  391. #endif
  392. #else
  393. seekpos = (long) (BLCKSZ * (blocknum));
  394. #endif
  395. if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
  396. return SM_FAIL;
  397. status = SM_SUCCESS;
  398. if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
  399. status = SM_FAIL;
  400. v->mdfd_flags |= MDFD_DIRTY;
  401. return status;
  402. }
  403. /*
  404.  * mdflush() -- Synchronously write a block to disk.
  405.  *
  406.  * This is exactly like mdwrite(), but doesn't return until the file
  407.  * system buffer cache has been flushed.
  408.  */
  409. int
  410. mdflush(Relation reln, BlockNumber blocknum, char *buffer)
  411. {
  412. int status;
  413. long seekpos;
  414. MdfdVec    *v;
  415. v = _mdfd_getseg(reln, blocknum);
  416. #ifndef LET_OS_MANAGE_FILESIZE
  417. seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
  418. #ifdef DIAGNOSTIC
  419. if (seekpos >= BLCKSZ * RELSEG_SIZE)
  420. elog(FATAL, "seekpos too big!");
  421. #endif
  422. #else
  423. seekpos = (long) (BLCKSZ * (blocknum));
  424. #endif
  425. if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
  426. return SM_FAIL;
  427. /* write and sync the block */
  428. status = SM_SUCCESS;
  429. if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ
  430. || FileSync(v->mdfd_vfd) < 0)
  431. status = SM_FAIL;
  432. /*
  433.  * By here, the block is written and changes have been forced to
  434.  * stable storage. Mark the descriptor as clean until the next write,
  435.  * so we don't sync it again unnecessarily at transaction commit.
  436.  */
  437. v->mdfd_flags &= ~MDFD_DIRTY;
  438. return status;
  439. }
  440. /*
  441.  * mdblindwrt() -- Write a block to disk blind.
  442.  *
  443.  * We have to be able to do this using only the name and OID of
  444.  * the database and relation in which the block belongs.  This
  445.  * is a synchronous write.
  446.  */
  447. int
  448. mdblindwrt(char *dbstr,
  449.    char *relstr,
  450.    Oid dbid,
  451.    Oid relid,
  452.    BlockNumber blkno,
  453.    char *buffer)
  454. {
  455. int fd;
  456. int segno;
  457. long seekpos;
  458. int status;
  459. char    *path;
  460. #ifndef LET_OS_MANAGE_FILESIZE
  461. int nchars;
  462. /* be sure we have enough space for the '.segno', if any */
  463. segno = blkno / RELSEG_SIZE;
  464. if (segno > 0)
  465. nchars = 10;
  466. else
  467. nchars = 0;
  468. /* construct the path to the file and open it */
  469. /* system table? then put in system area... */
  470. if (dbid == (Oid) 0)
  471. {
  472. path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2 + nchars);
  473. if (segno == 0)
  474. sprintf(path, "%s/%s", DataDir, relstr);
  475. else
  476. sprintf(path, "%s/%s.%d", DataDir, relstr, segno);
  477. }
  478. /* user table? then put in user database area... */
  479. else if (dbid == MyDatabaseId)
  480. {
  481. extern char *DatabasePath;
  482. path = (char *) palloc(strlen(DatabasePath) + 2 * sizeof(NameData) + 2 + nchars);
  483. if (segno == 0)
  484. sprintf(path, "%s%c%s", DatabasePath, SEP_CHAR, relstr);
  485. else
  486. sprintf(path, "%s%c%s.%d", DatabasePath, SEP_CHAR, relstr, segno);
  487. }
  488. else
  489. /* this is work arround only !!! */
  490. {
  491. char dbpath[MAXPGPATH + 1];
  492. int4 owner;
  493. Oid id;
  494. char    *tmpPath;
  495. int tmpEncoding;
  496. GetRawDatabaseInfo(dbstr, &owner, &id, dbpath, &tmpEncoding);
  497. if (id != dbid)
  498. elog(FATAL, "mdblindwrt: oid of db %s is not %u", dbstr, dbid);
  499. tmpPath = ExpandDatabasePath(dbpath);
  500. if (tmpPath == NULL)
  501. elog(FATAL, "mdblindwrt: can't expand path for db %s", dbstr);
  502. path = (char *) palloc(strlen(tmpPath) + 2 * sizeof(NameData) + 2 + nchars);
  503. if (segno == 0)
  504. sprintf(path, "%s%c%s", tmpPath, SEP_CHAR, relstr);
  505. else
  506. sprintf(path, "%s%c%s.%d", tmpPath, SEP_CHAR, relstr, segno);
  507. pfree(tmpPath);
  508. }
  509. #else
  510. /* construct the path to the file and open it */
  511. /* system table? then put in system area... */
  512. if (dbid == (Oid) 0)
  513. {
  514. path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2);
  515. sprintf(path, "%s/%s", DataDir, relstr);
  516. }
  517. /* user table? then put in user database area... */
  518. else if (dbid == MyDatabaseId)
  519. {
  520. extern char *DatabasePath;
  521. path = (char *) palloc(strlen(DatabasePath) + 2 * sizeof(NameData) + 2);
  522. sprintf(path, "%s%c%s", DatabasePath, SEP_CHAR, relstr);
  523. }
  524. else
  525. /* this is work arround only !!! */
  526. {
  527. char dbpath[MAXPGPATH + 1];
  528. int4 owner;
  529. Oid id;
  530. char    *tmpPath;
  531. int tmpEncoding;
  532. GetRawDatabaseInfo(dbstr, &owner, &id, dbpath, &tmpEncoding);
  533. if (id != dbid)
  534. elog(FATAL, "mdblindwrt: oid of db %s is not %u", dbstr, dbid);
  535. tmpPath = ExpandDatabasePath(dbpath);
  536. if (tmpPath == NULL)
  537. elog(FATAL, "mdblindwrt: can't expand path for db %s", dbstr);
  538. path = (char *) palloc(strlen(tmpPath) + 2 * sizeof(NameData) + 2);
  539. sprintf(path, "%s%c%s", tmpPath, SEP_CHAR, relstr);
  540. pfree(tmpPath);
  541. }
  542. #endif
  543. #ifndef __CYGWIN32__
  544. if ((fd = open(path, O_RDWR, 0600)) < 0)
  545. #else
  546. if ((fd = open(path, O_RDWR | O_BINARY, 0600)) < 0)
  547. #endif
  548. return SM_FAIL;
  549. /* seek to the right spot */
  550. #ifndef LET_OS_MANAGE_FILESIZE
  551. seekpos = (long) (BLCKSZ * (blkno % RELSEG_SIZE));
  552. #else
  553. seekpos = (long) (BLCKSZ * (blkno));
  554. #endif
  555. if (lseek(fd, seekpos, SEEK_SET) != seekpos)
  556. {
  557. close(fd);
  558. return SM_FAIL;
  559. }
  560. status = SM_SUCCESS;
  561. /* write and sync the block */
  562. if (write(fd, buffer, BLCKSZ) != BLCKSZ || (pg_fsync(fd) < 0))
  563. status = SM_FAIL;
  564. if (close(fd) < 0)
  565. status = SM_FAIL;
  566. pfree(path);
  567. return status;
  568. }
  569. /*
  570.  * mdnblocks() -- Get the number of blocks stored in a relation.
  571.  *
  572.  * Important side effect: all segments of the relation are opened
  573.  * and added to the mdfd_chain list.  If this routine has not been
  574.  * called, then only segments up to the last one actually touched
  575.  * are present in the chain...
  576.  *
  577.  * Returns # of blocks, elog's on error.
  578.  */
  579. int
  580. mdnblocks(Relation reln)
  581. {
  582. int fd;
  583. MdfdVec    *v;
  584. #ifndef LET_OS_MANAGE_FILESIZE
  585. int nblocks;
  586. int segno;
  587. #endif
  588. fd = _mdfd_getrelnfd(reln);
  589. v = &Md_fdvec[fd];
  590. #ifndef LET_OS_MANAGE_FILESIZE
  591. segno = 0;
  592. for (;;)
  593. {
  594. nblocks = _mdnblocks(v->mdfd_vfd, BLCKSZ);
  595. if (nblocks > RELSEG_SIZE)
  596. elog(FATAL, "segment too big in mdnblocks!");
  597. v->mdfd_lstbcnt = nblocks;
  598. if (nblocks == RELSEG_SIZE)
  599. {
  600. segno++;
  601. if (v->mdfd_chain == (MdfdVec *) NULL)
  602. {
  603. v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
  604. if (v->mdfd_chain == (MdfdVec *) NULL)
  605. elog(ERROR, "cannot count blocks for %s -- open failed",
  606.  RelationGetRelationName(reln));
  607. }
  608. v = v->mdfd_chain;
  609. }
  610. else
  611. return (segno * RELSEG_SIZE) + nblocks;
  612. }
  613. #else
  614. return _mdnblocks(v->mdfd_vfd, BLCKSZ);
  615. #endif
  616. }
  617. /*
  618.  * mdtruncate() -- Truncate relation to specified number of blocks.
  619.  *
  620.  * Returns # of blocks or -1 on error.
  621.  */
  622. int
  623. mdtruncate(Relation reln, int nblocks)
  624. {
  625. int curnblk;
  626. int fd;
  627. MdfdVec    *v;
  628. #ifndef LET_OS_MANAGE_FILESIZE
  629. MemoryContext oldcxt;
  630. int priorblocks;
  631. #endif
  632. /* NOTE: mdnblocks makes sure we have opened all existing segments,
  633.  * so that truncate/delete loop will get them all!
  634.  */
  635. curnblk = mdnblocks(reln);
  636. if (nblocks < 0 || nblocks > curnblk)
  637. return -1; /* bogus request */
  638. if (nblocks == curnblk)
  639. return nblocks; /* no work */
  640. fd = _mdfd_getrelnfd(reln);
  641. v = &Md_fdvec[fd];
  642. #ifndef LET_OS_MANAGE_FILESIZE
  643. oldcxt = MemoryContextSwitchTo(MdCxt);
  644. priorblocks = 0;
  645. while (v != (MdfdVec *) NULL)
  646. {
  647. MdfdVec    *ov = v;
  648. if (priorblocks > nblocks)
  649. {
  650. /* This segment is no longer wanted at all (and has already been
  651.  * unlinked from the mdfd_chain).
  652.  * We truncate the file before deleting it because if other
  653.  * backends are holding the file open, the unlink will fail on
  654.  * some platforms.  Better a zero-size file gets left around than
  655.  * a big file...
  656.  */
  657. FileTruncate(v->mdfd_vfd, 0);
  658. /* In 6.5, it is not safe to unlink apparently-unused segments,
  659.  * because another backend could store tuples in one of those
  660.  * segments before it notices the shared-cache-invalidation
  661.  * message that would warn it to re-open the file.  So, don't
  662.  * unlink 'em, just truncate 'em.  This is fixed properly for 6.6
  663.  * but back-patching the changes was judged too risky.
  664.  */
  665. #if 0
  666. FileUnlink(v->mdfd_vfd);
  667. #endif
  668. v = v->mdfd_chain;
  669. Assert(ov != &Md_fdvec[fd]); /* we never drop the 1st segment */
  670. pfree(ov);
  671. }
  672. else if (priorblocks + RELSEG_SIZE > nblocks)
  673. {
  674. /* This is the last segment we want to keep.
  675.  * Truncate the file to the right length, and clear chain link
  676.  * that points to any remaining segments (which we shall zap).
  677.  * NOTE: if nblocks is exactly a multiple K of RELSEG_SIZE,
  678.  * we will truncate the K+1st segment to 0 length but keep it.
  679.  * This is mainly so that the right thing happens if nblocks=0.
  680.  */
  681. int lastsegblocks = nblocks - priorblocks;
  682. if (FileTruncate(v->mdfd_vfd, lastsegblocks * BLCKSZ) < 0)
  683. return -1;
  684. v->mdfd_lstbcnt = lastsegblocks;
  685. v = v->mdfd_chain;
  686. ov->mdfd_chain = (MdfdVec *) NULL;
  687. }
  688. else
  689. {
  690. /* We still need this segment and 0 or more blocks beyond it,
  691.  * so nothing to do here.
  692.  */
  693. v = v->mdfd_chain;
  694. }
  695. priorblocks += RELSEG_SIZE;
  696. }
  697. MemoryContextSwitchTo(oldcxt);
  698. #else
  699. if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
  700. return -1;
  701. v->mdfd_lstbcnt = nblocks;
  702. #endif
  703. return nblocks;
  704. } /* mdtruncate */
  705. /*
  706.  * mdcommit() -- Commit a transaction.
  707.  *
  708.  * All changes to magnetic disk relations must be forced to stable
  709.  * storage.  This routine makes a pass over the private table of
  710.  * file descriptors.  Any descriptors to which we have done writes,
  711.  * but not synced, are synced here.
  712.  *
  713.  * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
  714.  */
  715. int
  716. mdcommit()
  717. {
  718. int i;
  719. MdfdVec    *v;
  720. for (i = 0; i < CurFd; i++)
  721. {
  722. #ifndef LET_OS_MANAGE_FILESIZE
  723. for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain)
  724. #else
  725. v = &Md_fdvec[i];
  726. if (v != (MdfdVec *) NULL)
  727. #endif
  728. {
  729. if (v->mdfd_flags & MDFD_DIRTY)
  730. {
  731. if (FileSync(v->mdfd_vfd) < 0)
  732. return SM_FAIL;
  733. v->mdfd_flags &= ~MDFD_DIRTY;
  734. }
  735. }
  736. }
  737. return SM_SUCCESS;
  738. }
  739. /*
  740.  * mdabort() -- Abort a transaction.
  741.  *
  742.  * Changes need not be forced to disk at transaction abort.  We mark
  743.  * all file descriptors as clean here.  Always returns SM_SUCCESS.
  744.  */
  745. int
  746. mdabort()
  747. {
  748. int i;
  749. MdfdVec    *v;
  750. for (i = 0; i < CurFd; i++)
  751. {
  752. #ifndef LET_OS_MANAGE_FILESIZE
  753. for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain)
  754. v->mdfd_flags &= ~MDFD_DIRTY;
  755. #else
  756. v = &Md_fdvec[i];
  757. v->mdfd_flags &= ~MDFD_DIRTY;
  758. #endif
  759. }
  760. return SM_SUCCESS;
  761. }
  762. /*
  763.  * _fdvec_alloc () -- grab a free (or new) md file descriptor vector.
  764.  *
  765.  */
  766. static
  767. int
  768. _fdvec_alloc()
  769. {
  770. MdfdVec    *nvec;
  771. int fdvec,
  772. i;
  773. MemoryContext oldcxt;
  774. if (Md_Free >= 0) /* get from free list */
  775. {
  776. fdvec = Md_Free;
  777. Md_Free = Md_fdvec[fdvec].mdfd_nextFree;
  778. Assert(Md_fdvec[fdvec].mdfd_flags == MDFD_FREE);
  779. Md_fdvec[fdvec].mdfd_flags = 0;
  780. if (fdvec >= CurFd)
  781. {
  782. Assert(fdvec == CurFd);
  783. CurFd++;
  784. }
  785. return fdvec;
  786. }
  787. /* Must allocate more room */
  788. if (Nfds != CurFd)
  789. elog(FATAL, "_fdvec_alloc error");
  790. Nfds *= 2;
  791. oldcxt = MemoryContextSwitchTo(MdCxt);
  792. nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
  793. MemSet(nvec, 0, Nfds * sizeof(MdfdVec));
  794. memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
  795. pfree(Md_fdvec);
  796. MemoryContextSwitchTo(oldcxt);
  797. Md_fdvec = nvec;
  798. /* Set new free list */
  799. for (i = CurFd; i < Nfds; i++)
  800. {
  801. Md_fdvec[i].mdfd_nextFree = i + 1;
  802. Md_fdvec[i].mdfd_flags = MDFD_FREE;
  803. }
  804. Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
  805. Md_Free = CurFd + 1;
  806. fdvec = CurFd;
  807. CurFd++;
  808. Md_fdvec[fdvec].mdfd_flags = 0;
  809. return fdvec;
  810. }
  811. /*
  812.  * _fdvec_free () -- free md file descriptor vector.
  813.  *
  814.  */
  815. static
  816. void
  817. _fdvec_free(int fdvec)
  818. {
  819. Assert(Md_Free < 0 || Md_fdvec[Md_Free].mdfd_flags == MDFD_FREE);
  820. Assert(Md_fdvec[fdvec].mdfd_flags != MDFD_FREE);
  821. Md_fdvec[fdvec].mdfd_nextFree = Md_Free;
  822. Md_fdvec[fdvec].mdfd_flags = MDFD_FREE;
  823. Md_Free = fdvec;
  824. }
  825. static MdfdVec *
  826. _mdfd_openseg(Relation reln, int segno, int oflags)
  827. {
  828. MemoryContext oldcxt;
  829. MdfdVec    *v;
  830. int fd;
  831. bool dofree;
  832. char    *path,
  833.    *fullpath;
  834. /* be sure we have enough space for the '.segno', if any */
  835. path = relpath(RelationGetRelationName(reln)->data);
  836. dofree = false;
  837. if (segno > 0)
  838. {
  839. dofree = true;
  840. fullpath = (char *) palloc(strlen(path) + 12);
  841. sprintf(fullpath, "%s.%d", path, segno);
  842. }
  843. else
  844. fullpath = path;
  845. /* open the file */
  846. #ifndef __CYGWIN32__
  847. fd = FileNameOpenFile(fullpath, O_RDWR | oflags, 0600);
  848. #else
  849. fd = FileNameOpenFile(fullpath, O_RDWR | O_BINARY | oflags, 0600);
  850. #endif
  851. if (dofree)
  852. pfree(fullpath);
  853. if (fd < 0)
  854. return (MdfdVec *) NULL;
  855. /* allocate an mdfdvec entry for it */
  856. oldcxt = MemoryContextSwitchTo(MdCxt);
  857. v = (MdfdVec *) palloc(sizeof(MdfdVec));
  858. MemoryContextSwitchTo(oldcxt);
  859. /* fill the entry */
  860. v->mdfd_vfd = fd;
  861. v->mdfd_flags = (uint16) 0;
  862. v->mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
  863. #ifndef LET_OS_MANAGE_FILESIZE
  864. v->mdfd_chain = (MdfdVec *) NULL;
  865. #ifdef DIAGNOSTIC
  866. if (v->mdfd_lstbcnt > RELSEG_SIZE)
  867. elog(FATAL, "segment too big on open!");
  868. #endif
  869. #endif
  870. /* all done */
  871. return v;
  872. }
  873. /* Get the fd for the relation, opening it if it's not already open */
  874. static int
  875. _mdfd_getrelnfd(Relation reln)
  876. {
  877. int fd;
  878. fd = RelationGetFile(reln);
  879. if (fd < 0)
  880. {
  881. if ((fd = mdopen(reln)) < 0)
  882. elog(ERROR, "cannot open relation %s",
  883.  RelationGetRelationName(reln));
  884. reln->rd_fd = fd;
  885. }
  886. return fd;
  887. }
  888. /* Find the segment of the relation holding the specified block */
  889. static MdfdVec *
  890. _mdfd_getseg(Relation reln, int blkno)
  891. {
  892. MdfdVec    *v;
  893. int segno;
  894. int fd;
  895. int i;
  896. fd = _mdfd_getrelnfd(reln);
  897. #ifndef LET_OS_MANAGE_FILESIZE
  898. for (v = &Md_fdvec[fd], segno = blkno / RELSEG_SIZE, i = 1;
  899.  segno > 0;
  900.  i++, segno--)
  901. {
  902. if (v->mdfd_chain == (MdfdVec *) NULL)
  903. {
  904. v->mdfd_chain = _mdfd_openseg(reln, i, O_CREAT);
  905. if (v->mdfd_chain == (MdfdVec *) NULL)
  906. elog(ERROR, "cannot open segment %d of relation %s",
  907.  i, RelationGetRelationName(reln));
  908. }
  909. v = v->mdfd_chain;
  910. }
  911. #else
  912. v = &Md_fdvec[fd];
  913. #endif
  914. return v;
  915. }
  916. static BlockNumber
  917. _mdnblocks(File file, Size blcksz)
  918. {
  919. long len;
  920. len = FileSeek(file, 0L, SEEK_END) - 1;
  921. return (BlockNumber) ((len < 0) ? 0 : 1 + len / blcksz);
  922. }