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