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