114272Spst/****************************************************************************** 214272Spst 350476SpeterVERSION $FreeBSD$ 414272SpstPACKAGE: User Level Shared Memory Manager 514272Spst 614272SpstDESCRIPTION: 714272Spst This package provides a buffer pool interface implemented as 814272Spst a collection of file pages mapped into shared memory. 914272Spst 1014272Spst Based on Mark's buffer manager 1114272Spst 1214272SpstROUTINES: 1314272Spst External 1414272Spst buf_alloc 1514272Spst buf_flags 1614272Spst buf_get 1714272Spst buf_init 1814272Spst buf_last 1914272Spst buf_open 2014272Spst buf_pin 2114272Spst buf_sync 2214272Spst buf_unpin 2314272Spst Internal 2414272Spst bf_assign_buf 2514272Spst bf_fid_to_fd 2614272Spst bf_newbuf 2714272Spst bf_put_page 2814272Spst 2914272Spst 3014272Spst******************************************************************************/ 3114272Spst#include <sys/types.h> 3214272Spst#include <assert.h> 3314272Spst#include <sys/file.h> 3414272Spst#include <sys/stat.h> 3514272Spst#include <stdio.h> 3614272Spst#include <errno.h> 3714272Spst#include "list.h" 3814272Spst#include "user.h" 3914272Spst#include "txn_sys.h" 4014272Spst#include "buf.h" 4114272Spst#include "semkeys.h" 4214272Spst#include "error.h" 4314272Spst 4414272Spst/* 4514272Spst we need to translate between some type of file id that the user 4614272Spst process passes and a file descriptor. For now, it's a nop. 4714272Spst*/ 4814272Spst#define GET_MASTER get_sem ( buf_spinlock ) 4914272Spst#define RELEASE_MASTER release_sem ( buf_spinlock ) 5014272Spst 5114272Spst#define LRUID *buf_lru 5214272Spst#define LRUP (bufhdr_table+*buf_lru) 5314272Spst#define MRU bufhdr_table[*buf_lru].lru.prev 5414272Spst 5514272Spst/* Global indicator that you have started reusing buffers */ 5614272Spstint do_statistics = 0; 5714272Spst/* 5814272Spst Process Statics (pointers into shared memory) 5914272Spst*/ 6014272Spststatic BUF_T *buf_table = 0; 6114272Spststatic BUFHDR_T *bufhdr_table; 6214272Spststatic int *buf_hash_table; 6314272Spststatic int *buf_lru; /* LRU is the free list */ 6414272Spststatic int buf_spinlock; 6514272Spststatic FINFO_T *buf_fids; 6614272Spststatic int *buf_sp; /* Pointer to string free space */ 6714272Spststatic char *buf_strings; 6814272Spst 6914272Spst/* Process Local FID->FD table */ 7014272Spststatic int fds[NUM_FILE_ENTRIES]; 7114272Spst 7214272Spst/* Static routines */ 7314272Spststatic BUFHDR_T *bf_assign_buf(); 7414272Spststatic int bf_fid_to_fd(); 7514272Spststatic BUFHDR_T *bf_newbuf(); 7614272Spststatic int bf_put_page(); 7714272Spst 7814272Spst/* 7914272Spst Return 0 on success 8014272Spst 1 on failure 8114272Spst*/ 8214272Spstextern int 8314272Spstbuf_init ( ) 8414272Spst{ 8514272Spst ADDR_T buf_region; 8614272Spst BUFHDR_T *bhp; 8714272Spst int i; 8814272Spst int ref_count; 8914272Spst int *spinlockp; 9014272Spst 9114272Spst /* 9214272Spst Initialize Process local structures 9314272Spst */ 9414272Spst for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 9514272Spst fds[i] = -1; 9614272Spst } 9714272Spst 9814272Spst buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM, 9914272Spst BUF_REGION_SIZE, &ref_count ); 10014272Spst if ( !buf_region ) { 10114272Spst return (1); 10214272Spst } 10314272Spst error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region, 10414272Spst BUF_REGION_NUM, BUF_REGION_SIZE ); 10514272Spst 10614272Spst buf_table = (BUF_T *)buf_region; 10714272Spst bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS); 10814272Spst buf_hash_table = (int *)(bufhdr_table + NUM_BUFS); 10914272Spst buf_lru = buf_hash_table + NUMTABLE_ENTRIES; 11014272Spst spinlockp = buf_lru + 1; 11114272Spst buf_fids = (FINFO_T *)(spinlockp+1); 11214272Spst buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES); 11314272Spst buf_strings = (char *)(buf_sp + 1); 11414272Spst 11514272Spst /* Create locking spinlock (gets creating holding the lock) */ 11614272Spst buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 ); 11714272Spst if ( buf_spinlock < 0 ) { 11814272Spst return(1); 11914272Spst } 12014272Spst if ( ref_count <= 1 ) { 12114272Spst *spinlockp = buf_spinlock; 12214272Spst 12314272Spst /* Now initialize the buffer manager */ 12414272Spst 12514272Spst /* 1. Free list */ 12614272Spst *buf_lru = 0; 12714272Spst 12814272Spst /* 2. Buffer headers */ 12914272Spst for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) { 13014272Spst bhp->lru.next = i+1; 13114272Spst bhp->lru.prev = i-1; 13214272Spst bhp->flags = 0; /* All Flags off */ 13314272Spst bhp->refcount = 0; 13414272Spst bhp->wait_proc = -1; /* No sleepers */ 13514272Spst LISTPE_INIT ( hash, bhp, i ); /* Hash chains */ 13614272Spst } 13714272Spst bufhdr_table[0].lru.prev = NUM_BUFS-1; 13814272Spst bufhdr_table[NUM_BUFS-1].lru.next = 0; 13914272Spst 14014272Spst /* 3. Hash Table */ 14114272Spst for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) { 14214272Spst buf_hash_table[i] = NUM_BUFS; 14314272Spst } 14414272Spst 14514272Spst /* 4. File ID Table */ 14614272Spst for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 14714272Spst buf_fids[i].offset = -1; 14814272Spst buf_fids[i].npages = -1; 14914272Spst buf_fids[i].refcount = 0; 15014272Spst } 15114272Spst 15214272Spst /* 5. Free String Pointer */ 15314272Spst *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES); 15414272Spst if (RELEASE_MASTER) { 15514272Spst return(1); 15614272Spst } 15714272Spst error_log0 ( "Initialized buffer region\n" ); 15814272Spst } 15914272Spst return (0); 16014272Spst} 16114272Spst 16214272Spstextern void 16314272Spstbuf_exit() 16414272Spst{ 16514272Spst int ref; 16614272Spst int i; 16714272Spst 16814272Spst /* Flush Buffer Pool on Exit */ 16914272Spst for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 17014272Spst if ( fds[i] != -1 ) { 17114272Spst close ( fds[i] ); 17214272Spst } 17314272Spst } 17414272Spst if ( buf_table ) { 17514272Spst detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref ); 17614272Spst } 17714272Spst return; 17814272Spst} 17914272Spst 18014272Spst/* 18114272Spst We need an empty buffer. Find the LRU unpinned NON-Dirty page. 18214272Spst*/ 18314272Spststatic BUFHDR_T * 18414272Spstbf_newbuf() 18514272Spst{ 18614272Spst int fd; 18714272Spst int lruid; 18814272Spst int nbytes; 18914272Spst int ndx; 19014272Spst BUFHDR_T *bhp; 19114272Spst 19214272Spst lruid = LRUID; 19314272Spst for ( bhp = LRUP; 19414272Spst bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS); 19514272Spst bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) { 19614272Spst 19714272Spst if ( bhp->lru.next == lruid ) { 19814272Spst /* OUT OF BUFFERS */ 19914272Spst error_log1 ( "All buffers are pinned. %s\n", 20014272Spst "Unable to grant buffer request" ); 20114272Spst return(NULL); 20214272Spst } 20314272Spst } 20414272Spst /* BHP can be used */ 20514272Spst if ( bhp->flags & BUF_DIRTY ) { 20614272Spst do_statistics = 1; 20714272Spst /* 20814272Spst MIS Check for log flushed appropriately 20914272Spst */ 21014272Spst fd = bf_fid_to_fd(bhp->id.file_id); 21114272Spst if ( fd == -1 ) { 21214272Spst error_log1 ("Invalid fid %d\n", bhp->id.file_id); 21314272Spst return(NULL); 21414272Spst } 21514272Spst if ( bf_put_page(fd, bhp) < 0 ) { 21614272Spst return(NULL); 21714272Spst } 21814272Spst } 21914272Spst /* Update Hash Pointers */ 22014272Spst ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id ); 22114272Spst LISTP_REMOVE(bufhdr_table, hash, bhp); 22214272Spst if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) { 22314272Spst if ( bhp->hash.next != (bhp-bufhdr_table) ) { 22414272Spst buf_hash_table[ndx] = bhp->hash.next; 22514272Spst } else { 22614272Spst buf_hash_table[ndx] = NUM_BUFS; 22714272Spst } 22814272Spst } 22914272Spst INIT_BUF(bhp); 23014272Spst 23114272Spst return(bhp); 23214272Spst} 23314272Spst/* 23414272Spst buf_alloc 23514272Spst 23614272Spst Add a page to a file and return a buffer for it. 23714272Spst 23814272Spst*/ 23914272SpstADDR_T 24014272Spstbuf_alloc ( fid, new_pageno ) 24114272Spstint fid; 24214272Spstint *new_pageno; 24314272Spst{ 24414272Spst BUFHDR_T *bhp; 24514272Spst int fd; 24614272Spst int len; 24714272Spst int ndx; 24814272Spst OBJ_T fobj; 24914272Spst 25014272Spst if (GET_MASTER) { 25114272Spst return(NULL); 25214272Spst } 25314272Spst if ( buf_fids[fid].npages == -1 ) { 25414272Spst /* initialize npages field */ 25514272Spst fd = bf_fid_to_fd ( fid ); 25614272Spst } 25714272Spst assert (fid < NUM_FILE_ENTRIES); 25814272Spst 25914272Spst *new_pageno = buf_fids[fid].npages; 26014272Spst if ( *new_pageno == -1 ) { 26114272Spst RELEASE_MASTER; 26214272Spst return ( NULL ); 26314272Spst } 26414272Spst buf_fids[fid].npages++; 26514272Spst ndx = BUF_HASH ( fid, *new_pageno ); 26614272Spst fobj.file_id = fid; 26714272Spst fobj.obj_id = *new_pageno; 26814272Spst bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len ); 26914272Spst if ( RELEASE_MASTER ) { 27014272Spst /* Memory leak */ 27114272Spst return(NULL); 27214272Spst } 27314272Spst if ( bhp ) { 27414272Spst return ((ADDR_T)(buf_table+(bhp-bufhdr_table))); 27514272Spst } else { 27614272Spst return ( NULL ); 27714272Spst } 27814272Spst} 27914272Spst 28014272Spst 28114272Spst/* 28214272Spst Buffer Flags 28314272Spst BF_DIRTY Mark page as dirty 28414272Spst BF_EMPTY Don't initialize page, just get buffer 28514272Spst BF_PIN Retrieve with pin 28614272Spst 28714272SpstMIS 28814272SpstMight want to add a flag that sets an LSN for this buffer is the 28914272SpstDIRTY flag is set 29014272Spst 29114272SpstEventually, you may want a flag that indicates the I/O and lock 29214272Spstrequest should be shipped off together, but not for now. 29314272Spst*/ 29414272Spstextern ADDR_T 29514272Spstbuf_get ( file_id, page_id, flags, len ) 29614272Spstint file_id; 29714272Spstint page_id; 29814272Spstu_long flags; 29914272Spstint *len; /* Number of bytes read into buffer */ 30014272Spst{ 30114272Spst BUFHDR_T *bhp; 30214272Spst int bufid; 30314272Spst int fd; 30414272Spst int ndx; 30514272Spst int next_bufid; 30614272Spst int stat; 30714272Spst OBJ_T fobj; 30814272Spst 30914272Spst ndx = BUF_HASH ( file_id, page_id ); 31014272Spst fobj.file_id = (long) file_id; 31114272Spst fobj.obj_id = (long) page_id; 31214272Spst if ( GET_MASTER ) { 31314272Spst return(NULL); 31414272Spst } 31514272Spst /* 31614272Spst This could be a for loop, but we lose speed 31714272Spst by making all the cases general purpose so we 31814272Spst optimize for the no-collision case. 31914272Spst */ 32014272Spst bufid = buf_hash_table[ndx]; 32114272Spst if ( bufid < NUM_BUFS ) { 32214272Spst for ( bhp = bufhdr_table+bufid; 32314272Spst !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID); 32414272Spst bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) { 32514272Spst 32614272Spst if ( bhp->hash.next == bufid ) { 32714272Spst goto not_found; 32814272Spst } 32914272Spst } 33014272Spst/* found */ 33114272Spst if ( flags & BF_PIN ) { 33214272Spst bhp->flags |= BUF_PINNED; 33314272Spst bhp->refcount++; 33414272Spst#ifdef PIN_DEBUG 33514272Spst fprintf(stderr, "buf_get: %X PINNED (%d)\n", 33614272Spst buf_table + (bhp-bufhdr_table), bhp->refcount); 33714272Spst#endif 33814272Spst } 33914272Spst if ( flags & BF_DIRTY ) { 34014272Spst bhp->flags |= BUF_DIRTY; 34114272Spst } 34214272Spst 34314272Spst while ( bhp->flags & BUF_IO_IN_PROGRESS ) { 34414272Spst /* MIS -- eventually err check here */ 34514272Spst#ifdef DEBUG 34614272Spst printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc, 34714272Spst my_txnp - txn_table); 34814272Spst#endif 34914272Spst#ifdef WAIT_STATS 35014272Spst buf_waits++; 35114272Spst#endif 35214272Spst stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock ); 35314272Spst if ( stat ) { 35414272Spst /* Memory leak */ 35514272Spst return(NULL); 35614272Spst } 35714272Spst if (!( bhp->flags & BUF_IO_IN_PROGRESS) && 35814272Spst (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) { 35914272Spst if (RELEASE_MASTER) 36014272Spst return(NULL); 36114272Spst return(buf_get ( file_id, page_id, flags, len )); 36214272Spst } 36314272Spst } 36414272Spst MAKE_MRU( bhp ); 36514272Spst *len = BUFSIZE; 36614272Spst } else { 36714272Spstnot_found: 36814272Spst /* If you get here, the page isn't in the hash table */ 36914272Spst bhp = bf_assign_buf ( ndx, &fobj, flags, len ); 37014272Spst } 37114272Spst /* Common code between found and not found */ 37214272Spst 37314272Spst if ( bhp && bhp->flags & BUF_NEWPAGE ) { 37414272Spst *len = 0; 37514272Spst } 37614272Spst if (RELEASE_MASTER){ 37714272Spst /* Memory leak */ 37814272Spst return(NULL); 37914272Spst } 38014272Spst if ( bhp ) { 38114272Spst return ((ADDR_T)(buf_table+(bhp-bufhdr_table))); 38214272Spst } else { 38314272Spst return ( NULL ); 38414272Spst } 38514272Spst} 38614272Spst 38714272Spst/* 38814272Spst MIS - do I want to add file links to buffer pool? 38914272Spst*/ 39014272Spstextern int 39114272Spstbuf_sync ( fid, close ) 39214272Spstint fid; 39314272Spstint close; /* should we dec refcount and possibly 39414272Spst invalidate all the buffers */ 39514272Spst{ 39614272Spst int i; 39714272Spst int fd; 39814272Spst int invalidate; 39914272Spst BUFHDR_T *bhp; 40014272Spst 40114272Spst if ( (fd = bf_fid_to_fd ( fid )) < 0 ) { 40214272Spst return(1); 40314272Spst } 40414272Spst if (GET_MASTER) { 40514272Spst return(1); 40614272Spst } 40714272Spst invalidate = (buf_fids[fid].refcount == 1 && close); 40814272Spst if ( invalidate ) 40914272Spst for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) { 41014272Spst if (bhp->id.file_id == fid) { 41114272Spst if ((bhp->flags & BF_DIRTY) && (bf_put_page( fd, bhp ) < 0)) { 41214272Spst return(1); 41314272Spst } 41414272Spst bhp->id.file_id = -1; 41514272Spst } 41614272Spst } 41714272Spst if (invalidate || close) 41814272Spst buf_fids[fid].refcount--; 41914272Spst 42014272Spst if (RELEASE_MASTER) { 42114272Spst return(1); 42214272Spst } 42314272Spst return(0); 42414272Spst 42514272Spst 42614272Spst} 42714272Spst 42814272Spstextern int 42914272Spstbuf_flags ( addr, set_flags, unset_flags ) 43014272SpstADDR_T addr; 43114272Spstu_long set_flags; 43214272Spstu_long unset_flags; 43314272Spst{ 43414272Spst int bufid; 43514272Spst BUFHDR_T *bhp; 43614272Spst 43714272Spst#ifdef PIN_DEBUG 43814272Spst fprintf(stderr, "buf_flags: %X setting %s%s%s%s%s releasing %s%s%s%s%s\n", 43914272Spst addr, 44014272Spst set_flags&BUF_DIRTY ? "DIRTY " : "", 44114272Spst set_flags&BUF_VALID ? "VALID " : "", 44214272Spst set_flags&BUF_PINNED ? "PINNED " : "", 44314272Spst set_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 44414272Spst set_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 44514272Spst set_flags&BUF_NEWPAGE ? "NEWPAGE " : "", 44614272Spst unset_flags&BUF_DIRTY ? "DIRTY " : "", 44714272Spst unset_flags&BUF_VALID ? "VALID " : "", 44814272Spst unset_flags&BUF_PINNED ? "PINNED " : "", 44914272Spst unset_flags&BUF_IO_ERROR ? "IO_ERROR " : "", 45014272Spst unset_flags&BUF_IO_IN_PROGRESS ? "IO_IN_PROG " : "", 45114272Spst unset_flags&BUF_NEWPAGE ? "NEWPAGE " : "" ); 45214272Spst#endif 45314272Spst if (!ADDR_OK(addr)) { 45414272Spst error_log1 ( "buf_pin: Invalid Buffer Address %x\n", addr ); 45514272Spst return(1); 45614272Spst } 45714272Spst bufid = ((BUF_T *)addr) - buf_table; 45814272Spst assert ( bufid < NUM_BUFS); 45914272Spst bhp = &bufhdr_table[bufid]; 46014272Spst if (GET_MASTER) { 46114272Spst return(1); 46214272Spst } 46314272Spst bhp->flags |= set_flags; 46414272Spst if ( set_flags & BUF_PINNED ) { 46514272Spst bhp->refcount++; 46614272Spst } 46714272Spst if ( set_flags & BUF_DIRTY ) { 46814272Spst unset_flags |= BUF_NEWPAGE; 46914272Spst } 47014272Spst 47114272Spst if ( unset_flags & BUF_PINNED ) { 47214272Spst bhp->refcount--; 47314272Spst if ( bhp->refcount ) { 47414272Spst /* Turn off pin bit so it doesn't get unset */ 47514272Spst unset_flags &= ~BUF_PINNED; 47614272Spst } 47714272Spst } 47814272Spst bhp->flags &= ~unset_flags; 47914272Spst MAKE_MRU(bhp); 48014272Spst if (RELEASE_MASTER) { 48114272Spst return(1); 48214272Spst } 48314272Spst return(0); 48414272Spst} 48514272Spst 48614272Spst/* 48714272Spst Take a string name and produce an fid. 48814272Spst 48914272Spst returns -1 on error 49014272Spst 49114272Spst MIS -- this is a potential problem -- you keep actual names 49214272Spst here -- what if people run from different directories? 49314272Spst*/ 49414272Spstextern int 49514272Spstbuf_name_lookup ( fname ) 49614272Spstchar *fname; 49714272Spst{ 49814272Spst int i; 49914272Spst int fid; 50014272Spst int ndx; 50114272Spst 50214272Spst fid = -1; 50314272Spst if (GET_MASTER) { 50414272Spst return(-1); 50514272Spst } 50614272Spst for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { 50714272Spst if ( buf_fids[i].offset == -1 ) { 50814272Spst fid = i; 50914272Spst } else { 51014272Spst if (!strcmp (fname, buf_strings+buf_fids[i].offset)) { 51114272Spst if (RELEASE_MASTER) { 51214272Spst return(-1); 51314272Spst } 51414272Spst buf_fids[i].refcount++; 51514272Spst return(i); 51614272Spst } 51714272Spst } 51814272Spst } 51914272Spst if ( fid == -1 ) { 52014272Spst error_log0 ( "No more file ID's\n" ); 52114272Spst } else { 52214272Spst ndx = *buf_sp - strlen(fname) - 1; 52314272Spst if ( ndx < 0 ) { 52414272Spst error_log0 ( "Out of string space\n" ); 52514272Spst fid = -1; 52614272Spst } else { 52714272Spst *buf_sp = ndx; 52814272Spst strcpy ( buf_strings+ndx, fname ); 52914272Spst buf_fids[fid].offset = ndx; 53014272Spst } 53114272Spst buf_fids[fid].refcount = 1; 53214272Spst } 53314272Spst if (RELEASE_MASTER) { 53414272Spst return(-1); 53514272Spst } 53614272Spst return(fid); 53714272Spst} 53814272Spst 53914272Spststatic int 54014272Spstbf_fid_to_fd ( fid ) 54114272Spstint fid; 54214272Spst{ 54314272Spst struct stat sbuf; 54414272Spst 54514272Spst assert ( (fid < NUM_FILE_ENTRIES) && (buf_fids[fid].offset != -1) ); 54614272Spst if ( fds[fid] != -1 ) { 54714272Spst return(fds[fid]); 54814272Spst 54914272Spst } 55014272Spst fds[fid] = open ( buf_strings+buf_fids[fid].offset, O_RDWR|O_CREAT, 55114272Spst 0666 ); 55214272Spst if ( fds[fid] < 0 ) { 55314272Spst error_log3 ( "Error Opening File %s FID: %d FD: %d. Errno = %d\n", 55414272Spst buf_strings+buf_fids[fid].offset, fid, fds[fid], 55514272Spst errno ); 55614272Spst return(-1); 55714272Spst } 55814272Spst error_log3 ( "Opening File %s FID: %d FD: %d\n", 55914272Spst buf_strings+buf_fids[fid].offset, fid, fds[fid] ); 56014272Spst if ( buf_fids[fid].npages == -1 ) { 56114272Spst /* Initialize the npages field */ 56214272Spst if ( fstat ( fds[fid], &sbuf ) ) { 56314272Spst error_log3 ( "Error Fstating %s FID: %d. Errno = %d\n", 56414272Spst buf_strings+buf_fids[fid].offset, fid, errno ); 56514272Spst } else { 56614272Spst buf_fids[fid].npages = ( sbuf.st_size / BUFSIZE ); 56714272Spst } 56814272Spst } 56914272Spst 57014272Spst return ( fds[fid] ); 57114272Spst} 57214272Spst 57314272Spststatic int 57414272Spstbf_put_page ( fd, bhp ) 57514272Spstint fd; 57614272SpstBUFHDR_T *bhp; 57714272Spst{ 57814272Spst int nbytes; 57914272Spst 58014272Spst assert ( (bhp-bufhdr_table) < NUM_BUFS ); 58114272Spst if ( lseek ( fd, bhp->id.obj_id << BUFSHIFT, L_SET ) < 0 ) { 58214272Spst return(-1); 58314272Spst } 58414272Spst bhp->flags |= BUF_IO_IN_PROGRESS; 58514272Spst if (RELEASE_MASTER) { 58614272Spst return(-1); 58714272Spst } 58814272Spst nbytes = write(fd, buf_table[bhp-bufhdr_table], BUFSIZE); 58914272Spst if (GET_MASTER) { 59014272Spst return(-2); 59114272Spst } 59214272Spst if ( nbytes < 0 ) { 59314272Spst error_log1 ("Write failed with error code %d\n", errno); 59414272Spst return(-1); 59514272Spst } else if ( nbytes != BUFSIZE ) { 59614272Spst error_log1 ("Short write: %d bytes of %d\n", nbytes, BUFSIZE ); 59714272Spst } 59814272Spst bhp->flags &= ~(BUF_DIRTY|BUF_IO_IN_PROGRESS); 59914272Spst return (0); 60014272Spst} 60114272Spst 60214272Spststatic BUFHDR_T * 60314272Spstbf_assign_buf ( ndx, obj, flags, len ) 60414272Spstint ndx; 60514272SpstOBJ_T *obj; 60614272Spstu_long flags; 60714272Spstint *len; /* Number of bytes read */ 60814272Spst{ 60914272Spst BUFHDR_T *bhp; 61014272Spst int fd; 61114272Spst 61214272Spst assert ( obj->file_id < NUM_FILE_ENTRIES ); 61314272Spst bhp = bf_newbuf(); 61414272Spst if ( !bhp ) { 61514272Spst return(NULL); 61614272Spst } 61714272Spst OBJ_ASSIGN ( (*obj), bhp->id ); 61814272Spst if ( buf_hash_table[ndx] >= NUM_BUFS ) { 61914272Spst buf_hash_table[ndx] = bhp-bufhdr_table; 62014272Spst } else { 62114272Spst LISTPE_INSERT ( bufhdr_table, hash, bhp, buf_hash_table[ndx] ); 62214272Spst } 62314272Spst 62414272Spst bhp->flags |= BUF_VALID; 62514272Spst if ( flags & BF_PIN ) { 62614272Spst bhp->flags |= BUF_PINNED; 62714272Spst bhp->refcount++; 62814272Spst#ifdef PIN_DEBUG 62914272Spst fprintf(stderr, "bf_assign_buf: %X PINNED (%d)\n", 63014272Spst buf_table + (bhp-bufhdr_table), bhp->refcount); 63114272Spst#endif 63214272Spst } 63314272Spst fd = bf_fid_to_fd(obj->file_id); 63414272Spst if ( fd == -1 ) { 63514272Spst error_log1 ("Invalid fid %d\n", obj->file_id); 63614272Spst bhp->flags |= ~BUF_IO_ERROR; 63714272Spst return(NULL); 63814272Spst } 63914272Spst if ( obj->obj_id >= buf_fids[obj->file_id].npages) { 64014272Spst buf_fids[obj->file_id].npages = obj->obj_id+1; 64114272Spst *len = 0; 64214272Spst } else if ( flags & BF_EMPTY ) { 64314272Spst *len = 0; 64414272Spst } else { 64514272Spst bhp->flags |= BUF_IO_IN_PROGRESS; 64614272Spst if (RELEASE_MASTER) { 64714272Spst return(NULL); 64814272Spst } 64914272Spst if ( lseek ( fd, obj->obj_id << BUFSHIFT, L_SET ) < -1 ) { 65014272Spst error_log2 ("Unable to perform seek on file: %d to page %d", 65114272Spst obj->file_id, obj->obj_id ); 65214272Spst bhp->flags &= ~BUF_IO_IN_PROGRESS; 65314272Spst bhp->flags |= ~BUF_IO_ERROR; 65414272Spst return(NULL); 65514272Spst } 65614272Spst *len = read(fd, buf_table[bhp-bufhdr_table], BUFSIZE); 65714272Spst if ( *len < 0 ) { 65814272Spst error_log2 ("Unable to perform read on file: %d to page %d", 65914272Spst obj->file_id, obj->obj_id ); 66014272Spst bhp->flags &= ~BUF_IO_IN_PROGRESS; 66114272Spst bhp->flags |= ~BUF_IO_ERROR; 66214272Spst return(NULL); 66314272Spst } 66414272Spst if (GET_MASTER) { 66514272Spst return(NULL); 66614272Spst } 66714272Spst bhp->flags &= ~BUF_IO_IN_PROGRESS; 66814272Spst if ( bhp->wait_proc != -1 ) { 66914272Spst /* wake up waiter and anyone waiting on it */ 67014272Spst#ifdef DEBUG 67114272Spst printf("Waking transaction %d due to completed I/O\n", 67214272Spst bhp->wait_proc); 67314272Spst#endif 67414272Spst proc_wake_id ( bhp->wait_proc ); 67514272Spst bhp->wait_proc = -1; 67614272Spst } 67714272Spst MAKE_MRU(bhp); 67814272Spst } 67914272Spst 68014272Spst if ( flags & BF_DIRTY ) { 68114272Spst bhp->flags |= BUF_DIRTY; 68214272Spst } else if ( *len < BUFSIZE ) { 68314272Spst bhp->flags |= BUF_NEWPAGE; 68414272Spst } 68514272Spst return ( bhp ); 68614272Spst} 68714272Spst 68814272Spstint 68914272Spstbuf_last ( fid ) 69014272Spstint fid; 69114272Spst{ 69214272Spst int val; 69314272Spst 69414272Spst if (GET_MASTER) { 69514272Spst return(-1); 69614272Spst } 69714272Spst assert ( fid < NUM_FILE_ENTRIES ); 69814272Spst if ( buf_fids[fid].npages == -1 ) { 69914272Spst /* initialize npages field */ 70014272Spst (void) bf_fid_to_fd ( fid ); 70114272Spst } 70214272Spst val = buf_fids[fid].npages; 70314272Spst if ( val ) { 70414272Spst val--; /* Convert to page number */ 70514272Spst } 70614272Spst if (RELEASE_MASTER) { 70714272Spst return(-1); 70814272Spst } 70914272Spst return(val); 71014272Spst} 71114272Spst 71214272Spst#ifdef DEBUG 71314272Spstextern void 71414272Spstbuf_dump ( id, all ) 71514272Spstint id; 71614272Spstint all; 71714272Spst{ 71814272Spst int i; 71914272Spst BUFHDR_T *bhp; 72014272Spst 72114272Spst printf ( "LRU + %d\n", *buf_lru ); 72214272Spst if ( all ) { 72314272Spst printf("ID\tFID\tPID\tLNEXT\tLPREV\tHNEXT\tHPREV\tSLEEP\tFLAG\tREFS\n"); 72414272Spst for ( bhp = bufhdr_table, i = 0; i < NUM_BUFS; bhp++, i++ ) { 72514272Spst printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i, 72614272Spst bhp->id.file_id, bhp->id.obj_id, 72714272Spst bhp->lru.next, bhp->lru.prev, 72814272Spst bhp->hash.next, bhp->hash.prev, 72914272Spst bhp->wait_proc, bhp->flags, bhp->refcount ); 73014272Spst } 73114272Spst } else { 73214272Spst if ( id >= NUM_BUFS ) { 73314272Spst printf ( "Buffer ID (%d) too high\n", id ); 73414272Spst return; 73514272Spst } 73614272Spst bhp = bufhdr_table+id; 73714272Spst printf ( "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%x\t%d\n", i, 73814272Spst bhp->id.file_id, bhp->id.obj_id, 73914272Spst bhp->lru.next, bhp->lru.prev, 74014272Spst bhp->hash.next, bhp->hash.prev, 74114272Spst bhp->wait_proc, bhp->flags, bhp->refcount ); 74214272Spst } 74314272Spst return; 74414272Spst} 74514272Spst#endif 74614272Spst 747