qam_files.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  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.16 2001/01/19 18:01:59 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_shash.h"
  18. #include "db_am.h"
  19. #include "lock.h"
  20. #include "btree.h"
  21. #include "qam.h"
  22. #include "mp.h"
  23. /*
  24.  * __qam_fprobe -- calcluate and open extent
  25.  *
  26.  * Calculate which extent the page is in, open and create
  27.  * if necessary.
  28.  *
  29.  * PUBLIC: int __qam_fprobe __P((DB *, db_pgno_t, void *, qam_probe_mode, int));
  30.  */
  31. int
  32. __qam_fprobe(dbp, pgno, addrp, mode, flags)
  33. DB *dbp;
  34. db_pgno_t pgno;
  35. void *addrp;
  36. qam_probe_mode mode;
  37. int flags;
  38. {
  39. DB_ENV *dbenv;
  40. DB_MPOOLFILE *mpf;
  41. MPFARRAY *array;
  42. QUEUE *qp;
  43. u_int32_t extid, maxext;
  44. char buf[256];
  45. int numext, offset, oldext, openflags, ret;
  46. qp = (QUEUE *)dbp->q_internal;
  47. if (qp->page_ext == 0) {
  48. mpf = dbp->mpf;
  49. if (mode == QAM_PROBE_GET)
  50. return (memp_fget(mpf, &pgno, flags, addrp));
  51. return (memp_fput(mpf, addrp, flags));
  52. }
  53. dbenv = dbp->dbenv;
  54. mpf = NULL;
  55. ret = 0;
  56. /*
  57.  * Need to lock long enough to find the mpf or create the file.
  58.  * The file cannot go away because we must have a record locked
  59.  * in that file.
  60.  */
  61. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  62. extid = (pgno - 1) / qp->page_ext;
  63. /* Array1 will always be in use if array2 is in use. */
  64. array = &qp->array1;
  65. if (array->n_extent == 0) {
  66. /* Start with 4 extents */
  67. oldext = 0;
  68. array->n_extent = 4;
  69. array->low_extent = extid;
  70. offset = 0;
  71. numext = 0;
  72. goto alloc;
  73. }
  74. offset = extid - qp->array1.low_extent;
  75. if (qp->array2.n_extent != 0 &&
  76.     abs(offset) > abs(extid - qp->array2.low_extent)) {
  77. array = &qp->array2;
  78. offset = extid - array->low_extent;
  79. }
  80. /*
  81.  * Check to see if the requested extent is outside the range of
  82.  * extents in the array.  This is true by defualt if there are
  83.  * no extents here yet.
  84.  */
  85. if (offset < 0 || (unsigned) offset >= array->n_extent) {
  86. oldext = array->n_extent;
  87. numext =  array->hi_extent - array->low_extent  + 1;
  88. if (offset < 0
  89.     && (unsigned) -offset + numext <= array->n_extent) {
  90. /* If we can fit this one in, move the array up */
  91. memmove(&array->mpfarray[-offset],
  92.     array->mpfarray, numext
  93.     * sizeof(array->mpfarray[0]));
  94. memset(array->mpfarray, 0, -offset
  95.      * sizeof(array->mpfarray[0]));
  96. offset = 0;
  97. } else if ((u_int32_t)offset == array->n_extent &&
  98.     mode != QAM_PROBE_MPF && array->mpfarray[0].pinref == 0) {
  99. /* We can close the bottom extent. */
  100. mpf = array->mpfarray[0].mpf;
  101. if (mpf != NULL && (ret = memp_fclose(mpf)) != 0)
  102. goto err;
  103. memmove(&array->mpfarray[0], &array->mpfarray[1],
  104.     (array->n_extent - 1) * sizeof (array->mpfarray[0]));
  105. array->low_extent++;
  106. array->hi_extent++;
  107. offset--;
  108. array->mpfarray[offset].mpf = NULL;
  109. array->mpfarray[offset].pinref = 0;
  110. } else {
  111. /* See if we have wrapped around the queue. */
  112. maxext = (u_int32_t) UINT32_T_MAX
  113.     / (qp->page_ext * qp->rec_page);
  114. if ((u_int32_t) abs(offset) >= maxext/2) {
  115. array = &qp->array2;
  116. DB_ASSERT(array->n_extent == 0);
  117. oldext = 0;
  118. array->n_extent = 4;
  119. array->low_extent = extid;
  120. offset = 0;
  121. numext = 0;
  122. } else {
  123. /*
  124.  * Increase the size to at least include
  125.  * the new one and double it.
  126.  */
  127. array->n_extent += abs(offset);
  128. array->n_extent <<= 2;
  129. }
  130. alloc:
  131. if ((ret = __os_realloc(dbenv,
  132.     array->n_extent * sizeof(struct __qmpf),
  133.     NULL, &array->mpfarray)) != 0)
  134. goto err;
  135. if (offset < 0) {
  136. offset = -offset;
  137. memmove(&array->mpfarray[offset], array->mpfarray,
  138.     numext * sizeof(array->mpfarray[0]));
  139. memset(array->mpfarray, 0,
  140.     offset * sizeof(array->mpfarray[0]));
  141. memset(&array->mpfarray[numext + offset], 0,
  142.      (array->n_extent - (numext + offset))
  143.      * sizeof(array->mpfarray[0]));
  144. offset = 0;
  145. }
  146. else
  147. memset(&array->mpfarray[oldext], 0,
  148.     (array->n_extent - oldext) *
  149.     sizeof(array->mpfarray[0]));
  150. }
  151. }
  152. if (extid < array->low_extent)
  153. array->low_extent = extid;
  154. if (extid > array->hi_extent)
  155. array->hi_extent = extid;
  156. if (array->mpfarray[offset].mpf == NULL) {
  157. snprintf(buf,
  158.     sizeof(buf), QUEUE_EXTENT, qp->dir, qp->name, extid);
  159. openflags = DB_EXTENT;
  160. if (LF_ISSET(DB_MPOOL_CREATE))
  161. openflags |= DB_CREATE;
  162. if (F_ISSET(dbp, DB_AM_RDONLY))
  163. openflags |= DB_RDONLY;
  164. qp->finfo.fileid = NULL;
  165. if ((ret = __memp_fopen(dbenv->mp_handle,
  166.     NULL, buf, openflags, qp->mode, dbp->pgsize,
  167.     1, &qp->finfo, &array->mpfarray[offset].mpf)) != 0)
  168. goto err;
  169. }
  170. mpf = array->mpfarray[offset].mpf;
  171. if (mode == QAM_PROBE_GET)
  172. array->mpfarray[offset].pinref++;
  173. if (LF_ISSET(DB_MPOOL_CREATE))
  174. __memp_clear_unlink(mpf);
  175. err:
  176. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  177. if (ret == 0) {
  178. if (mode == QAM_PROBE_MPF) {
  179. *(DB_MPOOLFILE **)addrp = mpf;
  180. return (0);
  181. }
  182. pgno--;
  183. pgno %= qp->page_ext;
  184. if (mode == QAM_PROBE_GET)
  185. return (memp_fget(mpf,
  186.     &pgno, flags | DB_MPOOL_EXTENT, addrp));
  187. ret = memp_fput(mpf, addrp, flags);
  188. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  189. array->mpfarray[offset].pinref--;
  190. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  191. }
  192. return (ret);
  193. }
  194. /*
  195.  * __qam_fclose -- close an extent.
  196.  *
  197.  * Calculate which extent the page is in and close it.
  198.  * We assume the mpf entry is present.
  199.  *
  200.  * PUBLIC: int __qam_fclose __P((DB *, db_pgno_t));
  201.  */
  202. int
  203. __qam_fclose(dbp, pgnoaddr)
  204. DB *dbp;
  205. db_pgno_t pgnoaddr;
  206. {
  207. DB_ENV *dbenv;
  208. DB_MPOOLFILE *mpf;
  209. MPFARRAY *array;
  210. QUEUE *qp;
  211. u_int32_t extid;
  212. int offset, ret;
  213. ret = 0;
  214. dbenv = dbp->dbenv;
  215. qp = (QUEUE *)dbp->q_internal;
  216. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  217. extid = (pgnoaddr - 1) / qp->page_ext;
  218. array = &qp->array1;
  219. if (array->low_extent > extid || array->hi_extent < extid)
  220. array = &qp->array2;
  221. offset = extid - array->low_extent;
  222. DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
  223. /* If other threads are still using this file, leave it. */
  224. if (array->mpfarray[offset].pinref != 0)
  225. goto done;
  226. mpf = array->mpfarray[offset].mpf;
  227. array->mpfarray[offset].mpf = NULL;
  228. ret = memp_fclose(mpf);
  229. done:
  230. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  231. return (ret);
  232. }
  233. /*
  234.  * __qam_fremove -- remove an extent.
  235.  *
  236.  * Calculate which extent the page is in and remove it.  There is no way
  237.  * to remove an extent without probing it first and seeing that is is empty
  238.  * so we assume the mpf entry is present.
  239.  *
  240.  * PUBLIC: int __qam_fremove __P((DB *, db_pgno_t));
  241.  */
  242. int
  243. __qam_fremove(dbp, pgnoaddr)
  244. DB *dbp;
  245. db_pgno_t pgnoaddr;
  246. {
  247. DB_ENV *dbenv;
  248. DB_MPOOLFILE *mpf;
  249. MPFARRAY *array;
  250. QUEUE *qp;
  251. u_int32_t extid;
  252. #if CONFIG_TEST
  253. char buf[256], *real_name;
  254. #endif
  255. int offset, ret;
  256. qp = (QUEUE *)dbp->q_internal;
  257. dbenv = dbp->dbenv;
  258. ret = 0;
  259. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  260. extid = (pgnoaddr - 1) / qp->page_ext;
  261. array = &qp->array1;
  262. if (array->low_extent > extid || array->hi_extent < extid)
  263. array = &qp->array2;
  264. offset = extid - array->low_extent;
  265. DB_ASSERT(offset >= 0 && (unsigned) offset < array->n_extent);
  266. #if CONFIG_TEST
  267. real_name = NULL;
  268. /* Find the real name of the file. */
  269. snprintf(buf, sizeof(buf),
  270.     QUEUE_EXTENT, qp->dir, qp->name, extid);
  271. if ((ret = __db_appname(dbenv,
  272.     DB_APP_DATA, NULL, buf, 0, NULL, &real_name)) != 0)
  273. goto err;
  274. #endif
  275. mpf = array->mpfarray[offset].mpf;
  276. array->mpfarray[offset].mpf = NULL;
  277. __memp_set_unlink(mpf);
  278. if ((ret = memp_fclose(mpf)) != 0)
  279. goto err;
  280. if (offset == 0) {
  281. memmove(array->mpfarray, &array->mpfarray[1],
  282.     (array->hi_extent - array->low_extent)
  283.     * sizeof(array->mpfarray[0]));
  284. array->mpfarray[array->hi_extent - array->low_extent].mpf = NULL;
  285. if (array->low_extent != array->hi_extent)
  286. array->low_extent++;
  287. } else {
  288. if (extid == array->hi_extent)
  289. array->hi_extent--;
  290. }
  291. err:
  292. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  293. #if CONFIG_TEST
  294. if (real_name != NULL)
  295. __os_freestr(real_name);
  296. #endif
  297. return (ret);
  298. }
  299. /*
  300.  * __qam_sync --
  301.  * Flush the database cache.
  302.  *
  303.  * PUBLIC: int __qam_sync __P((DB *, u_int32_t));
  304.  */
  305. int
  306. __qam_sync(dbp, flags)
  307. DB *dbp;
  308. u_int32_t flags;
  309. {
  310. DB_ENV *dbenv;
  311. DB_MPOOLFILE *mpf;
  312. MPFARRAY *array;
  313. QUEUE *qp;
  314. QUEUE_FILELIST *filelist;
  315. struct __qmpf *mpfp;
  316. u_int32_t i;
  317. int done, ret;
  318. dbenv = dbp->dbenv;
  319. PANIC_CHECK(dbenv);
  320. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
  321. if ((ret = __db_syncchk(dbp, flags)) != 0)
  322. return (ret);
  323. /* Read-only trees never need to be sync'd. */
  324. if (F_ISSET(dbp, DB_AM_RDONLY))
  325. return (0);
  326. /* If the tree was never backed by a database file, we're done. */
  327. if (F_ISSET(dbp, DB_AM_INMEM))
  328. return (0);
  329. /* Flush any dirty pages from the cache to the backing file. */
  330. if ((ret = memp_fsync(dbp->mpf)) != 0)
  331. return (ret);
  332. qp = (QUEUE *)dbp->q_internal;
  333. if (qp->page_ext == 0)
  334. return (0);
  335. /* We do this for the side effect of opening all active extents. */
  336. if ((ret = __qam_gen_filelist(dbp, &filelist)) != 0)
  337. return (ret);
  338. if (filelist == NULL)
  339. return (0);
  340. __os_free(filelist, 0);
  341. done = 0;
  342. qp = (QUEUE *)dbp->q_internal;
  343. array = &qp->array1;
  344. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  345. again:
  346. mpfp = array->mpfarray;
  347. for (i = array->low_extent; i <= array->hi_extent; i++, mpfp++)
  348. if ((mpf = mpfp->mpf) != NULL) {
  349. if ((ret = memp_fsync(mpf)) != 0)
  350. goto err;
  351. /*
  352.  * If we are the only ones with this file open
  353.  * then close it so it might be removed.
  354.  */
  355. if (mpfp->pinref == 0) {
  356. mpfp->mpf = NULL;
  357. if ((ret = memp_fclose(mpf)) != 0)
  358. goto err;
  359. }
  360. }
  361. if (done == 0 && qp->array2.n_extent != 0) {
  362. array = &qp->array2;
  363. done = 1;
  364. goto again;
  365. }
  366. err:
  367. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  368. return (ret);
  369. }
  370. /*
  371.  * __qam_gen_filelist -- generate a list of extent files.
  372.  * Another thread may close the handle so this should only
  373.  * be used single threaded or with care.
  374.  *
  375.  * PUBLIC: int __qam_gen_filelist __P(( DB *, QUEUE_FILELIST **));
  376.  */
  377. int
  378. __qam_gen_filelist(dbp, filelistp)
  379. DB *dbp;
  380. QUEUE_FILELIST **filelistp;
  381. {
  382. DB_ENV *dbenv;
  383. QUEUE *qp;
  384. QMETA *meta;
  385. db_pgno_t i, last, start, stop;
  386. db_recno_t current, first;
  387. QUEUE_FILELIST *fp;
  388. int ret;
  389. dbenv = dbp->dbenv;
  390. qp = (QUEUE *)dbp->q_internal;
  391. *filelistp = NULL;
  392. if (qp->page_ext == 0)
  393. return (0);
  394. /* This may happen during metapage recovery. */
  395. if (qp->name == NULL)
  396. return (0);
  397. /* Find out the page number of the last page in the database. */
  398. i = PGNO_BASE_MD;
  399. if ((ret = memp_fget(dbp->mpf, &i, 0, &meta)) != 0) {
  400. (void)dbp->close(dbp, 0);
  401. return (ret);
  402. }
  403. current = meta->cur_recno;
  404. first = meta->first_recno;
  405. if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0) {
  406. (void)dbp->close(dbp, 0);
  407. return (ret);
  408. }
  409. last = QAM_RECNO_PAGE(dbp, current);
  410. start = QAM_RECNO_PAGE(dbp, first);
  411. /* Allocate the worst case plus 1 for null termination. */
  412. if (last >= start)
  413. ret = last - start + 2;
  414. else
  415. ret = last + (QAM_RECNO_PAGE(dbp, UINT32_T_MAX) - start) + 1;
  416. if ((ret = __os_calloc(dbenv,
  417.     ret, sizeof(QUEUE_FILELIST), filelistp)) != 0)
  418. return (ret);
  419. fp = *filelistp;
  420. i = start;
  421. if (last >= start)
  422. stop = last;
  423. else
  424. stop = QAM_RECNO_PAGE(dbp, UINT32_T_MAX);
  425. again:
  426. for (; i <= last; i += qp->page_ext) {
  427. if ((ret = __qam_fprobe(dbp,
  428.     i, &fp->mpf, QAM_PROBE_MPF, 0)) != 0) {
  429. if (ret == ENOENT)
  430. continue;
  431. return (ret);
  432. }
  433. fp->id = (i - 1) / qp->page_ext;
  434. fp++;
  435. }
  436. if (last < start) {
  437. i = 1;
  438. stop = last;
  439. start = 0;
  440. goto again;
  441. }
  442. return (0);
  443. }