grrr...fix reverse chronological order
[dragonfly.git] / lib / libcr / db / mpool / mpool.libtp
1 /******************************************************************************
2
3 VERSION $FreeBSD: src/lib/libc/db/mpool/mpool.libtp,v 1.4 1999/08/27 23:58:23 peter Exp $
4 VERSION $DragonFly: src/lib/libcr/db/mpool/Attic/mpool.libtp,v 1.2 2003/06/17 04:26:42 dillon Exp $
5 PACKAGE:        User Level Shared Memory Manager
6
7 DESCRIPTION:    
8         This package provides a buffer pool interface implemented as
9         a collection of file pages mapped into shared memory.
10
11         Based on Mark's buffer manager
12
13 ROUTINES: 
14     External
15         buf_alloc
16         buf_flags
17         buf_get
18         buf_init
19         buf_last
20         buf_open
21         buf_pin
22         buf_sync
23         buf_unpin
24     Internal
25         bf_assign_buf
26         bf_fid_to_fd
27         bf_newbuf
28         bf_put_page
29         
30
31 ******************************************************************************/
32 #include        <sys/types.h>
33 #include        <assert.h>
34 #include        <sys/file.h>
35 #include        <sys/stat.h>
36 #include        <stdio.h>
37 #include        <errno.h>
38 #include        "list.h"
39 #include        "user.h"
40 #include        "txn_sys.h"
41 #include        "buf.h"
42 #include        "semkeys.h"
43 #include        "error.h"
44
45 /*
46     we need to translate between some type of file id that the user 
47     process passes and a file descriptor.  For now, it's a nop.
48 */
49 #define GET_MASTER      get_sem ( buf_spinlock )
50 #define RELEASE_MASTER  release_sem ( buf_spinlock )
51
52 #define LRUID   *buf_lru
53 #define LRUP    (bufhdr_table+*buf_lru)
54 #define MRU     bufhdr_table[*buf_lru].lru.prev
55
56 /* Global indicator that you have started reusing buffers */
57 int     do_statistics = 0;
58 /*
59     Process Statics (pointers into shared memory)
60 */
61 static  BUF_T   *buf_table = 0;
62 static  BUFHDR_T        *bufhdr_table;
63 static  int     *buf_hash_table;
64 static  int     *buf_lru;               /* LRU is the free list */
65 static  int     buf_spinlock;
66 static  FINFO_T *buf_fids;
67 static  int     *buf_sp;                /* Pointer to string free space */
68 static  char    *buf_strings;
69
70 /* Process Local FID->FD table */
71 static  int     fds[NUM_FILE_ENTRIES];
72
73 /* Static routines */
74 static  BUFHDR_T        *bf_assign_buf();
75 static  int             bf_fid_to_fd();
76 static  BUFHDR_T        *bf_newbuf();
77 static  int             bf_put_page();
78
79 /*
80     Return  0 on success
81             1 on failure
82 */
83 extern int
84 buf_init ( )
85 {
86     ADDR_T      buf_region;
87     BUFHDR_T    *bhp;
88     int         i;
89     int         ref_count;
90     int         *spinlockp;
91
92     /*
93         Initialize Process local structures
94     */
95     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
96         fds[i] = -1;
97     }
98
99     buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM,
100                                  BUF_REGION_SIZE, &ref_count );
101     if ( !buf_region ) {
102         return (1);
103     }
104     error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region,
105                     BUF_REGION_NUM, BUF_REGION_SIZE );
106
107     buf_table = (BUF_T *)buf_region;
108     bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS);
109     buf_hash_table = (int *)(bufhdr_table + NUM_BUFS);
110     buf_lru = buf_hash_table + NUMTABLE_ENTRIES;
111     spinlockp = buf_lru + 1;
112     buf_fids = (FINFO_T *)(spinlockp+1);
113     buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES);
114     buf_strings = (char *)(buf_sp + 1);
115
116     /* Create locking spinlock (gets creating holding the lock) */
117     buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 );
118     if ( buf_spinlock < 0 )  {
119         return(1);
120     }
121     if ( ref_count <= 1 ) {
122         *spinlockp = buf_spinlock;
123
124         /* Now initialize the buffer manager */
125
126         /* 1. Free list */
127         *buf_lru = 0;
128
129         /* 2. Buffer headers */
130         for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) {
131                 bhp->lru.next = i+1;
132                 bhp->lru.prev = i-1;
133                 bhp->flags = 0;                         /* All Flags off */
134                 bhp->refcount = 0;
135                 bhp->wait_proc = -1;                    /* No sleepers */
136                 LISTPE_INIT ( hash, bhp, i );           /* Hash chains */
137         }
138         bufhdr_table[0].lru.prev = NUM_BUFS-1;
139         bufhdr_table[NUM_BUFS-1].lru.next = 0;
140
141         /* 3. Hash Table */
142         for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) {
143                 buf_hash_table[i] = NUM_BUFS;
144         }
145
146         /* 4. File ID Table */
147         for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
148                 buf_fids[i].offset = -1;
149                 buf_fids[i].npages = -1;
150                 buf_fids[i].refcount = 0;
151         }
152
153         /* 5. Free String Pointer */
154         *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES);
155         if (RELEASE_MASTER) {
156                 return(1);
157         }
158         error_log0 ( "Initialized buffer region\n" );
159     } 
160     return (0);
161 }
162
163 extern  void
164 buf_exit()
165 {
166     int ref;
167     int i;
168
169     /* Flush Buffer Pool on Exit */
170     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
171         if ( fds[i] != -1 ) {
172                 close ( fds[i] );
173         }
174     }
175     if ( buf_table ) {
176         detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref );
177     }
178     return;
179 }
180
181 /*
182         We need an empty buffer.  Find the LRU unpinned NON-Dirty page.
183 */
184 static BUFHDR_T *
185 bf_newbuf()
186 {
187     int         fd;
188     int         lruid;
189     int         nbytes;
190     int         ndx;
191     BUFHDR_T    *bhp;
192
193     lruid = LRUID;
194     for ( bhp = LRUP; 
195           bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS); 
196           bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) {
197
198         if ( bhp->lru.next == lruid ) {
199                 /* OUT OF BUFFERS */
200                 error_log1 ( "All buffers are pinned.  %s\n",
201                                 "Unable to grant buffer request" );
202                 return(NULL);
203         }
204     }
205     /* BHP can be used */
206     if ( bhp->flags & BUF_DIRTY ) {
207         do_statistics = 1;
208         /* 
209             MIS  Check for log flushed appropriately
210         */
211         fd = bf_fid_to_fd(bhp->id.file_id);
212         if ( fd == -1 ) {
213             error_log1 ("Invalid fid %d\n", bhp->id.file_id);
214             return(NULL);
215         }
216         if ( bf_put_page(fd, bhp) < 0 ) {
217             return(NULL);
218         }
219     }
220     /* Update Hash Pointers */
221     ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id );
222     LISTP_REMOVE(bufhdr_table, hash, bhp);
223     if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) {
224         if ( bhp->hash.next != (bhp-bufhdr_table) ) {
225                 buf_hash_table[ndx] = bhp->hash.next;
226         } else {
227                 buf_hash_table[ndx] = NUM_BUFS;
228         }
229     }
230     INIT_BUF(bhp); 
231
232     return(bhp);
233 }
234 /*
235     buf_alloc
236
237     Add a page to a file and return a buffer for it.
238
239 */
240 ADDR_T
241 buf_alloc ( fid, new_pageno )
242 int     fid;
243 int     *new_pageno;
244 {
245         BUFHDR_T        *bhp;
246         int     fd;
247         int     len;
248         int     ndx;
249         OBJ_T   fobj;
250
251         if (GET_MASTER) {
252                 return(NULL);
253         }
254         if ( buf_fids[fid].npages == -1 ) {
255             /* initialize npages field */
256             fd = bf_fid_to_fd ( fid );
257         }
258         assert (fid < NUM_FILE_ENTRIES);
259
260         *new_pageno = buf_fids[fid].npages;
261         if ( *new_pageno == -1 ) {
262             RELEASE_MASTER;
263             return ( NULL );
264         }
265         buf_fids[fid].npages++;
266         ndx = BUF_HASH ( fid, *new_pageno );
267         fobj.file_id = fid;
268         fobj.obj_id  = *new_pageno;
269         bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len );
270         if ( RELEASE_MASTER ) {
271                 /* Memory leak */
272                 return(NULL);
273         }
274         if ( bhp ) {
275             return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
276         } else {
277             return ( NULL );
278         }
279 }
280
281
282 /*
283         Buffer Flags
284         BF_DIRTY                Mark page as dirty
285         BF_EMPTY                Don't initialize page, just get buffer
286         BF_PIN                  Retrieve with pin 
287
288 MIS
289 Might want to add a flag that sets an LSN for this buffer is the
290 DIRTY flag is set
291
292 Eventually, you may want a flag that indicates the I/O and lock
293 request should be shipped off together, but not for now.
294 */
295 extern ADDR_T
296 buf_get ( file_id, page_id, flags, len )
297 int     file_id;
298 int     page_id;
299 u_long  flags;
300 int     *len;           /* Number of bytes read into buffer */
301 {
302         BUFHDR_T        *bhp;
303         int             bufid;
304         int             fd;
305         int             ndx;
306         int             next_bufid;
307         int             stat;
308         OBJ_T           fobj;   
309
310         ndx = BUF_HASH ( file_id, page_id );
311         fobj.file_id = (long) file_id;
312         fobj.obj_id = (long) page_id;
313         if ( GET_MASTER ) {
314                 return(NULL);
315         }
316         /*
317                 This could be a for loop, but we lose speed
318                 by making all the cases general purpose so we
319                 optimize for the no-collision case. 
320         */
321         bufid = buf_hash_table[ndx]; 
322         if ( bufid < NUM_BUFS ) {
323             for ( bhp = bufhdr_table+bufid; 
324                   !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID);
325                   bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) {
326
327                 if ( bhp->hash.next == bufid ) {
328                     goto not_found;
329                 }
330             }
331 /* found */
332             if ( flags & BF_PIN ) {
333                     bhp->flags |= BUF_PINNED;
334                     bhp->refcount++;
335 #ifdef PIN_DEBUG
336         fprintf(stderr, "buf_get: %X PINNED (%d)\n", 
337                         buf_table + (bhp-bufhdr_table), bhp->refcount);
338 #endif
339             }
340             if ( flags & BF_DIRTY ) {
341                     bhp->flags |= BUF_DIRTY;
342             }
343
344             while ( bhp->flags & BUF_IO_IN_PROGRESS ) {
345                 /* MIS -- eventually err check here */
346 #ifdef DEBUG
347                 printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc,
348                         my_txnp - txn_table);
349 #endif
350 #ifdef WAIT_STATS
351                 buf_waits++;
352 #endif
353                 stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock );
354                 if ( stat ) {
355                         /* Memory leak */
356                         return(NULL);
357                 }
358                 if (!( bhp->flags & BUF_IO_IN_PROGRESS) &&
359                     (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) {
360                         if (RELEASE_MASTER)
361                                 return(NULL);
362                         return(buf_get ( file_id, page_id, flags, len ));
363                 }
364             }
365             MAKE_MRU( bhp );
366             *len = BUFSIZE;
367         } else {
368 not_found:
369             /* If you get here, the page isn't in the hash table */
370             bhp = bf_assign_buf ( ndx, &fobj, flags, len );
371         }
372         /* Common code between found and not found */
373
374         if ( bhp && bhp->flags & BUF_NEWPAGE ) {
375             *len = 0;
376         }
377         if (RELEASE_MASTER){
378                 /* Memory leak */
379                 return(NULL);
380         }
381         if ( bhp ) {
382             return ((ADDR_T)(buf_table+(bhp-bufhdr_table)));
383         } else {
384             return ( NULL );
385         }
386 }
387
388 /*
389         MIS - do I want to add file links to buffer pool?
390 */
391 extern int
392 buf_sync ( fid, close )
393 int     fid;
394 int     close;          /* should we dec refcount and possibly
395                            invalidate all the buffers */
396 {
397     int i;
398     int fd;
399     int invalidate;
400     BUFHDR_T    *bhp;
401
402     if ( (fd = bf_fid_to_fd ( fid )) < 0 ) {
403         return(1);
404     }
405     if (GET_MASTER) {
406         return(1);
407     }
408     invalidate = (buf_fids[fid].refcount == 1 && close);
409     if ( invalidate )
410         for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
411             if (bhp->id.file_id == fid) {
412                 if ((bhp->flags & BF_DIRTY) && (bf_put_page( fd, bhp ) < 0)) {
413                         return(1);
414                 }
415                 bhp->id.file_id = -1;
416             }
417         }
418     if (invalidate || close)
419         buf_fids[fid].refcount--;
420
421     if (RELEASE_MASTER) {
422         return(1);
423     }
424     return(0);
425
426
427 }
428
429 extern int
430 buf_flags ( addr, set_flags, unset_flags )
431 ADDR_T  addr;
432 u_long  set_flags;
433 u_long  unset_flags;
434 {
435     int         bufid;
436     BUFHDR_T    *bhp;
437
438 #ifdef PIN_DEBUG
439         fprintf(stderr, "buf_flags: %X setting %s%s%s%s%s releasing %s%s%s%s%s\n",
440             addr, 
441             set_flags&BUF_DIRTY ? "DIRTY " : "", 
442             set_flags&BUF_VALID ? "VALID " : "", 
443             set_flags&BUF_PINNED ? "PINNED " : "", 
444             set_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 
445             set_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 
446             set_flags&BUF_NEWPAGE ? "NEWPAGE " : "", 
447             unset_flags&BUF_DIRTY ? "DIRTY " : "", 
448             unset_flags&BUF_VALID ? "VALID " : "", 
449             unset_flags&BUF_PINNED ? "PINNED " : "", 
450             unset_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 
451             unset_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 
452             unset_flags&BUF_NEWPAGE ? "NEWPAGE " : "" );
453 #endif
454     if (!ADDR_OK(addr)) {
455         error_log1 ( "buf_pin: Invalid Buffer Address %x\n", addr );
456         return(1);
457     }
458     bufid = ((BUF_T *)addr) - buf_table;
459     assert ( bufid < NUM_BUFS);
460     bhp = &bufhdr_table[bufid];
461     if (GET_MASTER) {
462         return(1);
463     }
464     bhp->flags |= set_flags;
465     if ( set_flags & BUF_PINNED ) {
466         bhp->refcount++;
467     }
468     if ( set_flags & BUF_DIRTY ) {
469         unset_flags |= BUF_NEWPAGE;
470     }
471
472     if ( unset_flags & BUF_PINNED ) {
473         bhp->refcount--;
474         if ( bhp->refcount ) {
475                 /* Turn off pin bit so it doesn't get unset */
476                 unset_flags &= ~BUF_PINNED;
477         }
478     }
479     bhp->flags &= ~unset_flags;
480     MAKE_MRU(bhp);
481     if (RELEASE_MASTER) {
482         return(1);
483     }
484     return(0);
485 }
486
487 /*
488         Take a string name and produce an fid.
489
490         returns -1 on error
491
492         MIS -- this is a potential problem -- you keep actual names
493                 here -- what if people run from different directories?
494 */
495 extern  int
496 buf_name_lookup ( fname )
497 char    *fname;
498 {
499     int i;
500     int fid;
501     int ndx;
502
503     fid = -1;
504     if (GET_MASTER) {
505             return(-1);
506     }
507     for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) {
508         if ( buf_fids[i].offset == -1 ) {
509                 fid = i;
510         } else {
511                 if (!strcmp (fname, buf_strings+buf_fids[i].offset)) {
512                         if (RELEASE_MASTER) {
513                                 return(-1);
514                         }
515                         buf_fids[i].refcount++;
516                         return(i);
517                 }
518         }
519     }
520     if ( fid == -1 ) {
521         error_log0 ( "No more file ID's\n" );
522     } else {
523         ndx = *buf_sp - strlen(fname) - 1;
524         if ( ndx < 0 ) {
525             error_log0 ( "Out of string space\n" );
526             fid = -1;
527         } else {
528             *buf_sp = ndx;
529             strcpy ( buf_strings+ndx, fname );
530             buf_fids[fid].offset = ndx;
531         }
532         buf_fids[fid].refcount = 1;
533     }
534     if (RELEASE_MASTER) {
535         return(-1);
536     }
537     return(fid);
538 }
539
540 static  int
541 bf_fid_to_fd ( fid ) 
542 int     fid;
543 {
544         struct stat sbuf;
545
546         assert ( (fid < NUM_FILE_ENTRIES) && (buf_fids[fid].offset != -1) );
547         if ( fds[fid] != -1 ) {
548             return(fds[fid]);
549
550         }
551         fds[fid] = open ( buf_strings+buf_fids[fid].offset, O_RDWR|O_CREAT, 
552                           0666 );
553         if ( fds[fid] < 0 ) {
554             error_log3 ( "Error Opening File %s FID: %d FD: %d.  Errno = %d\n", 
555                             buf_strings+buf_fids[fid].offset, fid, fds[fid], 
556                             errno );
557             return(-1);
558         }
559         error_log3 ( "Opening File %s FID: %d FD: %d\n", 
560                         buf_strings+buf_fids[fid].offset, fid, fds[fid] );
561         if ( buf_fids[fid].npages == -1 ) {
562                 /* Initialize the npages field */
563                 if ( fstat ( fds[fid], &sbuf ) ) {
564                     error_log3 ( "Error Fstating %s FID: %d.  Errno = %d\n", 
565                                 buf_strings+buf_fids[fid].offset, fid, errno );
566                 } else {
567                     buf_fids[fid].npages = ( sbuf.st_size / BUFSIZE );
568                 }
569         }
570
571         return ( fds[fid] );
572 }
573
574 static int
575 bf_put_page ( fd, bhp ) 
576 int     fd;
577 BUFHDR_T        *bhp;
578 {
579         int     nbytes;
580
581         assert ( (bhp-bufhdr_table) < NUM_BUFS );
582         if ( lseek ( fd, bhp->id.obj_id << BUFSHIFT, L_SET ) < 0 ) {
583             return(-1);
584         }
585         bhp->flags |= BUF_IO_IN_PROGRESS;
586         if (RELEASE_MASTER) {
587             return(-1);
588         }
589         nbytes = write(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
590         if (GET_MASTER) {
591             return(-2);
592         }
593         if ( nbytes < 0 ) {
594                 error_log1 ("Write failed with error code %d\n", errno);
595                 return(-1);
596         } else if ( nbytes != BUFSIZE ) {
597                 error_log1 ("Short write: %d bytes of %d\n", nbytes, BUFSIZE );
598         }
599         bhp->flags &= ~(BUF_DIRTY|BUF_IO_IN_PROGRESS);
600         return (0);
601 }
602
603 static BUFHDR_T *
604 bf_assign_buf ( ndx, obj, flags, len )
605 int     ndx;
606 OBJ_T   *obj;
607 u_long  flags;
608 int     *len;           /* Number of bytes read */
609 {
610     BUFHDR_T    *bhp;
611     int         fd;
612
613     assert ( obj->file_id < NUM_FILE_ENTRIES );
614     bhp = bf_newbuf();
615     if ( !bhp ) {
616         return(NULL);
617     }
618     OBJ_ASSIGN ( (*obj), bhp->id );
619     if ( buf_hash_table[ndx] >= NUM_BUFS ) {
620         buf_hash_table[ndx] = bhp-bufhdr_table;
621     } else {
622         LISTPE_INSERT ( bufhdr_table, hash, bhp, buf_hash_table[ndx] );
623     }
624
625     bhp->flags |= BUF_VALID;
626     if ( flags & BF_PIN ) {
627         bhp->flags |= BUF_PINNED;
628         bhp->refcount++;
629 #ifdef PIN_DEBUG
630         fprintf(stderr, "bf_assign_buf: %X PINNED (%d)\n", 
631                 buf_table + (bhp-bufhdr_table), bhp->refcount);
632 #endif
633     }
634     fd = bf_fid_to_fd(obj->file_id);
635     if ( fd == -1 ) {
636         error_log1 ("Invalid fid %d\n", obj->file_id);
637         bhp->flags |= ~BUF_IO_ERROR;
638         return(NULL);
639     }
640     if ( obj->obj_id >= buf_fids[obj->file_id].npages) {
641         buf_fids[obj->file_id].npages = obj->obj_id+1;
642         *len = 0;
643     } else if ( flags & BF_EMPTY ) {
644         *len = 0;
645     } else {
646         bhp->flags |= BUF_IO_IN_PROGRESS;
647         if (RELEASE_MASTER) {
648                 return(NULL);
649         }
650         if ( lseek ( fd, obj->obj_id << BUFSHIFT, L_SET ) < -1 ) {
651             error_log2 ("Unable to perform seek on file: %d  to page %d",
652                         obj->file_id, obj->obj_id );
653             bhp->flags &= ~BUF_IO_IN_PROGRESS;
654             bhp->flags |= ~BUF_IO_ERROR;
655             return(NULL);
656         }
657         *len = read(fd, buf_table[bhp-bufhdr_table], BUFSIZE);
658         if ( *len < 0 ) {
659             error_log2 ("Unable to perform read on file: %d  to page %d",
660                         obj->file_id, obj->obj_id );
661             bhp->flags &= ~BUF_IO_IN_PROGRESS;
662             bhp->flags |= ~BUF_IO_ERROR;
663             return(NULL);
664         } 
665         if (GET_MASTER) {
666                 return(NULL);
667         }
668         bhp->flags &= ~BUF_IO_IN_PROGRESS;
669         if ( bhp->wait_proc != -1 ) {
670             /* wake up waiter and anyone waiting on it */
671 #ifdef DEBUG
672             printf("Waking transaction %d due to completed I/O\n", 
673                 bhp->wait_proc);
674 #endif
675             proc_wake_id ( bhp->wait_proc );
676             bhp->wait_proc = -1;
677         }
678         MAKE_MRU(bhp);
679     }
680
681     if ( flags & BF_DIRTY ) {
682         bhp->flags |= BUF_DIRTY;
683     } else if ( *len < BUFSIZE ) {
684         bhp->flags |= BUF_NEWPAGE;
685     }
686     return ( bhp );
687 }
688
689 int
690 buf_last ( fid )
691 int     fid;
692 {
693         int     val;
694
695         if (GET_MASTER) {
696                 return(-1);
697         }
698         assert ( fid < NUM_FILE_ENTRIES );
699         if ( buf_fids[fid].npages == -1 ) {
700             /* initialize npages field */
701             (void) bf_fid_to_fd ( fid );
702         }
703         val = buf_fids[fid].npages;     
704         if ( val ) {
705                 val--;                  /* Convert to page number */
706         }
707         if (RELEASE_MASTER) {
708                 return(-1);
709         }
710         return(val);
711 }
712
713 #ifdef DEBUG
714 extern void
715 buf_dump ( id, all )
716 int     id;
717 int     all;
718 {
719         int i;
720         BUFHDR_T        *bhp;
721
722         printf ( "LRU + %d\n", *buf_lru );
723         if ( all ) {
724             printf("ID\tFID\tPID\tLNEXT\tLPREV\tHNEXT\tHPREV\tSLEEP\tFLAG\tREFS\n");
725             for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) {
726                     printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
727                         bhp->id.file_id, bhp->id.obj_id,
728                         bhp->lru.next, bhp->lru.prev,
729                         bhp->hash.next, bhp->hash.prev,
730                         bhp->wait_proc, bhp->flags, bhp->refcount );
731             }
732         } else {
733                 if ( id >= NUM_BUFS ) {
734                         printf ( "Buffer ID (%d) too high\n", id );
735                         return;
736                 }
737                 bhp = bufhdr_table+id;
738                 printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i,
739                     bhp->id.file_id, bhp->id.obj_id,
740                     bhp->lru.next, bhp->lru.prev,
741                     bhp->hash.next, bhp->hash.prev,
742                     bhp->wait_proc, bhp->flags, bhp->refcount );
743         }
744         return;
745 }
746 #endif
747