isdiskbufs2.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*%% (c) Copyright 1993, 1994 Hewlett-Packard Company */
  24. /*%% (c) Copyright 1993, 1994 International Business Machines Corp. */
  25. /*%% (c) Copyright 1993, 1994 Sun Microsystems, Inc. */
  26. /*%% (c) Copyright 1993, 1994 Novell, Inc. */
  27. /*%% $XConsortium: isdiskbufs2.c /main/3 1995/10/23 11:37:47 rswiston $ */
  28. /*
  29. * Copyright (c) 1988 by Sun Microsystems, Inc.
  30. */
  31. /*
  32. * _isdiskbufs.c
  33. *
  34. * Description:
  35. * ISAM disk buffer managament
  36. *
  37. */
  38. /************************ NON MAPPED I/O version ***************************/
  39. #include "isam_impl.h"
  40. extern struct dlink *_isdln_next(), *_isdln_first();
  41. #define ISMAXBUFFERS 200 /* Use 20 buffers */
  42. #define ISHASHHDRS 256 /* Must be a power of two */
  43. #define ISHASHMASK (ISHASHHDRS-1)
  44. #define __hashblkno(fcb,blkno) (((size_t)(fcb)+(blkno)) & ISHASHMASK)
  45. #define base ((char *)0)
  46. #define _isdln_insert(l,e) _isdln_base_insert(base,(l),(e))
  47. #define _isdln_append(l,e) _isdln_base_append(base,(l),(e))
  48. #define _isdln_remove(e) _isdln_base_remove(base,(e))
  49. #define _isdln_first(l) _isdln_base_first(base,(l))
  50. #define _isdln_next(l) _isdln_base_next(base,(l))
  51. #define _isdln_prev(l) _isdln_base_prev(base,(l))
  52. #define _isdln_makeempty(l) _isdln_base_makeempty(base,(l))
  53. #define _isdln_isempty(l) _isdln_base_isempty(base,(l))
  54. /*---------------------- Local data ---------------------------------------*/
  55. static Bufhdr *_getavail(), *_findblock();
  56. static void _disk_init(), _commit1buffer(), _rollback1buffer(), _flush1buffer();
  57. static void _makenodata();
  58. Bufhdr bufhdrs [ISMAXBUFFERS];
  59. struct dlink hashhdrs [ISHASHHDRS]; /* Heads of hashed lists */
  60. struct dlink availlist; /* Available buffer list */
  61. struct dlink *pavail = &availlist;
  62. struct dlink changelist; /* Change buffer list */
  63. struct dlink *pchangl = &changelist;
  64. struct dlink fixlist; /* Fixed buffer list */
  65. struct dlink *pfixl = &fixlist;
  66. static int availn; /* Number of available buffers */
  67. static int minavailn; /* Minimum available buffers */
  68. static int maxavailn; /* Stop flushing when
  69. * when maxavailn buffers
  70. * are available */
  71. #define ISB_FIXED (ISB_RFIXED | ISB_WFIXED)
  72. #define MINAVAILN 40 /* in procent of total # buffers */
  73. #define MAXAVAILN 60 /* in procent of total # buffers */
  74. /* unixfd, .rec, .ind., .var */
  75. Bufhdr *
  76. _isdisk_fix(Fcb *fcb, int unixfd, Blkno blkno, int mode)
  77. {
  78. Bufhdr *p, *p2;
  79. struct dlink *hashl;
  80. /*
  81. * Initialize some local data.
  82. */
  83. _disk_init();
  84. if (fcb->datfd == unixfd)
  85. assert(blkno != 0); /* Never access control page */
  86. hashl = (hashhdrs +__hashblkno(fcb,blkno));
  87. /* Try to find the page in buffer pool. */
  88. if ((p = _findblock(fcb, unixfd, blkno)) == NULL) {
  89. /* Page is not in the pool - install it. */
  90. if (mode != ISFIXNOREAD) {
  91. p = _getavail(); /* Get free page from pool */
  92. _isdln_insert(hashl,&p->isb_hash); /* Insert into hash list */
  93. _isseekpg(unixfd, blkno);
  94. _isreadpg(unixfd, p->isb_buffer);
  95. p->isb_flags = ISB_READ;
  96. p->isb_oldcopy = NULL;
  97. p->isb_fcb = fcb;
  98. p->isb_unixfd = unixfd;
  99. p->isb_blkno = blkno;
  100. }
  101. else
  102. p = NULL;
  103. }
  104. if (p && (p->isb_flags & ISB_FIXED)==0) {
  105. /* Remove buffer from pavail (or pchangl) list. */
  106. _isdln_remove(&p->isb_aclist);
  107. if (!(p->isb_flags & ISB_CHANGE))
  108. availn--;
  109. }
  110. if (mode == ISFIXREAD) {
  111. assert(p);
  112. if(!(p->isb_flags & ISB_FIXED)) {
  113. /* Add buffer to pfixl list. */
  114. _isdln_append(pfixl,&p->isb_flist);
  115. p->isb_flags |= ISB_RFIXED;
  116. }
  117. return (p);
  118. } /* if (p) */
  119. else {
  120. /* If buffer is already fixed for write, no other actions are necces. */
  121. if (p && p->isb_flags & ISB_FIXED) {
  122. assert((p->isb_flags & ISB_RFIXED) == 0); /* Buffer cannot be */
  123. /* fixed for read when is fixed */
  124. /* being fixed for write */
  125. return (p);
  126. }
  127. /* Create shadow page */
  128. p2 = _getavail(); /* Get free page from pool */
  129. availn--;
  130. _isdln_remove(&p2->isb_aclist); /* Remove from pavail */
  131. _isdln_insert(hashl,&p2->isb_hash); /* Insert into hash list */
  132. _isdln_insert(pfixl,&p2->isb_flist); /* Insert into pfixl list */
  133. p2->isb_fcb = fcb;
  134. p2->isb_unixfd = unixfd;
  135. p2->isb_blkno = blkno;
  136. p2->isb_flags = ISB_READ|ISB_WFIXED; /* Mark buffer as dirty */
  137. if (mode == ISFIXWRITE) /* Copy buffer content */
  138. memcpy(p2->isb_buffer,p->isb_buffer,ISPAGESIZE);
  139. p2->isb_oldcopy = p;
  140. /* Make old copy */
  141. if (p) {
  142. assert ((p->isb_flags & ISB_FIXED) == 0);
  143. assert((p->isb_flags & ISB_OLDCOPY) == 0);
  144. p->isb_flags |= ISB_OLDCOPY;
  145. _isdln_remove(&p->isb_hash);
  146. }
  147. return (p2);
  148. }
  149. }
  150. void
  151. _isdisk_unfix (Bufhdr *p)
  152. {
  153. if (!(p->isb_flags & ISB_FIXED))
  154. assert(p->isb_flags & ISB_FIXED);
  155. if (p->isb_flags & ISB_WFIXED) /* Unfix at commit/abort time */
  156. return;
  157. p->isb_flags &= ~ISB_FIXED; /* Clear bit */
  158. _isdln_remove(&p->isb_flist); /* Remove from pfixl */
  159. /* Append to pavail or pchangl list. */
  160. if (p->isb_flags & ISB_CHANGE)
  161. _isdln_append(pchangl,&p->isb_aclist); /* Append to pchangl list */
  162. else {
  163. _isdln_append(pavail,&p->isb_aclist); /* Append to pavail list */
  164. availn++;
  165. }
  166. }
  167. void
  168. _isdisk_commit1 (Bufhdr *p)
  169. {
  170. _commit1buffer(p);
  171. }
  172. void
  173. _isdisk_commit(void)
  174. {
  175. Bufhdr *p;
  176. struct dlink *e;
  177. while ((e = _isdln_first(pfixl)) != pfixl) {
  178. p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
  179. assert(p->isb_flags & ISB_WFIXED);
  180. _commit1buffer(p);
  181. }
  182. }
  183. void
  184. _isdisk_rollback(void)
  185. {
  186. Bufhdr *p;
  187. struct dlink *e;
  188. while ((e = _isdln_first(pfixl)) != pfixl) {
  189. p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
  190. assert(p->isb_flags & ISB_FIXED);
  191. if (p->isb_flags & ISB_WFIXED)
  192. _rollback1buffer(p);
  193. else
  194. _isdisk_unfix(p);
  195. }
  196. }
  197. Bufhdr *
  198. _isdisk_refix(Bufhdr *p, int newmode)
  199. {
  200. Blkno blkno = p->isb_blkno;
  201. Fcb *fcb = p->isb_fcb;
  202. int unixfd = p->isb_unixfd;
  203. assert(newmode == ISFIXWRITE);
  204. if (p->isb_flags & ISB_RFIXED) {
  205. _isdisk_unfix(p);
  206. return (_isdisk_fix(fcb, unixfd, blkno, ISFIXWRITE));
  207. }
  208. else
  209. return (p);
  210. }
  211. void
  212. _isdisk_sync(void)
  213. {
  214. extern time_t _istimeget();
  215. Bufhdr *p;
  216. struct dlink *e;
  217. while ((e = _isdln_first(pchangl)) != pchangl) {
  218. p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
  219. assert(p->isb_flags & ISB_CHANGE);
  220. assert((p->isb_flags & ISB_FIXED)==0);
  221. _flush1buffer(p);
  222. }
  223. }
  224. void
  225. _isdisk_inval(void)
  226. {
  227. extern time_t _istimeget();
  228. Bufhdr *p;
  229. struct dlink *e;
  230. /* ensure pavail is initialized before using it */
  231. if (pavail->dln_forward == 0) {
  232. _isdln_makeempty(pavail);
  233. }
  234. e = pavail;
  235. while ((e = _isdln_prev(e)) != pavail) {
  236. p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
  237. if ((p->isb_flags & ISB_READ) == 0)
  238. break;
  239. _isdln_remove(&p->isb_hash);
  240. p->isb_flags = ISB_NODATA; /* Mark as no data in the buffer */
  241. }
  242. }
  243. #if ISDEBUG
  244. _isdisk_dumphd(void)
  245. {
  246. Bufhdr *p;
  247. int i;
  248. (void)printf("\nInd isfd blkno mode temp oldcopy\n");
  249. for (p = bufhdrs, i = 0; i < ISMAXBUFFERS; p++,i++)
  250. if (p->isb_flags != ISB_NODATA)
  251. (void) printf("%3d: %3d %6d %2x %3d\n",i,
  252. _isfd_getisfd(p->isb_pisfd),
  253. p->isb_blkno,p->isb_flags,
  254. p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
  255. }
  256. aclistdump(struct dlink *lh)
  257. {
  258. Bufhdr *p;
  259. struct dlink *e;
  260. for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
  261. p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
  262. (void) printf("%3d: %3d %6d %2x %3d\n",p-bufhdrs,
  263. _isfd_getisfd(p->isb_pisfd),
  264. p->isb_blkno,p->isb_flags,
  265. p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
  266. }
  267. }
  268. flistdump(struct dlink *lh)
  269. {
  270. Bufhdr *p;
  271. struct dlink *e;
  272. for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
  273. p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
  274. (void) printf("%3d: %3d %6d %2x %3d\n",p-bufhdrs,
  275. _isfd_getisfd(p->isb_pisfd),
  276. p->isb_blkno,p->isb_flags,
  277. p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
  278. }
  279. }
  280. #endif
  281. /*------------------------ Local functions ---------------------------------*/
  282. Static void
  283. _disk_init(void)
  284. {
  285. static Bool initialized = FALSE;
  286. int i;
  287. if (initialized == TRUE)
  288. return;
  289. initialized = TRUE;
  290. /* Initialize hash queue list heads. */
  291. for (i = 0; i < ISHASHHDRS; i++) {
  292. _isdln_makeempty(hashhdrs+i);
  293. }
  294. /* initialize pavail, pchangel, and pfixl lists to empty. */
  295. _isdln_makeempty(pavail);
  296. _isdln_makeempty(pchangl);
  297. _isdln_makeempty(pfixl);
  298. /* Link all buffers into pavail list. */
  299. for (i = 0; i < ISMAXBUFFERS; i++) {
  300. bufhdrs[i].isb_buffer = _ismalloc(ISPAGESIZE);
  301. _isdln_append(pavail,&bufhdrs[i].isb_aclist);
  302. availn++;
  303. }
  304. /* Set maxavailn and minavailn. */
  305. minavailn = (ISMAXBUFFERS * MINAVAILN) / 100;
  306. maxavailn = (ISMAXBUFFERS * MAXAVAILN) / 100;
  307. }
  308. /* _getavail() - get available buffer in disk */
  309. Static Bufhdr *
  310. _getavail(void)
  311. {
  312. Bufhdr *p;
  313. struct dlink *q;
  314. if ((q = _isdln_first(pavail)) == pavail) {
  315. _isfatal_error("No buffer in pool available");
  316. }
  317. p = GETBASE(q,bufhdr,isb_aclist);
  318. if (p->isb_flags & ISB_READ) { /* Remove from hash queue */
  319. _isdln_remove(&p->isb_hash);
  320. p->isb_flags = ISB_NODATA; /* Mark as no data in the buffer */
  321. }
  322. return ((Bufhdr *) p);
  323. }
  324. /* _findblock() - Find block in buffer pool */
  325. Static Bufhdr *
  326. _findblock(Fcb *fcb, int unixfd, Blkno blkno)
  327. {
  328. Bufhdr *p;
  329. struct dlink *lh, *e;
  330. int hashval;
  331. hashval = __hashblkno(fcb,blkno);
  332. lh = hashhdrs + hashval; /* lh is list head */
  333. for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
  334. p = GETBASE(e,bufhdr,isb_hash); /* Get pointer to bufhdr */
  335. if (p->isb_blkno == blkno && p->isb_fcb == fcb && p->isb_unixfd == unixfd) {
  336. assert(p->isb_flags != ISB_NODATA);
  337. return(p);
  338. }
  339. }
  340. return (NULL);
  341. }
  342. /* _commit1buffer() - Commit changes to buffer */
  343. Static void
  344. _commit1buffer(Bufhdr *p)
  345. {
  346. assert(p->isb_flags & ISB_WFIXED); /* Fixed for read buffers should */
  347. /* go through _isdisk_unfix() */
  348. /* Free old permanent buffer if any exists. */
  349. if (p->isb_oldcopy) {
  350. _makenodata(p->isb_oldcopy); /* Make this buffer available */
  351. }
  352. /* Remove buffer from list of fixed buffers. */
  353. /* Append buffer to list of changed buffers. */
  354. _isdln_remove(&p->isb_flist);
  355. _isdln_append(pchangl,&p->isb_aclist);
  356. p->isb_flags &= ~ISB_FIXED;
  357. p->isb_flags |= ISB_CHANGE;
  358. }
  359. /* _rollback1buffer() - Rollback changes to buffer */
  360. Static void
  361. _rollback1buffer(Bufhdr *p)
  362. {
  363. Bufhdr *p2;
  364. assert(p->isb_flags & ISB_WFIXED); /* Fixed for read buffers should */
  365. /* go through _isdisk_unfix() */
  366. /* Re-install old copy if that exists. */
  367. if ((p2 = p->isb_oldcopy) != NULL) {
  368. if (p2->isb_flags & ISB_CHANGE) {
  369. _isdln_append(pchangl,&p2->isb_aclist);
  370. }
  371. else {
  372. _isdln_append(pavail,&p2->isb_aclist);
  373. availn++;
  374. }
  375. p2->isb_flags &= ~ISB_OLDCOPY; /* Clear bit */
  376. /* See implementation of _isdln_append() that this will work. */
  377. _isdln_append(&p->isb_hash,&p2->isb_hash); /* Insert into hash list */
  378. }
  379. _isdln_remove(&p->isb_hash); /* Remove bufer from hash list */
  380. _isdln_remove(&p->isb_flist); /* Remove bufer from pfixl */
  381. _makenodata(p); /* Make this buffer available */
  382. }
  383. /* _makenodata() - make buffer available with no data in it*/
  384. Static void
  385. _makenodata(Bufhdr *p)
  386. {
  387. assert(p->isb_flags & ISB_READ);
  388. p->isb_flags = ISB_NODATA;
  389. _isdln_insert(pavail,&p->isb_aclist);
  390. availn++;
  391. }
  392. /* _flush1buffer() - flush buffer to disk */
  393. Static void
  394. _flush1buffer(Bufhdr *p)
  395. {
  396. assert(p->isb_flags & ISB_CHANGE);
  397. _isseekpg(p->isb_unixfd, p->isb_blkno);
  398. _iswritepg(p->isb_unixfd, p->isb_buffer);
  399. p->isb_flags &= ~ISB_CHANGE; /* clear change flag */
  400. _isdln_remove(&p->isb_aclist); /* Remove from pchangl */
  401. _isdln_append(pavail,&p->isb_aclist); /* Append to pavail */
  402. availn++;
  403. }