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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: mp_fput.c,v 11.36 2002/08/09 19:04:11 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #endif
  14. #include "db_int.h"
  15. #include "dbinc/db_shash.h"
  16. #include "dbinc/mp.h"
  17. /*
  18.  * __memp_fput --
  19.  * Mpool file put function.
  20.  *
  21.  * PUBLIC: int __memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t));
  22.  */
  23. int
  24. __memp_fput(dbmfp, pgaddr, flags)
  25. DB_MPOOLFILE *dbmfp;
  26. void *pgaddr;
  27. u_int32_t flags;
  28. {
  29. BH *argbhp, *bhp, *prev;
  30. DB_ENV *dbenv;
  31. DB_MPOOL *dbmp;
  32. DB_MPOOL_HASH *hp;
  33. MPOOL *c_mp;
  34. u_int32_t n_cache;
  35. int adjust, ret;
  36. dbmp = dbmfp->dbmp;
  37. dbenv = dbmp->dbenv;
  38. PANIC_CHECK(dbenv);
  39. /* Validate arguments. */
  40. if (flags) {
  41. if ((ret = __db_fchk(dbenv, "memp_fput", flags,
  42.     DB_MPOOL_CLEAN | DB_MPOOL_DIRTY | DB_MPOOL_DISCARD)) != 0)
  43. return (ret);
  44. if ((ret = __db_fcchk(dbenv, "memp_fput",
  45.     flags, DB_MPOOL_CLEAN, DB_MPOOL_DIRTY)) != 0)
  46. return (ret);
  47. if (LF_ISSET(DB_MPOOL_DIRTY) && F_ISSET(dbmfp, MP_READONLY)) {
  48. __db_err(dbenv,
  49.     "%s: dirty flag set for readonly file page",
  50.     __memp_fn(dbmfp));
  51. return (EACCES);
  52. }
  53. }
  54. /*
  55.  * If we're mapping the file, there's nothing to do.  Because we can
  56.  * stop mapping the file at any time, we have to check on each buffer
  57.  * to see if the address we gave the application was part of the map
  58.  * region.
  59.  */
  60. if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr &&
  61.     (u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len)
  62. return (0);
  63. #ifdef DIAGNOSTIC
  64. /*
  65.  * Decrement the per-file pinned buffer count (mapped pages aren't
  66.  * counted).
  67.  */
  68. R_LOCK(dbenv, dbmp->reginfo);
  69. if (dbmfp->pinref == 0) {
  70. ret = EINVAL;
  71. __db_err(dbenv,
  72.     "%s: more pages returned than retrieved", __memp_fn(dbmfp));
  73. } else {
  74. ret = 0;
  75. --dbmfp->pinref;
  76. }
  77. R_UNLOCK(dbenv, dbmp->reginfo);
  78. if (ret != 0)
  79. return (ret);
  80. #endif
  81. /* Convert a page address to a buffer header and hash bucket. */
  82. bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
  83. n_cache = NCACHE(dbmp->reginfo[0].primary, bhp->mf_offset, bhp->pgno);
  84. c_mp = dbmp->reginfo[n_cache].primary;
  85. hp = R_ADDR(&dbmp->reginfo[n_cache], c_mp->htab);
  86. hp = &hp[NBUCKET(c_mp, bhp->mf_offset, bhp->pgno)];
  87. MUTEX_LOCK(dbenv, &hp->hash_mutex);
  88. /* Set/clear the page bits. */
  89. if (LF_ISSET(DB_MPOOL_CLEAN) &&
  90.     F_ISSET(bhp, BH_DIRTY) && !F_ISSET(bhp, BH_DIRTY_CREATE)) {
  91. DB_ASSERT(hp->hash_page_dirty != 0);
  92. --hp->hash_page_dirty;
  93. F_CLR(bhp, BH_DIRTY);
  94. }
  95. if (LF_ISSET(DB_MPOOL_DIRTY) && !F_ISSET(bhp, BH_DIRTY)) {
  96. ++hp->hash_page_dirty;
  97. F_SET(bhp, BH_DIRTY);
  98. }
  99. if (LF_ISSET(DB_MPOOL_DISCARD))
  100. F_SET(bhp, BH_DISCARD);
  101. /*
  102.  * Check for a reference count going to zero.  This can happen if the
  103.  * application returns a page twice.
  104.  */
  105. if (bhp->ref == 0) {
  106. __db_err(dbenv, "%s: page %lu: unpinned page returned",
  107.     __memp_fn(dbmfp), (u_long)bhp->pgno);
  108. MUTEX_UNLOCK(dbenv, &hp->hash_mutex);
  109. return (EINVAL);
  110. }
  111. /*
  112.  * If more than one reference to the page or a reference other than a
  113.  * thread waiting to flush the buffer to disk, we're done.  Ignore the
  114.  * discard flags (for now) and leave the buffer's priority alone.
  115.  */
  116. if (--bhp->ref > 1 || (bhp->ref == 1 && !F_ISSET(bhp, BH_LOCKED))) {
  117. MUTEX_UNLOCK(dbenv, &hp->hash_mutex);
  118. return (0);
  119. }
  120. /* Update priority values. */
  121. if (F_ISSET(bhp, BH_DISCARD) ||
  122.     dbmfp->mfp->priority == MPOOL_PRI_VERY_LOW)
  123. bhp->priority = 0;
  124. else {
  125. /*
  126.  * We don't lock the LRU counter or the stat.st_pages field, if
  127.  * we get garbage (which won't happen on a 32-bit machine), it
  128.  * only means a buffer has the wrong priority.
  129.  */
  130. bhp->priority = c_mp->lru_count;
  131. adjust = 0;
  132. if (dbmfp->mfp->priority != 0)
  133. adjust =
  134.     (int)c_mp->stat.st_pages / dbmfp->mfp->priority;
  135. if (F_ISSET(bhp, BH_DIRTY))
  136. adjust += c_mp->stat.st_pages / MPOOL_PRI_DIRTY;
  137. if (adjust > 0) {
  138. if (UINT32_T_MAX - bhp->priority <= (u_int32_t)adjust)
  139. bhp->priority += adjust;
  140. } else if (adjust < 0)
  141. if (bhp->priority > (u_int32_t)-adjust)
  142. bhp->priority += adjust;
  143. }
  144. /*
  145.  * Buffers on hash buckets are sorted by priority -- move the buffer
  146.  * to the correct position in the list.
  147.  */
  148. argbhp = bhp;
  149. SH_TAILQ_REMOVE(&hp->hash_bucket, argbhp, hq, __bh);
  150. prev = NULL;
  151. for (bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh);
  152.     bhp != NULL; prev = bhp, bhp = SH_TAILQ_NEXT(bhp, hq, __bh))
  153. if (bhp->priority > argbhp->priority)
  154. break;
  155. if (prev == NULL)
  156. SH_TAILQ_INSERT_HEAD(&hp->hash_bucket, argbhp, hq, __bh);
  157. else
  158. SH_TAILQ_INSERT_AFTER(&hp->hash_bucket, prev, argbhp, hq, __bh);
  159. /* Reset the hash bucket's priority. */
  160. hp->hash_priority = SH_TAILQ_FIRST(&hp->hash_bucket, __bh)->priority;
  161. #ifdef DIAGNOSTIC
  162. __memp_check_order(hp);
  163. #endif
  164. /*
  165.  * The sync code has a separate counter for buffers on which it waits.
  166.  * It reads that value without holding a lock so we update it as the
  167.  * last thing we do.  Once that value goes to 0, we won't see another
  168.  * reference to that buffer being returned to the cache until the sync
  169.  * code has finished, so we're safe as long as we don't let the value
  170.  * go to 0 before we finish with the buffer.
  171.  */
  172. if (F_ISSET(argbhp, BH_LOCKED) && argbhp->ref_sync != 0)
  173. --argbhp->ref_sync;
  174. MUTEX_UNLOCK(dbenv, &hp->hash_mutex);
  175. return (0);
  176. }