qam_files.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:15k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: qam_files.c,v 1.52 2002/08/26 17:52:18 margo Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "dbinc/db_page.h"
  18. #include "dbinc/qam.h"
  19. #include "dbinc/db_am.h"
  20. /*
  21.  * __qam_fprobe -- calculate and open extent
  22.  *
  23.  * Calculate which extent the page is in, open and create if necessary.
  24.  *
  25.  * PUBLIC: int __qam_fprobe
  26.  * PUBLIC:    __P((DB *, db_pgno_t, void *, qam_probe_mode, u_int32_t));
  27.  */
  28. int
  29. __qam_fprobe(dbp, pgno, addrp, mode, flags)
  30. DB *dbp;
  31. db_pgno_t pgno;
  32. void *addrp;
  33. qam_probe_mode mode;
  34. u_int32_t flags;
  35. {
  36. DB_ENV *dbenv;
  37. DB_MPOOLFILE *mpf;
  38. MPFARRAY *array;
  39. QUEUE *qp;
  40. u_int8_t fid[DB_FILE_ID_LEN];
  41. u_int32_t extid, maxext, openflags;
  42. char buf[MAXPATHLEN];
  43. int numext, offset, oldext, ret;
  44. dbenv = dbp->dbenv;
  45. qp = (QUEUE *)dbp->q_internal;
  46. ret = 0;
  47. if (qp->page_ext == 0) {
  48. mpf = dbp->mpf;
  49. return (mode == QAM_PROBE_GET ?
  50.     mpf->get(mpf, &pgno, flags, addrp) :
  51.     mpf->put(mpf, addrp, flags));
  52. }
  53. mpf = NULL;
  54. /*
  55.  * Need to lock long enough to find the mpf or create the file.
  56.  * The file cannot go away because we must have a record locked
  57.  * in that file.
  58.  */
  59. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  60. extid = (pgno - 1) / qp->page_ext;
  61. /* Array1 will always be in use if array2 is in use. */
  62. array = &qp->array1;
  63. if (array->n_extent == 0) {
  64. /* Start with 4 extents */
  65. oldext = 0;
  66. array->n_extent = 4;
  67. array->low_extent = extid;
  68. offset = 0;
  69. numext = 0;
  70. goto alloc;
  71. }
  72. offset = extid - qp->array1.low_extent;
  73. if (qp->array2.n_extent != 0 &&
  74.     abs(offset) > abs(extid - qp->array2.low_extent)) {
  75. array = &qp->array2;
  76. offset = extid - array->low_extent;
  77. }
  78. /*
  79.  * Check to see if the requested extent is outside the range of
  80.  * extents in the array.  This is true by default if there are
  81.  * no extents here yet.
  82.  */
  83. if (offset < 0 || (unsigned) offset >= array->n_extent) {
  84. oldext = array->n_extent;
  85. numext = array->hi_extent - array->low_extent  + 1;
  86. if (offset < 0 &&
  87.     (unsigned) -offset + numext <= array->n_extent) {
  88. /*
  89.  * If we can fit this one into the existing array by
  90.  * shifting the existing entries then we do not have
  91.  * to allocate.
  92.  */
  93. memmove(&array->mpfarray[-offset],
  94.     array->mpfarray, numext
  95.     * sizeof(array->mpfarray[0]));
  96. memset(array->mpfarray, 0, -offset
  97.     * sizeof(array->mpfarray[0]));
  98. offset = 0;
  99. } else if ((u_int32_t)offset == array->n_extent &&
  100.     mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) {
  101. /*
  102.  * If this is at the end of the array and the file at
  103.  * the begining has a zero pin count we can close
  104.  * the bottom extent and put this one at the end.
  105.  */
  106. mpf = array->mpfarray[0].mpf;
  107. if (mpf != NULL && (ret = mpf->close(mpf, 0)) != 0)
  108. goto err;
  109. memmove(&array->mpfarray[0], &array->mpfarray[1],
  110.     (array->n_extent - 1) * sizeof(array->mpfarray[0]));
  111. array->low_extent++;
  112. array->hi_extent++;
  113. offset--;
  114. array->mpfarray[offset].mpf = NULL;
  115. array->mpfarray[offset].pinref = 0;
  116. } else {
  117. /*
  118.  * See if we have wrapped around the queue.
  119.  * If it has then allocate the second array.
  120.  * Otherwise just expand the one we are using.
  121.  */
  122. maxext = (u_int32_t) UINT32_T_MAX
  123.     / (qp->page_ext * qp->rec_page);
  124. if ((u_int32_t) abs(offset) >= maxext/2) {
  125. array = &qp->array2;
  126. DB_ASSERT(array->n_extent == 0);
  127. oldext = 0;
  128. array->n_extent = 4;
  129. array->low_extent = extid;
  130. offset = 0;
  131. numext = 0;
  132. } else {
  133. /*
  134.  * Increase the size to at least include
  135.  * the new one and double it.
  136.  */
  137. array->n_extent += abs(offset);
  138. array->n_extent <<= 2;
  139. }
  140. alloc:
  141. if ((ret = __os_realloc(dbenv,
  142.     array->n_extent * sizeof(struct __qmpf),
  143.     &array->mpfarray)) != 0)
  144. goto err;
  145. if (offset < 0) {
  146. /*
  147.  * Move the array up and put the new one
  148.  * in the first slot.
  149.  */
  150. offset = -offset;
  151. memmove(&array->mpfarray[offset],
  152.     array->mpfarray,
  153.     numext * sizeof(array->mpfarray[0]));
  154. memset(array->mpfarray, 0,
  155.     offset * sizeof(array->mpfarray[0]));
  156. memset(&array->mpfarray[numext + offset], 0,
  157.     (array->n_extent - (numext + offset))
  158.     * sizeof(array->mpfarray[0]));
  159. offset = 0;
  160. }
  161. else
  162. /* Clear the new part of the array. */
  163. memset(&array->mpfarray[oldext], 0,
  164.     (array->n_extent - oldext) *
  165.     sizeof(array->mpfarray[0]));
  166. }
  167. }
  168. /* Update the low and hi range of saved extents. */
  169. if (extid < array->low_extent)
  170. array->low_extent = extid;
  171. if (extid > array->hi_extent)
  172. array->hi_extent = extid;
  173. /* If the extent file is not yet open, open it. */
  174. if (array->mpfarray[offset].mpf == NULL) {
  175. snprintf(buf, sizeof(buf),
  176.     QUEUE_EXTENT, qp->dir, PATH_SEPARATOR[0], qp->name, extid);
  177. if ((ret = dbenv->memp_fcreate(
  178.     dbenv, &array->mpfarray[offset].mpf, 0)) != 0)
  179. goto err;
  180. mpf = array->mpfarray[offset].mpf;
  181. (void)mpf->set_lsn_offset(mpf, 0);
  182. (void)mpf->set_pgcookie(mpf, &qp->pgcookie);
  183. /* Set up the fileid for this extent. */
  184. __qam_exid(dbp, fid, extid);
  185. (void)mpf->set_fileid(mpf, fid);
  186. openflags = DB_EXTENT;
  187. if (LF_ISSET(DB_MPOOL_CREATE))
  188. openflags |= DB_CREATE;
  189. if (F_ISSET(dbp, DB_AM_RDONLY))
  190. openflags |= DB_RDONLY;
  191. if (F_ISSET(dbenv, DB_ENV_DIRECT_DB))
  192. openflags |= DB_DIRECT;
  193. if ((ret = mpf->open(
  194.     mpf, buf, openflags, qp->mode, dbp->pgsize)) != 0) {
  195. array->mpfarray[offset].mpf = NULL;
  196. (void)mpf->close(mpf, 0);
  197. goto err;
  198. }
  199. }
  200. mpf = array->mpfarray[offset].mpf;
  201. if (mode == QAM_PROBE_GET)
  202. array->mpfarray[offset].pinref++;
  203. if (LF_ISSET(DB_MPOOL_CREATE))
  204. mpf->set_unlink(mpf, 0);
  205. err:
  206. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  207. if (ret == 0) {
  208. if (mode == QAM_PROBE_MPF) {
  209. *(DB_MPOOLFILE **)addrp = mpf;
  210. return (0);
  211. }
  212. pgno--;
  213. pgno %= qp->page_ext;
  214. if (mode == QAM_PROBE_GET)
  215. return (mpf->get(mpf, &pgno, flags, addrp));
  216. ret = mpf->put(mpf, addrp, flags);
  217. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  218. array->mpfarray[offset].pinref--;
  219. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  220. }
  221. return (ret);
  222. }
  223. /*
  224.  * __qam_fclose -- close an extent.
  225.  *
  226.  * Calculate which extent the page is in and close it.
  227.  * We assume the mpf entry is present.
  228.  *
  229.  * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t));
  230.  */
  231. int
  232. __qam_fclose(dbp, pgnoaddr)
  233. DB *dbp;
  234. db_pgno_t pgnoaddr;
  235. {
  236. DB_ENV *dbenv;
  237. DB_MPOOLFILE *mpf;
  238. MPFARRAY *array;
  239. QUEUE *qp;
  240. u_int32_t extid;
  241. int offset, ret;
  242. ret = 0;
  243. dbenv = dbp->dbenv;
  244. qp = (QUEUE *)dbp->q_internal;
  245. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  246. extid = (pgnoaddr - 1) / qp->page_ext;
  247. array = &qp->array1;
  248. if (array->low_extent > extid || array->hi_extent < extid)
  249. array = &qp->array2;
  250. offset = extid - array->low_extent;
  251. DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
  252. /* If other threads are still using this file, leave it. */
  253. if (array->mpfarray[offset].pinref != 0)
  254. goto done;
  255. mpf = array->mpfarray[offset].mpf;
  256. array->mpfarray[offset].mpf = NULL;
  257. ret = mpf->close(mpf, 0);
  258. done:
  259. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  260. return (ret);
  261. }
  262. /*
  263.  * __qam_fremove -- remove an extent.
  264.  *
  265.  * Calculate which extent the page is in and remove it.  There is no way
  266.  * to remove an extent without probing it first and seeing that is is empty
  267.  * so we assume the mpf entry is present.
  268.  *
  269.  * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t));
  270.  */
  271. int
  272. __qam_fremove(dbp, pgnoaddr)
  273. DB *dbp;
  274. db_pgno_t pgnoaddr;
  275. {
  276. DB_ENV *dbenv;
  277. DB_MPOOLFILE *mpf;
  278. MPFARRAY *array;
  279. QUEUE *qp;
  280. u_int32_t extid;
  281. #if CONFIG_TEST
  282. char buf[MAXPATHLEN], *real_name;
  283. #endif
  284. int offset, ret;
  285. qp = (QUEUE *)dbp->q_internal;
  286. dbenv = dbp->dbenv;
  287. ret = 0;
  288. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  289. extid = (pgnoaddr - 1) / qp->page_ext;
  290. array = &qp->array1;
  291. if (array->low_extent > extid || array->hi_extent < extid)
  292. array = &qp->array2;
  293. offset = extid - array->low_extent;
  294. DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
  295. #if CONFIG_TEST
  296. real_name = NULL;
  297. /* Find the real name of the file. */
  298. snprintf(buf, sizeof(buf),
  299.     QUEUE_EXTENT, qp->dir, PATH_SEPARATOR[0], qp->name, extid);
  300. if ((ret = __db_appname(dbenv,
  301.     DB_APP_DATA, buf, 0, NULL, &real_name)) != 0)
  302. goto err;
  303. #endif
  304. /*
  305.  * The log must be flushed before the file is deleted.  We depend on
  306.  * the log record of the last delete to recreate the file if we crash.
  307.  */
  308. if (LOGGING_ON(dbenv) && (ret = dbenv->log_flush(dbenv, NULL)) != 0)
  309. goto err;
  310. mpf = array->mpfarray[offset].mpf;
  311. array->mpfarray[offset].mpf = NULL;
  312. mpf->set_unlink(mpf, 1);
  313. if ((ret = mpf->close(mpf, 0)) != 0)
  314. goto err;
  315. /*
  316.  * If the file is at the bottom of the array
  317.  * shift things down and adjust the end points.
  318.  */
  319. if (offset == 0) {
  320. memmove(array->mpfarray, &array->mpfarray[1],
  321.     (array->hi_extent - array->low_extent)
  322.     * sizeof(array->mpfarray[0]));
  323. array->mpfarray[
  324.     array->hi_extent - array->low_extent].mpf = NULL;
  325. if (array->low_extent != array->hi_extent)
  326. array->low_extent++;
  327. } else {
  328. if (extid == array->hi_extent)
  329. array->hi_extent--;
  330. }
  331. err:
  332. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  333. #if CONFIG_TEST
  334. if (real_name != NULL)
  335. __os_free(dbenv, real_name);
  336. #endif
  337. return (ret);
  338. }
  339. /*
  340.  * __qam_sync --
  341.  * Flush the database cache.
  342.  *
  343.  * PUBLIC: int __qam_sync __P((DB *, u_int32_t));
  344.  */
  345. int
  346. __qam_sync(dbp, flags)
  347. DB *dbp;
  348. u_int32_t flags;
  349. {
  350. DB_ENV *dbenv;
  351. DB_MPOOLFILE *mpf;
  352. MPFARRAY *array;
  353. QUEUE *qp;
  354. QUEUE_FILELIST *filelist;
  355. struct __qmpf *mpfp;
  356. u_int32_t i;
  357. int done, ret;
  358. dbenv = dbp->dbenv;
  359. mpf = dbp->mpf;
  360. PANIC_CHECK(dbenv);
  361. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
  362. if ((ret = __db_syncchk(dbp, flags)) != 0)
  363. return (ret);
  364. /* Read-only trees never need to be sync'd. */
  365. if (F_ISSET(dbp, DB_AM_RDONLY))
  366. return (0);
  367. /* If the tree was never backed by a database file, we're done. */
  368. if (F_ISSET(dbp, DB_AM_INMEM))
  369. return (0);
  370. /* Flush any dirty pages from the cache to the backing file. */
  371. if ((ret = mpf->sync(dbp->mpf)) != 0)
  372. return (ret);
  373. qp = (QUEUE *)dbp->q_internal;
  374. if (qp->page_ext == 0)
  375. return (0);
  376. /* We do this for the side effect of opening all active extents. */
  377. if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0)
  378. return (ret);
  379. if (filelist == NULL)
  380. return (0);
  381. __os_free(dbp->dbenv, filelist);
  382. done = 0;
  383. qp = (QUEUE *)dbp->q_internal;
  384. array = &qp->array1;
  385. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  386. again:
  387. mpfp = array->mpfarray;
  388. for (i = array->low_extent; i <= array->hi_extent; i++, mpfp++)
  389. if ((mpf = mpfp->mpf) != NULL) {
  390. if ((ret = mpf->sync(mpf)) != 0)
  391. goto err;
  392. /*
  393.  * If we are the only ones with this file open
  394.  * then close it so it might be removed.
  395.  */
  396. if (mpfp->pinref == 0) {
  397. mpfp->mpf = NULL;
  398. if ((ret = mpf->close(mpf, 0)) != 0)
  399. goto err;
  400. }
  401. }
  402. if (done == 0 && qp->array2.n_extent != 0) {
  403. array = &qp->array2;
  404. done = 1;
  405. goto again;
  406. }
  407. err:
  408. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  409. return (ret);
  410. }
  411. /*
  412.  * __qam_gen_filelist -- generate a list of extent files.
  413.  * Another thread may close the handle so this should only
  414.  * be used single threaded or with care.
  415.  *
  416.  * PUBLIC: int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **));
  417.  */
  418. int
  419. __qam_gen_filelist(dbp, filelistp)
  420. DB *dbp;
  421. QUEUE_FILELIST **filelistp;
  422. {
  423. DB_ENV *dbenv;
  424. DB_MPOOLFILE *mpf;
  425. QUEUE *qp;
  426. QMETA *meta;
  427. db_pgno_t i, last, start;
  428. db_recno_t current, first;
  429. QUEUE_FILELIST *fp;
  430. int ret;
  431. dbenv = dbp->dbenv;
  432. mpf = dbp->mpf;
  433. qp = (QUEUE *)dbp->q_internal;
  434. *filelistp = NULL;
  435. if (qp->page_ext == 0)
  436. return (0);
  437. /* This may happen during metapage recovery. */
  438. if (qp->name == NULL)
  439. return (0);
  440. /* Find out the page number of the last page in the database. */
  441. i = PGNO_BASE_MD;
  442. if ((ret = mpf->get(mpf, &i, 0, &meta)) != 0)
  443. return (ret);
  444. current = meta->cur_recno;
  445. first = meta->first_recno;
  446. if ((ret = mpf->put(mpf, meta, 0)) != 0)
  447. return (ret);
  448. last = QAM_RECNO_PAGE(dbp, current);
  449. start = QAM_RECNO_PAGE(dbp, first);
  450. /* Allocate the worst case plus 1 for null termination. */
  451. if (last >= start)
  452. ret = last - start + 2;
  453. else
  454. ret = last + (QAM_RECNO_PAGE(dbp, UINT32_T_MAX) - start) + 1;
  455. if ((ret = __os_calloc(dbenv,
  456.     ret, sizeof(QUEUE_FILELIST), filelistp)) != 0)
  457. return (ret);
  458. fp = *filelistp;
  459. i = start;
  460. again: for (; i <= last; i += qp->page_ext) {
  461. if ((ret =
  462.     __qam_fprobe(dbp, i, &fp->mpf, QAM_PROBE_MPF, 0)) != 0) {
  463. if (ret == ENOENT)
  464. continue;
  465. return (ret);
  466. }
  467. fp->id = (i - 1) / qp->page_ext;
  468. fp++;
  469. }
  470. if (last < start) {
  471. i = 1;
  472. start = 0;
  473. goto again;
  474. }
  475. return (0);
  476. }
  477. /*
  478.  * __qam_extent_names -- generate a list of extent files names.
  479.  *
  480.  * PUBLIC: int __qam_extent_names __P((DB_ENV *, char *, char ***));
  481.  */
  482. int
  483. __qam_extent_names(dbenv, name, namelistp)
  484. DB_ENV *dbenv;
  485. char *name;
  486. char ***namelistp;
  487. {
  488. DB *dbp;
  489. QUEUE *qp;
  490. QUEUE_FILELIST *filelist, *fp;
  491. char buf[MAXPATHLEN], *dir, **cp, *freep;
  492. int cnt, len, ret;
  493. *namelistp = NULL;
  494. filelist = NULL;
  495. if ((ret = db_create(&dbp, dbenv, 0)) != 0)
  496. return (ret);
  497. if ((ret =
  498.     __db_open(dbp, NULL, name, NULL, DB_QUEUE, DB_RDONLY, 0)) != 0)
  499. return (ret);
  500. qp = dbp->q_internal;
  501. if (qp->page_ext == 0)
  502. goto done;
  503. if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0)
  504. goto done;
  505. if (filelist == NULL)
  506. goto done;
  507. cnt = 0;
  508. for (fp = filelist; fp->mpf != NULL; fp++)
  509. cnt++;
  510. dir = ((QUEUE *)dbp->q_internal)->dir;
  511. name = ((QUEUE *)dbp->q_internal)->name;
  512. /* QUEUE_EXTENT contains extra chars, but add 6 anyway for the int. */
  513. len = (u_int32_t)(cnt * (sizeof(**namelistp)
  514.     + strlen(QUEUE_EXTENT) + strlen(dir) + strlen(name) + 6));
  515. if ((ret =
  516.     __os_malloc(dbp->dbenv, len, namelistp)) != 0)
  517. goto done;
  518. cp = *namelistp;
  519. freep = (char *)(cp + cnt + 1);
  520. for (fp = filelist; fp->mpf != NULL; fp++) {
  521. snprintf(buf, sizeof(buf),
  522.     QUEUE_EXTENT, dir, PATH_SEPARATOR[0], name, fp->id);
  523. len = (u_int32_t)strlen(buf);
  524. *cp++ = freep;
  525. strcpy(freep, buf);
  526. freep += len + 1;
  527. }
  528. *cp = NULL;
  529. done:
  530. if (filelist != NULL)
  531. __os_free(dbp->dbenv, filelist);
  532. (void)dbp->close(dbp, DB_NOSYNC);
  533. return (ret);
  534. }
  535. /*
  536.  * __qam_exid --
  537.  * Generate a fileid for an extent based on the fileid of the main
  538.  * file.  Since we do not log schema creates/deletes explicitly, the log
  539.  * never captures the fileid of an extent file.  In order that masters and
  540.  * replicas have the same fileids (so they can explicitly delete them), we
  541.  * use computed fileids for the extent files of Queue files.
  542.  *
  543.  * An extent file id retains the low order 12 bytes of the file id and
  544.  * overwrites the dev/inode fields, placing a 0 in the inode field, and
  545.  * the extent number in the dev field.
  546.  *
  547.  * PUBLIC: void __qam_exid __P((DB *, u_int8_t *, u_int32_t));
  548.  */
  549. void
  550. __qam_exid(dbp, fidp, exnum)
  551. DB *dbp;
  552. u_int8_t *fidp;
  553. u_int32_t exnum;
  554. {
  555. int i;
  556. u_int8_t *p;
  557. /* Copy the fileid from the master. */
  558. memcpy(fidp, dbp->fileid, DB_FILE_ID_LEN);
  559. /* The first four bytes are the inode or the FileIndexLow; 0 it. */
  560. for (i = sizeof(u_int32_t); i > 0; --i)
  561. *fidp++ = 0;
  562. /* The next four bytes are the dev/FileIndexHigh; insert the exnum . */
  563. for (p = (u_int8_t *)&exnum, i = sizeof(u_int32_t); i > 0; --i)
  564. *fidp++ = *p++;
  565. }