hash_buf.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*-
  2. * Copyright (c) 1990, 1993, 1994
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * This code is derived from software contributed to Berkeley by
  6. * Margo Seltzer.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. All advertising materials mentioning features or use of this software
  17. * must display the following acknowledgement:
  18. * This product includes software developed by the University of
  19. * California, Berkeley and its contributors.
  20. * 4. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. */
  36. #if defined(LIBC_SCCS) && !defined(lint)
  37. static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
  38. #endif /* LIBC_SCCS and not lint */
  39. /*
  40. * PACKAGE: hash
  41. *
  42. * DESCRIPTION:
  43. * Contains buffer management
  44. *
  45. * ROUTINES:
  46. * External
  47. * __buf_init
  48. * __get_buf
  49. * __buf_free
  50. * __reclaim_buf
  51. * Internal
  52. * newbuf
  53. */
  54. #include <sys/param.h>
  55. #include <errno.h>
  56. #include <stddef.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #ifdef DEBUG
  60. #include <assert.h>
  61. #endif
  62. #include "../include/db.h"
  63. #include "hash.h"
  64. #include "page.h"
  65. #include "extern.h"
  66. static BUFHEAD *newbuf __P((HTAB *, u_int32_t, BUFHEAD *));
  67. /* Unlink B from its place in the lru */
  68. #define BUF_REMOVE(B) { \
  69. (B)->prev->next = (B)->next; \
  70. (B)->next->prev = (B)->prev; \
  71. }
  72. /* Insert B after P */
  73. #define BUF_INSERT(B, P) { \
  74. (B)->next = (P)->next; \
  75. (B)->prev = (P); \
  76. (P)->next = (B); \
  77. (B)->next->prev = (B); \
  78. }
  79. #define MRU hashp->bufhead.next
  80. #define LRU hashp->bufhead.prev
  81. #define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
  82. #define LRU_INSERT(B) BUF_INSERT((B), LRU)
  83. /*
  84. * We are looking for a buffer with address "addr". If prev_bp is NULL, then
  85. * address is a bucket index. If prev_bp is not NULL, then it points to the
  86. * page previous to an overflow page that we are trying to find.
  87. *
  88. * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
  89. * be valid. Therefore, you must always verify that its address matches the
  90. * address you are seeking.
  91. */
  92. extern BUFHEAD *
  93. __get_buf(hashp, addr, prev_bp, newpage)
  94. HTAB *hashp;
  95. u_int32_t addr;
  96. BUFHEAD *prev_bp;
  97. int newpage; /* If prev_bp set, indicates a new overflow page. */
  98. {
  99. register BUFHEAD *bp;
  100. register u_int32_t is_disk_mask;
  101. register int is_disk, segment_ndx = 0;
  102. SEGMENT segp = 0;
  103. is_disk = 0;
  104. is_disk_mask = 0;
  105. if (prev_bp) {
  106. bp = prev_bp->ovfl;
  107. if (!bp || (bp->addr != addr))
  108. bp = NULL;
  109. if (!newpage)
  110. is_disk = BUF_DISK;
  111. } else {
  112. /* Grab buffer out of directory */
  113. segment_ndx = addr & (hashp->SGSIZE - 1);
  114. /* valid segment ensured by __call_hash() */
  115. segp = hashp->dir[addr >> hashp->SSHIFT];
  116. #ifdef DEBUG
  117. assert(segp != NULL);
  118. #endif
  119. bp = PTROF(segp[segment_ndx]);
  120. is_disk_mask = ISDISK(segp[segment_ndx]);
  121. is_disk = is_disk_mask || !hashp->new_file;
  122. }
  123. if (!bp) {
  124. bp = newbuf(hashp, addr, prev_bp);
  125. if (!bp ||
  126. __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
  127. return (NULL);
  128. if (!prev_bp)
  129. segp[segment_ndx] =
  130. (BUFHEAD *)((ptrdiff_t)bp | is_disk_mask);
  131. } else {
  132. BUF_REMOVE(bp);
  133. MRU_INSERT(bp);
  134. }
  135. return (bp);
  136. }
  137. /*
  138. * We need a buffer for this page. Either allocate one, or evict a resident
  139. * one (if we have as many buffers as we're allowed) and put this one in.
  140. *
  141. * If newbuf finds an error (returning NULL), it also sets errno.
  142. */
  143. static BUFHEAD *
  144. newbuf(hashp, addr, prev_bp)
  145. HTAB *hashp;
  146. u_int32_t addr;
  147. BUFHEAD *prev_bp;
  148. {
  149. register BUFHEAD *bp; /* The buffer we're going to use */
  150. register BUFHEAD *xbp; /* Temp pointer */
  151. register BUFHEAD *next_xbp;
  152. SEGMENT segp;
  153. int segment_ndx;
  154. u_int16_t oaddr, *shortp;
  155. oaddr = 0;
  156. bp = LRU;
  157. /*
  158. * If LRU buffer is pinned, the buffer pool is too small. We need to
  159. * allocate more buffers.
  160. */
  161. if (hashp->nbufs || (bp->flags & BUF_PIN)) {
  162. /* Allocate a new one */
  163. if ((bp = (BUFHEAD *)malloc(sizeof(BUFHEAD))) == NULL)
  164. return (NULL);
  165. #ifdef PURIFY
  166. memset(bp, 0xff, sizeof(BUFHEAD));
  167. #endif
  168. if ((bp->page = (char *)malloc(hashp->BSIZE)) == NULL) {
  169. free(bp);
  170. return (NULL);
  171. }
  172. #ifdef PURIFY
  173. memset(bp->page, 0xff, hashp->BSIZE);
  174. #endif
  175. if (hashp->nbufs)
  176. hashp->nbufs--;
  177. } else {
  178. /* Kick someone out */
  179. BUF_REMOVE(bp);
  180. /*
  181. * If this is an overflow page with addr 0, it's already been
  182. * flushed back in an overflow chain and initialized.
  183. */
  184. if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
  185. /*
  186. * Set oaddr before __put_page so that you get it
  187. * before bytes are swapped.
  188. */
  189. shortp = (u_int16_t *)bp->page;
  190. if (shortp[0])
  191. oaddr = shortp[shortp[0] - 1];
  192. if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
  193. bp->addr, (int)IS_BUCKET(bp->flags), 0))
  194. return (NULL);
  195. /*
  196. * Update the pointer to this page (i.e. invalidate it).
  197. *
  198. * If this is a new file (i.e. we created it at open
  199. * time), make sure that we mark pages which have been
  200. * written to disk so we retrieve them from disk later,
  201. * rather than allocating new pages.
  202. */
  203. if (IS_BUCKET(bp->flags)) {
  204. segment_ndx = bp->addr & (hashp->SGSIZE - 1);
  205. segp = hashp->dir[bp->addr >> hashp->SSHIFT];
  206. #ifdef DEBUG
  207. assert(segp != NULL);
  208. #endif
  209. if (hashp->new_file &&
  210. ((bp->flags & BUF_MOD) ||
  211. ISDISK(segp[segment_ndx])))
  212. segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
  213. else
  214. segp[segment_ndx] = NULL;
  215. }
  216. /*
  217. * Since overflow pages can only be access by means of
  218. * their bucket, free overflow pages associated with
  219. * this bucket.
  220. */
  221. for (xbp = bp; xbp->ovfl;) {
  222. next_xbp = xbp->ovfl;
  223. xbp->ovfl = 0;
  224. xbp = next_xbp;
  225. /* Check that ovfl pointer is up date. */
  226. if (IS_BUCKET(xbp->flags) ||
  227. (oaddr != xbp->addr))
  228. break;
  229. shortp = (u_int16_t *)xbp->page;
  230. if (shortp[0])
  231. /* set before __put_page */
  232. oaddr = shortp[shortp[0] - 1];
  233. if ((xbp->flags & BUF_MOD) && __put_page(hashp,
  234. xbp->page, xbp->addr, 0, 0))
  235. return (NULL);
  236. xbp->addr = 0;
  237. xbp->flags = 0;
  238. BUF_REMOVE(xbp);
  239. LRU_INSERT(xbp);
  240. }
  241. }
  242. }
  243. /* Now assign this buffer */
  244. bp->addr = addr;
  245. #ifdef DEBUG1
  246. (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
  247. bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
  248. #endif
  249. bp->ovfl = NULL;
  250. if (prev_bp) {
  251. /*
  252. * If prev_bp is set, this is an overflow page, hook it in to
  253. * the buffer overflow links.
  254. */
  255. #ifdef DEBUG1
  256. (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
  257. prev_bp->addr, (prev_bp->ovfl ? bp->ovfl->addr : 0),
  258. (bp ? bp->addr : 0));
  259. #endif
  260. prev_bp->ovfl = bp;
  261. bp->flags = 0;
  262. } else
  263. bp->flags = BUF_BUCKET;
  264. MRU_INSERT(bp);
  265. return (bp);
  266. }
  267. extern void
  268. __buf_init(hashp, nbytes)
  269. HTAB *hashp;
  270. int nbytes;
  271. {
  272. BUFHEAD *bfp;
  273. int npages;
  274. bfp = &(hashp->bufhead);
  275. npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
  276. npages = MAX(npages, MIN_BUFFERS);
  277. hashp->nbufs = npages;
  278. bfp->next = bfp;
  279. bfp->prev = bfp;
  280. /*
  281. * This space is calloc'd so these are already null.
  282. *
  283. * bfp->ovfl = NULL;
  284. * bfp->flags = 0;
  285. * bfp->page = NULL;
  286. * bfp->addr = 0;
  287. */
  288. }
  289. extern int
  290. __buf_free(hashp, do_free, to_disk)
  291. HTAB *hashp;
  292. int do_free, to_disk;
  293. {
  294. BUFHEAD *bp;
  295. /* Need to make sure that buffer manager has been initialized */
  296. if (!LRU)
  297. return (0);
  298. for (bp = LRU; bp != &hashp->bufhead;) {
  299. /* Check that the buffer is valid */
  300. if (bp->addr || IS_BUCKET(bp->flags)) {
  301. if (to_disk && (bp->flags & BUF_MOD) &&
  302. __put_page(hashp, bp->page,
  303. bp->addr, IS_BUCKET(bp->flags), 0))
  304. return (-1);
  305. }
  306. /* Check if we are freeing stuff */
  307. if (do_free) {
  308. if (bp->page)
  309. free(bp->page);
  310. BUF_REMOVE(bp);
  311. free(bp);
  312. bp = LRU;
  313. } else
  314. bp = bp->prev;
  315. }
  316. return (0);
  317. }
  318. extern void
  319. __reclaim_buf(hashp, bp)
  320. HTAB *hashp;
  321. BUFHEAD *bp;
  322. {
  323. bp->ovfl = 0;
  324. bp->addr = 0;
  325. bp->flags = 0;
  326. BUF_REMOVE(bp);
  327. LRU_INSERT(bp);
  328. }