Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / tt / mini_isam / isdiskbufs2.c
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 librararies 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 #ifndef lint
29 static char sccsid[] = "@(#)isdiskbufs2.c 1.3 89/07/17 Copyr 1988 Sun Micro";
30 #endif
31
32 /*
33  * Copyright (c) 1988 by Sun Microsystems, Inc.
34  */
35
36 /*
37  * _isdiskbufs.c
38  *
39  * Description:
40  *      ISAM disk buffer managament
41  *
42  */
43
44 /************************ NON MAPPED I/O version ***************************/
45
46 #include "isam_impl.h"
47
48 extern struct dlink *_isdln_next(), *_isdln_first();
49
50 #define ISMAXBUFFERS    200                  /* Use 20 buffers */
51 #define ISHASHHDRS      256                  /* Must be a power of two */
52 #define ISHASHMASK      (ISHASHHDRS-1)
53
54 #define __hashblkno(fcb,blkno) (((int)(fcb)+(blkno)) & ISHASHMASK)
55
56
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))
66
67 /*---------------------- Local data ---------------------------------------*/
68 static Bufhdr *_getavail(), *_findblock();
69 static void _disk_init(), _commit1buffer(), _rollback1buffer(), _flush1buffer();
70 static void _makenodata();
71
72 Bufhdr bufhdrs [ISMAXBUFFERS];
73 struct dlink  hashhdrs [ISHASHHDRS];         /* Heads of hashed lists */
74
75 struct dlink  availlist;                     /* Available buffer list */
76 struct dlink  *pavail = &availlist;
77
78 struct dlink  changelist;                    /* Change buffer list */
79 struct dlink  *pchangl = &changelist;
80
81 struct dlink  fixlist;                       /* Fixed buffer list */
82 struct dlink  *pfixl = &fixlist;
83
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
88                                               * are available */
89
90
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 */
94
95
96
97 Bufhdr *
98 _isdisk_fix(fcb, unixfd, blkno, mode)
99     Fcb         *fcb;
100     int         unixfd;                      /* .rec, .ind., .var */
101     Blkno       blkno;
102     int         mode;
103 {
104     register Bufhdr *p, *p2;
105     struct dlink           *hashl;
106
107     /*
108      * Initialize some local data.
109      */
110     _disk_init();       
111
112     if (fcb->datfd == unixfd)
113         assert(blkno != 0);                  /* Never access control page */
114
115     hashl = (hashhdrs +__hashblkno(fcb,blkno));
116     
117     /* Try to find the page in buffer pool. */
118     if ((p = _findblock(fcb, unixfd, blkno)) == NULL) {
119         
120         /* Page is not in the pool - install it. */
121         if (mode != ISFIXNOREAD) {
122             p = _getavail();                 /* Get free page from pool */
123             _isdln_insert(hashl,&p->isb_hash); /* Insert into hash list */
124             
125             _isseekpg(unixfd, blkno);
126             _isreadpg(unixfd, p->isb_buffer);
127
128             p->isb_flags = ISB_READ;
129             p->isb_oldcopy = NULL;
130             p->isb_fcb = fcb;
131             p->isb_unixfd  = unixfd;
132             p->isb_blkno = blkno;
133         }
134         else
135             p = NULL;
136     }   
137     
138     if (p && (p->isb_flags & ISB_FIXED)==0) {
139         
140         /* Remove buffer from pavail (or pchangl) list. */
141         _isdln_remove(&p->isb_aclist);
142
143
144         if (!(p->isb_flags & ISB_CHANGE))
145             availn--;
146
147     }
148     
149     if (mode == ISFIXREAD) {
150         assert(p);
151         
152         if(!(p->isb_flags & ISB_FIXED)) {  
153             
154             /* Add buffer to pfixl list. */
155             _isdln_append(pfixl,&p->isb_flist);
156             p->isb_flags |= ISB_RFIXED;
157             
158         }
159         return (p);
160     }   /* if (p) */
161     else {
162         
163         /* If buffer is already fixed for write, no other actions are necces. */
164         if (p && p->isb_flags & ISB_FIXED) {
165             assert((p->isb_flags & ISB_RFIXED) == 0); /* Buffer cannot be */
166             /* fixed for read when is fixed */
167             /* being fixed for write */
168             return (p);
169         }
170         
171         /* Create shadow page */
172         p2 = _getavail();                    /* Get free page from pool */
173         availn--;
174         _isdln_remove(&p2->isb_aclist);      /* Remove from pavail */
175         _isdln_insert(hashl,&p2->isb_hash);  /* Insert into hash list */
176         _isdln_insert(pfixl,&p2->isb_flist); /* Insert into pfixl list */
177         
178         p2->isb_fcb = fcb;
179         p2->isb_unixfd = unixfd;
180         p2->isb_blkno = blkno;
181         p2->isb_flags = ISB_READ|ISB_WFIXED; /* Mark buffer as dirty */
182         
183         if (mode == ISFIXWRITE)              /* Copy buffer content */
184             memcpy(p2->isb_buffer,p->isb_buffer,ISPAGESIZE);
185         
186         p2->isb_oldcopy = p;
187         
188         /* Make old copy */
189         if (p) {
190             assert ((p->isb_flags & ISB_FIXED) == 0);
191             assert((p->isb_flags & ISB_OLDCOPY) == 0);
192             
193             p->isb_flags |= ISB_OLDCOPY;
194             _isdln_remove(&p->isb_hash);
195         }
196         
197         return (p2);
198     }
199 }
200
201 void
202 _isdisk_unfix (p)
203     register Bufhdr     *p;
204 {
205     if (!(p->isb_flags & ISB_FIXED))
206     assert(p->isb_flags & ISB_FIXED);
207     
208     if (p->isb_flags & ISB_WFIXED)           /* Unfix at commit/abort time */
209         return;
210     
211     p->isb_flags &= ~ISB_FIXED;              /* Clear bit */
212     _isdln_remove(&p->isb_flist);            /* Remove from pfixl */
213     
214     /* Append to pavail or pchangl list. */
215     if (p->isb_flags & ISB_CHANGE)
216         _isdln_append(pchangl,&p->isb_aclist); /* Append to pchangl list */
217     else {
218         _isdln_append(pavail,&p->isb_aclist); /* Append to pavail list */
219         availn++;
220     }
221 }
222
223 void
224 _isdisk_commit1 (p)
225     Bufhdr      *p;
226 {
227     _commit1buffer(p);
228 }
229
230 void
231 _isdisk_commit()
232 {
233     register Bufhdr *p;
234     struct dlink           *e;
235     
236     while ((e = _isdln_first(pfixl)) != pfixl) {
237         p = GETBASE(e,bufhdr,isb_flist);  /* Get pointer to bufhdr */
238         assert(p->isb_flags & ISB_WFIXED);
239         _commit1buffer(p);
240     }
241 }
242
243 void
244 _isdisk_rollback()
245 {
246     register Bufhdr     *p;
247     struct dlink           *e;
248     
249     while ((e = _isdln_first(pfixl)) != pfixl) {
250         p = GETBASE(e,bufhdr,isb_flist);  /* Get pointer to bufhdr */
251         assert(p->isb_flags & ISB_FIXED);
252         if (p->isb_flags & ISB_WFIXED)
253             _rollback1buffer(p);
254         else 
255             _isdisk_unfix(p);
256     }
257 }
258
259 Bufhdr *
260 _isdisk_refix(p, newmode)
261     Bufhdr      *p;
262     int                 newmode;
263 {
264     Blkno       blkno = p->isb_blkno;
265     Fcb         *fcb = p->isb_fcb;
266     int         unixfd = p->isb_unixfd;
267     
268     assert(newmode == ISFIXWRITE);
269     
270     if (p->isb_flags & ISB_RFIXED) {    
271         _isdisk_unfix(p);
272         return (_isdisk_fix(fcb, unixfd, blkno, ISFIXWRITE));
273     }
274     else
275         return (p);
276 }
277
278 void
279 _isdisk_sync()
280 {
281     extern time_t _istimeget();
282     register Bufhdr *p;
283     struct dlink           *e;
284     
285     while ((e = _isdln_first(pchangl)) != pchangl) {
286         p = GETBASE(e,bufhdr,isb_aclist);  /* Get pointer to bufhdr */
287         assert(p->isb_flags & ISB_CHANGE);
288         assert((p->isb_flags & ISB_FIXED)==0);
289         _flush1buffer(p);
290     }
291 }
292
293 void
294 _isdisk_inval()
295 {
296     extern time_t _istimeget();
297     register Bufhdr *p;
298     struct dlink           *e;
299     
300     /* ensure pavail is initialized before using it */
301
302     if (pavail->dln_forward == 0) {
303             _isdln_makeempty(pavail);
304     }
305
306     e = pavail;
307
308     while ((e = _isdln_prev(e)) != pavail) {
309         p = GETBASE(e,bufhdr,isb_aclist);  /* Get pointer to bufhdr */
310     
311         if ((p->isb_flags & ISB_READ) == 0)  
312             break;
313
314         _isdln_remove(&p->isb_hash);
315         p->isb_flags = ISB_NODATA;           /* Mark as no data in the buffer */
316     }
317 }
318
319
320 #if ISDEBUG
321 _isdisk_dumphd()
322 {
323     register Bufhdr *p;
324     int                     i;
325     
326     (void)printf("\nInd isfd   blkno mode temp oldcopy\n");
327     for (p = bufhdrs, i = 0; i < ISMAXBUFFERS; p++,i++)
328         if (p->isb_flags != ISB_NODATA)
329             (void) printf("%3d: %3d  %6d   %2x     %3d\n",i,
330                           _isfd_getisfd(p->isb_pisfd),
331                           p->isb_blkno,p->isb_flags,
332                           p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
333 }
334
335 aclistdump(lh)
336     struct dlink           *lh;
337 {
338     register Bufhdr *p;
339     struct dlink           *e;
340     
341     for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
342         p = GETBASE(e,bufhdr,isb_aclist);  /* Get pointer to bufhdr */
343         (void) printf("%3d: %3d  %6d   %2x     %3d\n",p-bufhdrs,
344                       _isfd_getisfd(p->isb_pisfd),
345                       p->isb_blkno,p->isb_flags,
346                       p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
347     }
348 }
349
350 flistdump(lh)
351     struct dlink           *lh;
352 {
353     register Bufhdr *p;
354     struct dlink           *e;
355     
356     for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
357         p = GETBASE(e,bufhdr,isb_flist);  /* Get pointer to bufhdr */
358         (void) printf("%3d: %3d  %6d   %2x     %3d\n",p-bufhdrs,
359                       _isfd_getisfd(p->isb_pisfd),
360                       p->isb_blkno,p->isb_flags,
361                       p->isb_oldcopy?(p->isb_oldcopy - bufhdrs):-1);
362     }
363 }
364
365 #endif
366
367
368 /*------------------------ Local functions ---------------------------------*/
369
370 Static void
371 _disk_init()
372 {
373     static Bool  initialized = FALSE;
374     register int        i;
375     
376     if (initialized == TRUE)
377         return;
378
379     initialized = TRUE;
380     
381     /* Initialize hash queue list heads. */
382     for (i = 0; i < ISHASHHDRS; i++) {
383         _isdln_makeempty(hashhdrs+i);
384     }
385
386     /* initialize pavail, pchangel, and pfixl lists to empty. */
387
388     _isdln_makeempty(pavail);
389     _isdln_makeempty(pchangl);
390     _isdln_makeempty(pfixl);
391     
392     /* Link all buffers into pavail list. */
393     for (i = 0; i < ISMAXBUFFERS; i++) {
394         bufhdrs[i].isb_buffer = _ismalloc(ISPAGESIZE);
395         _isdln_append(pavail,&bufhdrs[i].isb_aclist);
396         availn++;
397     }
398     
399     /* Set maxavailn and minavailn. */
400     minavailn = (ISMAXBUFFERS * MINAVAILN) / 100;
401     maxavailn = (ISMAXBUFFERS * MAXAVAILN) / 100;
402 }
403
404 /* _getavail() - get available buffer in disk */
405 Static Bufhdr *
406 _getavail()
407 {
408     register Bufhdr *p;
409     register struct dlink  *q;
410     
411     if ((q = _isdln_first(pavail)) == pavail) {
412         _isfatal_error("No buffer in pool available");
413     }
414     
415     p = GETBASE(q,bufhdr,isb_aclist);
416     
417     if (p->isb_flags & ISB_READ) {           /* Remove from hash queue */
418         _isdln_remove(&p->isb_hash);
419         p->isb_flags = ISB_NODATA;           /* Mark as no data in the buffer */
420     }
421     
422     return ((Bufhdr *) p);
423 }
424
425 /* _findblock() - Find block in buffer pool */
426 Static Bufhdr *
427 _findblock(fcb, unixfd, blkno)
428     Fcb         *fcb;
429     int         unixfd;
430     Blkno       blkno;
431 {
432     register Bufhdr *p;
433     struct dlink           *lh, *e;
434     int                    hashval;
435     
436     hashval = __hashblkno(fcb,blkno);
437     
438     lh = hashhdrs + hashval;                 /* lh is list head */
439     for (e = _isdln_first(lh); e != lh; e = _isdln_next(e)) {
440         p = GETBASE(e,bufhdr,isb_hash);  /* Get pointer to bufhdr */
441         if (p->isb_blkno == blkno && p->isb_fcb == fcb && p->isb_unixfd == unixfd) {
442             assert(p->isb_flags != ISB_NODATA); 
443             return(p);
444         }
445     }
446     
447     return (NULL);
448 }
449
450 /* _commit1buffer() - Commit changes to buffer */
451 Static void
452 _commit1buffer(p)
453     register Bufhdr     *p;
454 {
455     assert(p->isb_flags & ISB_WFIXED);       /* Fixed for read buffers should */
456     /* go through _isdisk_unfix() */
457     
458     /* Free old permanent buffer if any exists. */
459     if (p->isb_oldcopy) {
460         _makenodata(p->isb_oldcopy);         /* Make this buffer available */
461     }
462     
463     /* Remove buffer from list of fixed buffers. */
464     /* Append buffer to list of changed buffers. */
465     _isdln_remove(&p->isb_flist);
466     _isdln_append(pchangl,&p->isb_aclist);
467     p->isb_flags &= ~ISB_FIXED;
468     p->isb_flags |= ISB_CHANGE;
469 }
470
471 /* _rollback1buffer() - Rollback changes to buffer */
472 Static void
473 _rollback1buffer(p)
474     register Bufhdr     *p;
475 {
476     register Bufhdr     *p2;
477     
478     assert(p->isb_flags & ISB_WFIXED);       /* Fixed for read buffers should */
479     /* go through _isdisk_unfix() */
480     
481     /* Re-install old copy if that exists. */
482     if ((p2 = p->isb_oldcopy) != NULL) {
483         if (p2->isb_flags & ISB_CHANGE) {
484             _isdln_append(pchangl,&p2->isb_aclist);
485         }
486         else {
487             _isdln_append(pavail,&p2->isb_aclist);
488             availn++;
489         }
490         p2->isb_flags &= ~ISB_OLDCOPY;       /* Clear bit */
491         
492         /* See implementation of _isdln_append() that this will work. */
493         _isdln_append(&p->isb_hash,&p2->isb_hash); /* Insert into hash list */
494     }   
495     
496     
497     _isdln_remove(&p->isb_hash);             /* Remove bufer from hash list */
498     _isdln_remove(&p->isb_flist);            /* Remove bufer from pfixl */
499     _makenodata(p);                          /* Make this buffer available */
500 }
501
502 /* _makenodata() - make buffer available with no data in it*/
503 Static void
504 _makenodata(p)
505     register Bufhdr     *p;
506 {
507     assert(p->isb_flags & ISB_READ);
508     
509     p->isb_flags = ISB_NODATA;
510     _isdln_insert(pavail,&p->isb_aclist);
511     availn++;
512 }
513
514 /* _flush1buffer() - flush buffer to disk */
515 Static void
516 _flush1buffer(p)
517     register Bufhdr     *p;
518 {
519     assert(p->isb_flags & ISB_CHANGE);
520     
521     _isseekpg(p->isb_unixfd, p->isb_blkno);
522     _iswritepg(p->isb_unixfd, p->isb_buffer);
523     
524     p->isb_flags &= ~ISB_CHANGE;             /* clear change flag */
525     
526     _isdln_remove(&p->isb_aclist);           /* Remove from pchangl */
527     _isdln_append(pavail,&p->isb_aclist);    /* Append to pavail */
528     availn++;
529 }