2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
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
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 $ */
29 static char sccsid[] = "@(#)isdiskbufs2.c 1.3 89/07/17 Copyr 1988 Sun Micro";
33 * Copyright (c) 1988 by Sun Microsystems, Inc.
40 * ISAM disk buffer managament
44 /************************ NON MAPPED I/O version ***************************/
46 #include "isam_impl.h"
48 extern struct dlink *_isdln_next(), *_isdln_first();
50 #define ISMAXBUFFERS 200 /* Use 20 buffers */
51 #define ISHASHHDRS 256 /* Must be a power of two */
52 #define ISHASHMASK (ISHASHHDRS-1)
54 #define __hashblkno(fcb,blkno) (((size_t)(fcb)+(blkno)) & ISHASHMASK)
57 #define base ((char *)0)
58 #define _isdln_insert(l,e) _isdln_base_insert(base,(l),(e))
59 #define _isdln_append(l,e) _isdln_base_append(base,(l),(e))
60 #define _isdln_remove(e) _isdln_base_remove(base,(e))
61 #define _isdln_first(l) _isdln_base_first(base,(l))
62 #define _isdln_next(l) _isdln_base_next(base,(l))
63 #define _isdln_prev(l) _isdln_base_prev(base,(l))
64 #define _isdln_makeempty(l) _isdln_base_makeempty(base,(l))
65 #define _isdln_isempty(l) _isdln_base_isempty(base,(l))
67 /*---------------------- Local data ---------------------------------------*/
68 static Bufhdr *_getavail(), *_findblock();
69 static void _disk_init(), _commit1buffer(), _rollback1buffer(), _flush1buffer();
70 static void _makenodata();
72 Bufhdr bufhdrs [ISMAXBUFFERS];
73 struct dlink hashhdrs [ISHASHHDRS]; /* Heads of hashed lists */
75 struct dlink availlist; /* Available buffer list */
76 struct dlink *pavail = &availlist;
78 struct dlink changelist; /* Change buffer list */
79 struct dlink *pchangl = &changelist;
81 struct dlink fixlist; /* Fixed buffer list */
82 struct dlink *pfixl = &fixlist;
84 static int availn; /* Number of available buffers */
85 static int minavailn; /* Minimum available buffers */
86 static int maxavailn; /* Stop flushing when
87 * when maxavailn buffers
91 #define ISB_FIXED (ISB_RFIXED | ISB_WFIXED)
92 #define MINAVAILN 40 /* in procent of total # buffers */
93 #define MAXAVAILN 60 /* in procent of total # buffers */
97 /* unixfd, .rec, .ind., .var */
99 _isdisk_fix(Fcb *fcb, int unixfd, Blkno blkno, int mode)
105 * Initialize some local data.
109 if (fcb->datfd == unixfd)
110 assert(blkno != 0); /* Never access control page */
112 hashl = (hashhdrs +__hashblkno(fcb,blkno));
114 /* Try to find the page in buffer pool. */
115 if ((p = _findblock(fcb, unixfd, blkno)) == NULL) {
117 /* Page is not in the pool - install it. */
118 if (mode != ISFIXNOREAD) {
119 p = _getavail(); /* Get free page from pool */
120 _isdln_insert(hashl,&p->isb_hash); /* Insert into hash list */
122 _isseekpg(unixfd, blkno);
123 _isreadpg(unixfd, p->isb_buffer);
125 p->isb_flags = ISB_READ;
126 p->isb_oldcopy = NULL;
128 p->isb_unixfd = unixfd;
129 p->isb_blkno = blkno;
135 if (p && (p->isb_flags & ISB_FIXED)==0) {
137 /* Remove buffer from pavail (or pchangl) list. */
138 _isdln_remove(&p->isb_aclist);
141 if (!(p->isb_flags & ISB_CHANGE))
146 if (mode == ISFIXREAD) {
149 if(!(p->isb_flags & ISB_FIXED)) {
151 /* Add buffer to pfixl list. */
152 _isdln_append(pfixl,&p->isb_flist);
153 p->isb_flags |= ISB_RFIXED;
160 /* If buffer is already fixed for write, no other actions are necces. */
161 if (p && p->isb_flags & ISB_FIXED) {
162 assert((p->isb_flags & ISB_RFIXED) == 0); /* Buffer cannot be */
163 /* fixed for read when is fixed */
164 /* being fixed for write */
168 /* Create shadow page */
169 p2 = _getavail(); /* Get free page from pool */
171 _isdln_remove(&p2->isb_aclist); /* Remove from pavail */
172 _isdln_insert(hashl,&p2->isb_hash); /* Insert into hash list */
173 _isdln_insert(pfixl,&p2->isb_flist); /* Insert into pfixl list */
176 p2->isb_unixfd = unixfd;
177 p2->isb_blkno = blkno;
178 p2->isb_flags = ISB_READ|ISB_WFIXED; /* Mark buffer as dirty */
180 if (mode == ISFIXWRITE) /* Copy buffer content */
181 memcpy(p2->isb_buffer,p->isb_buffer,ISPAGESIZE);
187 assert ((p->isb_flags & ISB_FIXED) == 0);
188 assert((p->isb_flags & ISB_OLDCOPY) == 0);
190 p->isb_flags |= ISB_OLDCOPY;
191 _isdln_remove(&p->isb_hash);
199 _isdisk_unfix (Bufhdr *p)
201 if (!(p->isb_flags & ISB_FIXED))
202 assert(p->isb_flags & ISB_FIXED);
204 if (p->isb_flags & ISB_WFIXED) /* Unfix at commit/abort time */
207 p->isb_flags &= ~ISB_FIXED; /* Clear bit */
208 _isdln_remove(&p->isb_flist); /* Remove from pfixl */
210 /* Append to pavail or pchangl list. */
211 if (p->isb_flags & ISB_CHANGE)
212 _isdln_append(pchangl,&p->isb_aclist); /* Append to pchangl list */
214 _isdln_append(pavail,&p->isb_aclist); /* Append to pavail list */
220 _isdisk_commit1 (Bufhdr *p)
231 while ((e = _isdln_first(pfixl)) != pfixl) {
232 p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
233 assert(p->isb_flags & ISB_WFIXED);
239 _isdisk_rollback(void)
244 while ((e = _isdln_first(pfixl)) != pfixl) {
245 p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
246 assert(p->isb_flags & ISB_FIXED);
247 if (p->isb_flags & ISB_WFIXED)
255 _isdisk_refix(Bufhdr *p, int newmode)
257 Blkno blkno = p->isb_blkno;
258 Fcb *fcb = p->isb_fcb;
259 int unixfd = p->isb_unixfd;
261 assert(newmode == ISFIXWRITE);
263 if (p->isb_flags & ISB_RFIXED) {
265 return (_isdisk_fix(fcb, unixfd, blkno, ISFIXWRITE));
274 extern time_t _istimeget();
278 while ((e = _isdln_first(pchangl)) != pchangl) {
279 p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
280 assert(p->isb_flags & ISB_CHANGE);
281 assert((p->isb_flags & ISB_FIXED)==0);
289 extern time_t _istimeget();
293 /* ensure pavail is initialized before using it */
295 if (pavail->dln_forward == 0) {
296 _isdln_makeempty(pavail);
301 while ((e = _isdln_prev(e)) != pavail) {
302 p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
304 if ((p->isb_flags & ISB_READ) == 0)
307 _isdln_remove(&p->isb_hash);
308 p->isb_flags = ISB_NODATA; /* Mark as no data in the buffer */
319 (void)printf("\nInd isfd blkno mode temp oldcopy\n");
320 for (p = bufhdrs, i = 0; i < ISMAXBUFFERS; p++,i++)
321 if (p->isb_flags != ISB_NODATA)
322 (void) printf("%3d: %3d %6d %2x %3d\n",i,
323 _isfd_getisfd(p->isb_pisfd),
324 p->isb_blkno,p->isb_flags,
325 p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
328 aclistdump(struct dlink *lh)
333 for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
334 p = GETBASE(e,bufhdr,isb_aclist); /* Get pointer to bufhdr */
335 (void) printf("%3d: %3d %6d %2x %3d\n",p-bufhdrs,
336 _isfd_getisfd(p->isb_pisfd),
337 p->isb_blkno,p->isb_flags,
338 p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
342 flistdump(struct dlink *lh)
347 for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
348 p = GETBASE(e,bufhdr,isb_flist); /* Get pointer to bufhdr */
349 (void) printf("%3d: %3d %6d %2x %3d\n",p-bufhdrs,
350 _isfd_getisfd(p->isb_pisfd),
351 p->isb_blkno,p->isb_flags,
352 p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
359 /*------------------------ Local functions ---------------------------------*/
364 static Bool initialized = FALSE;
367 if (initialized == TRUE)
372 /* Initialize hash queue list heads. */
373 for (i = 0; i < ISHASHHDRS; i++) {
374 _isdln_makeempty(hashhdrs+i);
377 /* initialize pavail, pchangel, and pfixl lists to empty. */
379 _isdln_makeempty(pavail);
380 _isdln_makeempty(pchangl);
381 _isdln_makeempty(pfixl);
383 /* Link all buffers into pavail list. */
384 for (i = 0; i < ISMAXBUFFERS; i++) {
385 bufhdrs[i].isb_buffer = _ismalloc(ISPAGESIZE);
386 _isdln_append(pavail,&bufhdrs[i].isb_aclist);
390 /* Set maxavailn and minavailn. */
391 minavailn = (ISMAXBUFFERS * MINAVAILN) / 100;
392 maxavailn = (ISMAXBUFFERS * MAXAVAILN) / 100;
395 /* _getavail() - get available buffer in disk */
402 if ((q = _isdln_first(pavail)) == pavail) {
403 _isfatal_error("No buffer in pool available");
406 p = GETBASE(q,bufhdr,isb_aclist);
408 if (p->isb_flags & ISB_READ) { /* Remove from hash queue */
409 _isdln_remove(&p->isb_hash);
410 p->isb_flags = ISB_NODATA; /* Mark as no data in the buffer */
413 return ((Bufhdr *) p);
416 /* _findblock() - Find block in buffer pool */
418 _findblock(Fcb *fcb, int unixfd, Blkno blkno)
421 struct dlink *lh, *e;
424 hashval = __hashblkno(fcb,blkno);
426 lh = hashhdrs + hashval; /* lh is list head */
427 for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
428 p = GETBASE(e,bufhdr,isb_hash); /* Get pointer to bufhdr */
429 if (p->isb_blkno == blkno && p->isb_fcb == fcb && p->isb_unixfd == unixfd) {
430 assert(p->isb_flags != ISB_NODATA);
438 /* _commit1buffer() - Commit changes to buffer */
440 _commit1buffer(Bufhdr *p)
442 assert(p->isb_flags & ISB_WFIXED); /* Fixed for read buffers should */
443 /* go through _isdisk_unfix() */
445 /* Free old permanent buffer if any exists. */
446 if (p->isb_oldcopy) {
447 _makenodata(p->isb_oldcopy); /* Make this buffer available */
450 /* Remove buffer from list of fixed buffers. */
451 /* Append buffer to list of changed buffers. */
452 _isdln_remove(&p->isb_flist);
453 _isdln_append(pchangl,&p->isb_aclist);
454 p->isb_flags &= ~ISB_FIXED;
455 p->isb_flags |= ISB_CHANGE;
458 /* _rollback1buffer() - Rollback changes to buffer */
460 _rollback1buffer(Bufhdr *p)
464 assert(p->isb_flags & ISB_WFIXED); /* Fixed for read buffers should */
465 /* go through _isdisk_unfix() */
467 /* Re-install old copy if that exists. */
468 if ((p2 = p->isb_oldcopy) != NULL) {
469 if (p2->isb_flags & ISB_CHANGE) {
470 _isdln_append(pchangl,&p2->isb_aclist);
473 _isdln_append(pavail,&p2->isb_aclist);
476 p2->isb_flags &= ~ISB_OLDCOPY; /* Clear bit */
478 /* See implementation of _isdln_append() that this will work. */
479 _isdln_append(&p->isb_hash,&p2->isb_hash); /* Insert into hash list */
483 _isdln_remove(&p->isb_hash); /* Remove bufer from hash list */
484 _isdln_remove(&p->isb_flist); /* Remove bufer from pfixl */
485 _makenodata(p); /* Make this buffer available */
488 /* _makenodata() - make buffer available with no data in it*/
490 _makenodata(Bufhdr *p)
492 assert(p->isb_flags & ISB_READ);
494 p->isb_flags = ISB_NODATA;
495 _isdln_insert(pavail,&p->isb_aclist);
499 /* _flush1buffer() - flush buffer to disk */
501 _flush1buffer(Bufhdr *p)
503 assert(p->isb_flags & ISB_CHANGE);
505 _isseekpg(p->isb_unixfd, p->isb_blkno);
506 _iswritepg(p->isb_unixfd, p->isb_buffer);
508 p->isb_flags &= ~ISB_CHANGE; /* clear change flag */
510 _isdln_remove(&p->isb_aclist); /* Remove from pchangl */
511 _isdln_append(pavail,&p->isb_aclist); /* Append to pavail */