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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: mp_sync.c,v 11.29 2001/01/11 18:19:53 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #endif
  15. #ifdef  HAVE_RPC
  16. #include "db_server.h"
  17. #endif
  18. #include "db_int.h"
  19. #include "db_shash.h"
  20. #include "mp.h"
  21. #ifdef HAVE_RPC
  22. #include "gen_client_ext.h"
  23. #include "rpc_client_ext.h"
  24. #endif
  25. static int __bhcmp __P((const void *, const void *));
  26. static int __memp_fsync __P((DB_MPOOLFILE *));
  27. static int __memp_sballoc __P((DB_ENV *, BH ***, u_int32_t *));
  28. /*
  29.  * memp_sync --
  30.  * Mpool sync function.
  31.  */
  32. int
  33. memp_sync(dbenv, lsnp)
  34. DB_ENV *dbenv;
  35. DB_LSN *lsnp;
  36. {
  37. BH *bhp, **bharray;
  38. DB_MPOOL *dbmp;
  39. DB_LSN tlsn;
  40. MPOOL *c_mp, *mp;
  41. MPOOLFILE *mfp;
  42. u_int32_t ar_cnt, i, ndirty;
  43. int ret, retry_done, retry_need, wrote;
  44. #ifdef HAVE_RPC
  45. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  46. return (__dbcl_memp_sync(dbenv, lsnp));
  47. #endif
  48. PANIC_CHECK(dbenv);
  49. ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL);
  50. dbmp = dbenv->mp_handle;
  51. mp = dbmp->reginfo[0].primary;
  52. /*
  53.  * If no LSN is provided, flush the entire cache.
  54.  *
  55.  * !!!
  56.  * Our current behavior is to flush the entire cache, so there's
  57.  * nothing special we have to do here other than deal with NULL
  58.  * pointers.
  59.  */
  60. if (lsnp == NULL) {
  61. ZERO_LSN(tlsn);
  62. lsnp = &tlsn;
  63. F_SET(mp, MP_LSN_RETRY);
  64. } else if (!LOGGING_ON(dbenv)) {
  65. __db_err(dbenv, "memp_sync: requires logging");
  66. return (EINVAL);
  67. }
  68. /*
  69.  * Sync calls are single-threaded so that we don't have multiple
  70.  * threads, with different checkpoint LSNs, walking the caches
  71.  * and updating the checkpoint LSNs and how many buffers remain
  72.  * to be written for the checkpoint.  This shouldn't be a problem,
  73.  * any application that has multiple checkpoint threads isn't what
  74.  * I'd call trustworthy.
  75.  */
  76. MUTEX_LOCK(dbenv, &mp->sync_mutex, dbenv->lockfhp);
  77. /*
  78.  * If the application is asking about a previous call to memp_sync(),
  79.  * and we haven't found any buffers that the application holding the
  80.  * pin couldn't write, return yes or no based on the current count.
  81.  * Note, if the application is asking about a LSN *smaller* than one
  82.  * we've already handled or are currently handling, then we return a
  83.  * result based on the count for the larger LSN.
  84.  */
  85. R_LOCK(dbenv, dbmp->reginfo);
  86. if (!IS_ZERO_LSN(*lsnp) &&
  87.     !F_ISSET(mp, MP_LSN_RETRY) && log_compare(lsnp, &mp->lsn) <= 0) {
  88. if (mp->lsn_cnt == 0) {
  89. *lsnp = mp->lsn;
  90. ret = 0;
  91. } else
  92. ret = DB_INCOMPLETE;
  93. R_UNLOCK(dbenv, dbmp->reginfo);
  94. MUTEX_UNLOCK(dbenv, &mp->sync_mutex);
  95. return (ret);
  96. }
  97. /*
  98.  * Allocate room for a list of buffers, and decide how many buffers
  99.  * we can pin down.
  100.  *
  101.  * !!!
  102.  * Note: __memp_sballoc has released the region lock if we're not
  103.  * continuing forward.
  104.  */
  105. if ((ret =
  106.     __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0) {
  107. MUTEX_UNLOCK(dbenv, &mp->sync_mutex);
  108. return (ret);
  109. }
  110. retry_done = 0;
  111. retry: retry_need = 0;
  112. /*
  113.  * Start a new checkpoint.
  114.  *
  115.  * Save the LSN.  We know that it's a new LSN, a retry, or larger than
  116.  * the one for which we were already doing a checkpoint.  (BTW, I don't
  117.  * expect to see multiple LSN's from the same or multiple processes,
  118.  * but You Just Never Know.  Responding as if they all called with the
  119.  * largest of the LSNs specified makes everything work.)
  120.  *
  121.  * We don't currently use the LSN we save.  We could potentially save
  122.  * the last-written LSN in each buffer header and use it to determine
  123.  * what buffers need to be written.  The problem with this is that it's
  124.  * sizeof(LSN) more bytes of buffer header.  We currently write all the
  125.  * dirty buffers instead, but with a sufficiently large cache that's
  126.  * going to be a problem.
  127.  */
  128. mp->lsn = *lsnp;
  129. /*
  130.  * Clear the global count of buffers waiting to be written, walk the
  131.  * list of files clearing the count of buffers waiting to be written.
  132.  *
  133.  * Clear the retry flag.
  134.  */
  135. mp->lsn_cnt = 0;
  136. for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
  137.     mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile))
  138. mfp->lsn_cnt = 0;
  139. F_CLR(mp, MP_LSN_RETRY);
  140. /*
  141.  * Walk each cache's list of buffers and mark all dirty buffers to be
  142.  * written and all pinned buffers to be potentially written (we can't
  143.  * know if they'll need to be written until the holder returns them to
  144.  * the cache).  We do this in one pass while holding the region locked
  145.  * so that processes can't make new buffers dirty, causing us to never
  146.  * finish.  Since the application may have restarted the sync using a
  147.  * different LSN value, clear any BH_SYNC | BH_SYNC_LOGFLSH flags that
  148.  * appear leftover from previous calls.
  149.  *
  150.  * Keep a count of the total number of buffers we need to write in
  151.  * MPOOL->lsn_cnt, and for each file, in MPOOLFILE->lsn_count.
  152.  */
  153. for (ar_cnt = 0, i = 0; i < mp->nreg; ++i) {
  154. c_mp = dbmp->reginfo[i].primary;
  155. for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh);
  156.     bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
  157. if (F_ISSET(bhp, BH_DIRTY) || bhp->ref != 0) {
  158. F_SET(bhp, BH_SYNC);
  159. ++mp->lsn_cnt;
  160. mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
  161. ++mfp->lsn_cnt;
  162. /*
  163.  * If the buffer isn't being used, we can write
  164.  * it immediately, so increment its reference
  165.  * count to lock it down, and save a reference
  166.  * to it.
  167.  *
  168.  * If we've run out space to store buffer refs,
  169.  * we're screwed.  We don't want to realloc the
  170.  * array while holding a region lock, so we set
  171.  * a flag and deal with it later.
  172.  */
  173. if (bhp->ref == 0) {
  174. ++bhp->ref;
  175. bharray[ar_cnt] = bhp;
  176. if (++ar_cnt >= ndirty) {
  177. retry_need = 1;
  178. break;
  179. }
  180. }
  181. } else
  182. if (F_ISSET(bhp, BH_SYNC))
  183. F_CLR(bhp, BH_SYNC | BH_SYNC_LOGFLSH);
  184. }
  185. if (ar_cnt >= ndirty)
  186. break;
  187. }
  188. /* If there no buffers we can write immediately, we're done. */
  189. if (ar_cnt == 0) {
  190. ret = mp->lsn_cnt ? DB_INCOMPLETE : 0;
  191. goto done;
  192. }
  193. R_UNLOCK(dbenv, dbmp->reginfo);
  194. /*
  195.  * Sort the buffers we're going to write immediately.
  196.  *
  197.  * We try and write the buffers in file/page order: it should reduce
  198.  * seeks by the underlying filesystem and possibly reduce the actual
  199.  * number of writes.
  200.  */
  201. if (ar_cnt > 1)
  202. qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
  203. /*
  204.  * Flush the log.  We have to ensure the log records reflecting the
  205.  * changes on the database pages we're writing have already made it
  206.  * to disk.  We usually do that as we write each page, but if we
  207.  * are going to write a large number of pages, repeatedly acquiring
  208.  * the log region lock is going to be expensive.  Flush the entire
  209.  * log now, so that sync doesn't require any more log flushes.
  210.  */
  211. if (LOGGING_ON(dbenv) && (ret = log_flush(dbenv, NULL)) != 0)
  212. goto done;
  213. R_LOCK(dbenv, dbmp->reginfo);
  214. /* Walk the array, writing buffers. */
  215. for (i = 0; i < ar_cnt; ++i) {
  216. /*
  217.  * It's possible for a thread to have gotten the buffer since
  218.  * we listed it for writing.  If the reference count is still
  219.  * 1, we're the only ones using the buffer, go ahead and write.
  220.  * If it's >1, then skip the buffer and assume that it will be
  221.  * written when it's returned to the cache.
  222.  */
  223. if (bharray[i]->ref > 1) {
  224. --bharray[i]->ref;
  225. continue;
  226. }
  227. /* Write the buffer. */
  228. mfp = R_ADDR(dbmp->reginfo, bharray[i]->mf_offset);
  229. ret = __memp_bhwrite(dbmp, mfp, bharray[i], NULL, &wrote);
  230. /* Release the buffer. */
  231. --bharray[i]->ref;
  232. if (ret == 0 && wrote)
  233. continue;
  234. /*
  235.  * Any process syncing the shared memory buffer pool had best
  236.  * be able to write to any underlying file. Be understanding,
  237.  * but firm, on this point.
  238.  */
  239. if (ret == 0) {
  240. __db_err(dbenv, "%s: unable to flush page: %lu",
  241.     __memp_fns(dbmp, mfp), (u_long)bharray[i]->pgno);
  242. ret = EPERM;
  243. }
  244. /*
  245.  * On error, clear MPOOL->lsn and set MP_LSN_RETRY so that no
  246.  * future checkpoint return can depend on this failure.  Clear
  247.  * the buffer's BH_SYNC flag, because it's used to determine
  248.  * if lsn_cnt values are incremented/decremented.  Don't bother
  249.  * to reset/clear:
  250.  *
  251.  * MPOOL->lsn_cnt
  252.  * MPOOLFILE->lsn_cnt
  253.  *
  254.  * they don't make any difference.
  255.  */
  256. ZERO_LSN(mp->lsn);
  257. F_SET(mp, MP_LSN_RETRY);
  258. /* Release any buffers we're still pinning down. */
  259. while (++i < ar_cnt) {
  260. bhp = bharray[i];
  261. --bhp->ref;
  262. F_CLR(bhp, BH_SYNC | BH_SYNC_LOGFLSH);
  263. }
  264. goto done;
  265. }
  266. ret = mp->lsn_cnt != 0 ? DB_INCOMPLETE : 0;
  267. /*
  268.  * If there were too many buffers and we're not returning an error, we
  269.  * re-try the checkpoint once -- since we allocated 80% of the total
  270.  * buffer count, once should be enough. If it still doesn't work, some
  271.  * other thread of control is dirtying buffers as fast as we're writing
  272.  * them, and we might as well give up for now.  In the latter case, set
  273.  * the global retry flag, we'll have to start from scratch on the next
  274.  * checkpoint.
  275.  */
  276. if (retry_need) {
  277. if (retry_done) {
  278. ret = DB_INCOMPLETE;
  279. F_SET(mp, MP_LSN_RETRY);
  280. } else {
  281. retry_done = 1;
  282. goto retry;
  283. }
  284. }
  285. done: R_UNLOCK(dbenv, dbmp->reginfo);
  286. MUTEX_UNLOCK(dbenv, &mp->sync_mutex);
  287. __os_free(bharray, ndirty * sizeof(BH *));
  288. return (ret);
  289. }
  290. /*
  291.  * memp_fsync --
  292.  * Mpool file sync function.
  293.  */
  294. int
  295. memp_fsync(dbmfp)
  296. DB_MPOOLFILE *dbmfp;
  297. {
  298. DB_ENV *dbenv;
  299. DB_MPOOL *dbmp;
  300. int is_tmp;
  301. dbmp = dbmfp->dbmp;
  302. dbenv = dbmp->dbenv;
  303. #ifdef HAVE_RPC
  304. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  305. return (__dbcl_memp_fsync(dbmfp));
  306. #endif
  307. PANIC_CHECK(dbenv);
  308. /*
  309.  * If this handle doesn't have a file descriptor that's open for
  310.  * writing, or if the file is a temporary, there's no reason to
  311.  * proceed further.
  312.  */
  313. if (F_ISSET(dbmfp, MP_READONLY))
  314. return (0);
  315. R_LOCK(dbenv, dbmp->reginfo);
  316. is_tmp = F_ISSET(dbmfp->mfp, MP_TEMP);
  317. R_UNLOCK(dbenv, dbmp->reginfo);
  318. if (is_tmp)
  319. return (0);
  320. return (__memp_fsync(dbmfp));
  321. }
  322. /*
  323.  * __mp_xxx_fh --
  324.  * Return a file descriptor for DB 1.85 compatibility locking.
  325.  *
  326.  * PUBLIC: int __mp_xxx_fh __P((DB_MPOOLFILE *, DB_FH **));
  327.  */
  328. int
  329. __mp_xxx_fh(dbmfp, fhp)
  330. DB_MPOOLFILE *dbmfp;
  331. DB_FH **fhp;
  332. {
  333. /*
  334.  * This is a truly spectacular layering violation, intended ONLY to
  335.  * support compatibility for the DB 1.85 DB->fd call.
  336.  *
  337.  * Sync the database file to disk, creating the file as necessary.
  338.  *
  339.  * We skip the MP_READONLY and MP_TEMP tests done by memp_fsync(3).
  340.  * The MP_READONLY test isn't interesting because we will either
  341.  * already have a file descriptor (we opened the database file for
  342.  * reading) or we aren't readonly (we created the database which
  343.  * requires write privileges).  The MP_TEMP test isn't interesting
  344.  * because we want to write to the backing file regardless so that
  345.  * we get a file descriptor to return.
  346.  */
  347. *fhp = &dbmfp->fh;
  348. return (F_ISSET(&dbmfp->fh, DB_FH_VALID) ? 0 : __memp_fsync(dbmfp));
  349. }
  350. /*
  351.  * __memp_fsync --
  352.  * Mpool file internal sync function.
  353.  */
  354. static int
  355. __memp_fsync(dbmfp)
  356. DB_MPOOLFILE *dbmfp;
  357. {
  358. BH *bhp, **bharray;
  359. DB_ENV *dbenv;
  360. DB_MPOOL *dbmp;
  361. MPOOL *c_mp, *mp;
  362. size_t mf_offset;
  363. u_int32_t ar_cnt, i, ndirty;
  364. int incomplete, ret, retry_done, retry_need, wrote;
  365. dbmp = dbmfp->dbmp;
  366. dbenv = dbmp->dbenv;
  367. mp = dbmp->reginfo[0].primary;
  368. R_LOCK(dbenv, dbmp->reginfo);
  369. /*
  370.  * Allocate room for a list of buffers, and decide how many buffers
  371.  * we can pin down.
  372.  *
  373.  * !!!
  374.  * Note: __memp_sballoc has released our region lock if we're not
  375.  * continuing forward.
  376.  */
  377. if ((ret =
  378.     __memp_sballoc(dbenv, &bharray, &ndirty)) != 0 || ndirty == 0)
  379. return (ret);
  380. retry_done = 0;
  381. retry: retry_need = 0;
  382. /*
  383.  * Walk each cache's list of buffers and mark all dirty buffers to be
  384.  * written and all pinned buffers to be potentially written (we can't
  385.  * know if they'll need to be written until the holder returns them to
  386.  * the cache).  We do this in one pass while holding the region locked
  387.  * so that processes can't make new buffers dirty, causing us to never
  388.  * finish.
  389.  */
  390. mf_offset = R_OFFSET(dbmp->reginfo, dbmfp->mfp);
  391. for (ar_cnt = 0, incomplete = 0, i = 0; i < mp->nreg; ++i) {
  392. c_mp = dbmp->reginfo[i].primary;
  393. for (bhp = SH_TAILQ_FIRST(&c_mp->bhq, __bh);
  394.     bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
  395. if (!F_ISSET(bhp, BH_DIRTY) ||
  396.     bhp->mf_offset != mf_offset)
  397. continue;
  398. if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED)) {
  399. incomplete = 1;
  400. continue;
  401. }
  402. /*
  403.  * If the buffer isn't being used, we can write
  404.  * it immediately, so increment its reference
  405.  * count to lock it down, and save a reference
  406.  * to it.
  407.  *
  408.  * If we've run out space to store buffer refs,
  409.  * we're screwed.  We don't want to realloc the
  410.  * array while holding a region lock, so we set
  411.  * a flag and deal with it later.
  412.  */
  413. ++bhp->ref;
  414. bharray[ar_cnt] = bhp;
  415. if (++ar_cnt >= ndirty) {
  416. retry_need = 1;
  417. break;
  418. }
  419. }
  420. if (ar_cnt >= ndirty)
  421. break;
  422. }
  423. /* If there no buffers we can write immediately, we're done. */
  424. if (ar_cnt == 0) {
  425. ret = 0;
  426. goto done;
  427. }
  428. R_UNLOCK(dbenv, dbmp->reginfo);
  429. /* Sort the buffers we're going to write. */
  430. if (ar_cnt > 1)
  431. qsort(bharray, ar_cnt, sizeof(BH *), __bhcmp);
  432. R_LOCK(dbenv, dbmp->reginfo);
  433. /* Walk the array, writing buffers. */
  434. for (i = 0; i < ar_cnt;) {
  435. /*
  436.  * It's possible for a thread to have gotten the buffer since
  437.  * we listed it for writing.  If the reference count is still
  438.  * 1, we're the only ones using the buffer, go ahead and write.
  439.  * If it's >1, then skip the buffer and assume that it will be
  440.  * written when it's returned to the cache.
  441.  */
  442. if (bharray[i]->ref > 1) {
  443. incomplete = 1;
  444. --bharray[i++]->ref;
  445. continue;
  446. }
  447. /* Write the buffer. */
  448. ret = __memp_pgwrite(dbmp, dbmfp, bharray[i], NULL, &wrote);
  449. /* Release the buffer. */
  450. --bharray[i++]->ref;
  451. if (ret == 0) {
  452. if (!wrote)
  453. incomplete = 1;
  454. continue;
  455. }
  456. /*
  457.  * On error:
  458.  *
  459.  * Release any buffers we're still pinning down.
  460.  */
  461. while (i < ar_cnt)
  462. --bharray[i++]->ref;
  463. break;
  464. }
  465. /*
  466.  * If there were too many buffers and we're not returning an error, we
  467.  * re-try the flush once -- since we allocated 80% of the total
  468.  * buffer count, once should be enough. If it still doesn't work, some
  469.  * other thread of control is dirtying buffers as fast as we're writing
  470.  * them, and we might as well give up.
  471.  */
  472. if (retry_need) {
  473. if (retry_done)
  474. incomplete = 1;
  475. else {
  476. retry_done = 1;
  477. goto retry;
  478. }
  479. }
  480. done: R_UNLOCK(dbenv, dbmp->reginfo);
  481. __os_free(bharray, ndirty * sizeof(BH *));
  482. /*
  483.  * Sync the underlying file as the last thing we do, so that the OS
  484.  * has a maximal opportunity to flush buffers before we request it.
  485.  *
  486.  * !!!:
  487.  * Don't lock the region around the sync, fsync(2) has no atomicity
  488.  * issues.
  489.  */
  490. if (ret == 0)
  491. ret = incomplete ?
  492.     DB_INCOMPLETE : __os_fsync(dbenv, &dbmfp->fh);
  493. return (ret);
  494. }
  495. /*
  496.  * __memp_sballoc --
  497.  * Allocate room for a list of buffers.
  498.  */
  499. static int
  500. __memp_sballoc(dbenv, bharrayp, ndirtyp)
  501. DB_ENV *dbenv;
  502. BH ***bharrayp;
  503. u_int32_t *ndirtyp;
  504. {
  505. DB_MPOOL *dbmp;
  506. MPOOL *c_mp, *mp;
  507. u_int32_t i, nclean, ndirty, maxpin;
  508. int ret;
  509. dbmp = dbenv->mp_handle;
  510. mp = dbmp->reginfo[0].primary;
  511. /*
  512.  * We don't want to hold the region lock while we write the buffers,
  513.  * so only lock it while we create a list.
  514.  *
  515.  * Walk through the list of caches, figuring out how many buffers
  516.  * we're going to need.
  517.  *
  518.  * Make a point of not holding the region lock across the library
  519.  * allocation call.
  520.  */
  521. for (nclean = ndirty = 0, i = 0; i < mp->nreg; ++i) {
  522. c_mp = dbmp->reginfo[i].primary;
  523. ndirty += c_mp->stat.st_page_dirty;
  524. nclean += c_mp->stat.st_page_clean;
  525. }
  526. R_UNLOCK(dbenv, dbmp->reginfo);
  527. if (ndirty == 0) {
  528. *ndirtyp = 0;
  529. return (0);
  530. }
  531. /*
  532.  * We don't want to pin down the entire buffer cache, otherwise we'll
  533.  * starve threads needing new pages.  Don't pin down more than 80% of
  534.  * the cache, making sure that we don't screw up just because only a
  535.  * few pages have been created.
  536.  */
  537. maxpin = ((ndirty + nclean) * 8) / 10;
  538. if (maxpin < 10)
  539. maxpin = 10;
  540. /*
  541.  * Get a good-sized block of memory to hold buffer pointers, we don't
  542.  * want to run out, but correct if we want to allocate more than we
  543.  * would be allowed to store, regardless.
  544.  */
  545. ndirty += ndirty / 2 + 10;
  546. if (ndirty > maxpin)
  547. ndirty = maxpin;
  548. if ((ret =
  549.     __os_malloc(dbenv, ndirty * sizeof(BH *), NULL, bharrayp)) != 0)
  550. return (ret);
  551. *ndirtyp = ndirty;
  552. R_LOCK(dbenv, dbmp->reginfo);
  553. return (0);
  554. }
  555. static int
  556. __bhcmp(p1, p2)
  557. const void *p1, *p2;
  558. {
  559. BH *bhp1, *bhp2;
  560. bhp1 = *(BH * const *)p1;
  561. bhp2 = *(BH * const *)p2;
  562. /* Sort by file (shared memory pool offset). */
  563. if (bhp1->mf_offset < bhp2->mf_offset)
  564. return (-1);
  565. if (bhp1->mf_offset > bhp2->mf_offset)
  566. return (1);
  567. /*
  568.  * !!!
  569.  * Defend against badly written quicksort code calling the comparison
  570.  * function with two identical pointers (e.g., WATCOM C++ (Power++)).
  571.  */
  572. if (bhp1->pgno < bhp2->pgno)
  573. return (-1);
  574. if (bhp1->pgno > bhp2->pgno)
  575. return (1);
  576. return (0);
  577. }