mpool.libtp
来自「基于组件方式开发操作系统的OSKIT源代码」· LIBTP 代码 · 共 747 行 · 第 1/2 页
LIBTP
747 行
/******************************************************************************VERSION $Id: mpool.libtp,v 1.3 1997/02/22 14:57:55 peter Exp $PACKAGE: User Level Shared Memory ManagerDESCRIPTION: This package provides a buffer pool interface implemented as a collection of file pages mapped into shared memory. Based on Mark's buffer managerROUTINES: External buf_alloc buf_flags buf_get buf_init buf_last buf_open buf_pin buf_sync buf_unpin Internal bf_assign_buf bf_fid_to_fd bf_newbuf bf_put_page ******************************************************************************/#include <sys/types.h>#include <assert.h>#include <sys/file.h>#include <sys/stat.h>#include <stdio.h>#include <errno.h>#include "list.h"#include "user.h"#include "txn_sys.h"#include "buf.h"#include "semkeys.h"#include "error.h"/* we need to translate between some type of file id that the user process passes and a file descriptor. For now, it's a nop.*/#define GET_MASTER get_sem ( buf_spinlock )#define RELEASE_MASTER release_sem ( buf_spinlock )#define LRUID *buf_lru#define LRUP (bufhdr_table+*buf_lru)#define MRU bufhdr_table[*buf_lru].lru.prev/* Global indicator that you have started reusing buffers */int do_statistics = 0;/* Process Statics (pointers into shared memory)*/static BUF_T *buf_table = 0;static BUFHDR_T *bufhdr_table;static int *buf_hash_table;static int *buf_lru; /* LRU is the free list */static int buf_spinlock;static FINFO_T *buf_fids;static int *buf_sp; /* Pointer to string free space */static char *buf_strings;/* Process Local FID->FD table */static int fds[NUM_FILE_ENTRIES];/* Static routines */static BUFHDR_T *bf_assign_buf();static int bf_fid_to_fd();static BUFHDR_T *bf_newbuf();static int bf_put_page();/* Return 0 on success 1 on failure*/extern intbuf_init ( ){ ADDR_T buf_region; BUFHDR_T *bhp; int i; int ref_count; int *spinlockp; /* Initialize Process local structures */ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { fds[i] = -1; } buf_region = attach_region ( BUF_REGION_NAME, BUF_REGION_NUM, BUF_REGION_SIZE, &ref_count ); if ( !buf_region ) { return (1); } error_log3 ( "Buf Region: ADDR: %d ID: %d SIZE: %d\n", buf_region, BUF_REGION_NUM, BUF_REGION_SIZE ); buf_table = (BUF_T *)buf_region; bufhdr_table = (BUFHDR_T *)(buf_table + NUM_BUFS); buf_hash_table = (int *)(bufhdr_table + NUM_BUFS); buf_lru = buf_hash_table + NUMTABLE_ENTRIES; spinlockp = buf_lru + 1; buf_fids = (FINFO_T *)(spinlockp+1); buf_sp = (int *)(buf_fids + NUM_FILE_ENTRIES); buf_strings = (char *)(buf_sp + 1); /* Create locking spinlock (gets creating holding the lock) */ buf_spinlock = create_sem ( BUF_SPIN_NAME, BUF_SPIN_NUM, ref_count <= 1 ); if ( buf_spinlock < 0 ) { return(1); } if ( ref_count <= 1 ) { *spinlockp = buf_spinlock; /* Now initialize the buffer manager */ /* 1. Free list */ *buf_lru = 0; /* 2. Buffer headers */ for ( i = 0, bhp = bufhdr_table; i < NUM_BUFS; bhp++, i++ ) { bhp->lru.next = i+1; bhp->lru.prev = i-1; bhp->flags = 0; /* All Flags off */ bhp->refcount = 0; bhp->wait_proc = -1; /* No sleepers */ LISTPE_INIT ( hash, bhp, i ); /* Hash chains */ } bufhdr_table[0].lru.prev = NUM_BUFS-1; bufhdr_table[NUM_BUFS-1].lru.next = 0; /* 3. Hash Table */ for ( i = 0; i < NUMTABLE_ENTRIES; i++ ) { buf_hash_table[i] = NUM_BUFS; } /* 4. File ID Table */ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { buf_fids[i].offset = -1; buf_fids[i].npages = -1; buf_fids[i].refcount = 0; } /* 5. Free String Pointer */ *buf_sp = (FILE_NAME_LEN*NUM_FILE_ENTRIES); if (RELEASE_MASTER) { return(1); } error_log0 ( "Initialized buffer region\n" ); } return (0);}extern voidbuf_exit(){ int ref; int i; /* Flush Buffer Pool on Exit */ for ( i = 0; i < NUM_FILE_ENTRIES; i++ ) { if ( fds[i] != -1 ) { close ( fds[i] ); } } if ( buf_table ) { detach_region ( buf_table, BUF_REGION_NUM, BUF_REGION_SIZE, &ref ); } return;}/* We need an empty buffer. Find the LRU unpinned NON-Dirty page.*/static BUFHDR_T *bf_newbuf(){ int fd; int lruid; int nbytes; int ndx; BUFHDR_T *bhp; lruid = LRUID; for ( bhp = LRUP; bhp->flags & (BUF_PINNED|BUF_IO_IN_PROGRESS); bhp = LISTP_NEXTP (bufhdr_table, lru, bhp ) ) { if ( bhp->lru.next == lruid ) { /* OUT OF BUFFERS */ error_log1 ( "All buffers are pinned. %s\n", "Unable to grant buffer request" ); return(NULL); } } /* BHP can be used */ if ( bhp->flags & BUF_DIRTY ) { do_statistics = 1; /* MIS Check for log flushed appropriately */ fd = bf_fid_to_fd(bhp->id.file_id); if ( fd == -1 ) { error_log1 ("Invalid fid %d\n", bhp->id.file_id); return(NULL); } if ( bf_put_page(fd, bhp) < 0 ) { return(NULL); } } /* Update Hash Pointers */ ndx = BUF_HASH ( bhp->id.file_id, bhp->id.obj_id ); LISTP_REMOVE(bufhdr_table, hash, bhp); if ( buf_hash_table[ndx] == (bhp-bufhdr_table) ) { if ( bhp->hash.next != (bhp-bufhdr_table) ) { buf_hash_table[ndx] = bhp->hash.next; } else { buf_hash_table[ndx] = NUM_BUFS; } } INIT_BUF(bhp); return(bhp);}/* buf_alloc Add a page to a file and return a buffer for it.*/ADDR_Tbuf_alloc ( fid, new_pageno )int fid;int *new_pageno;{ BUFHDR_T *bhp; int fd; int len; int ndx; OBJ_T fobj; if (GET_MASTER) { return(NULL); } if ( buf_fids[fid].npages == -1 ) { /* initialize npages field */ fd = bf_fid_to_fd ( fid ); } assert (fid < NUM_FILE_ENTRIES); *new_pageno = buf_fids[fid].npages; if ( *new_pageno == -1 ) { RELEASE_MASTER; return ( NULL ); } buf_fids[fid].npages++; ndx = BUF_HASH ( fid, *new_pageno ); fobj.file_id = fid; fobj.obj_id = *new_pageno; bhp = bf_assign_buf ( ndx, &fobj, BF_PIN|BF_DIRTY|BF_EMPTY, &len ); if ( RELEASE_MASTER ) { /* Memory leak */ return(NULL); } if ( bhp ) { return ((ADDR_T)(buf_table+(bhp-bufhdr_table))); } else { return ( NULL ); }}/* Buffer Flags BF_DIRTY Mark page as dirty BF_EMPTY Don't initialize page, just get buffer BF_PIN Retrieve with pin MISMight want to add a flag that sets an LSN for this buffer is theDIRTY flag is setEventually, you may want a flag that indicates the I/O and lockrequest should be shipped off together, but not for now.*/extern ADDR_Tbuf_get ( file_id, page_id, flags, len )int file_id;int page_id;u_long flags;int *len; /* Number of bytes read into buffer */{ BUFHDR_T *bhp; int bufid; int fd; int ndx; int next_bufid; int stat; OBJ_T fobj; ndx = BUF_HASH ( file_id, page_id ); fobj.file_id = (long) file_id; fobj.obj_id = (long) page_id; if ( GET_MASTER ) { return(NULL); } /* This could be a for loop, but we lose speed by making all the cases general purpose so we optimize for the no-collision case. */ bufid = buf_hash_table[ndx]; if ( bufid < NUM_BUFS ) { for ( bhp = bufhdr_table+bufid; !OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID); bhp = LISTP_NEXTP ( bufhdr_table, hash, bhp ) ) { if ( bhp->hash.next == bufid ) { goto not_found; } }/* found */ if ( flags & BF_PIN ) { bhp->flags |= BUF_PINNED; bhp->refcount++;#ifdef PIN_DEBUG fprintf(stderr, "buf_get: %X PINNED (%d)\n", buf_table + (bhp-bufhdr_table), bhp->refcount);#endif } if ( flags & BF_DIRTY ) { bhp->flags |= BUF_DIRTY; } while ( bhp->flags & BUF_IO_IN_PROGRESS ) { /* MIS -- eventually err check here */#ifdef DEBUG printf("About to sleep on %d (me: %d\n)\n", bhp->wait_proc, my_txnp - txn_table);#endif#ifdef WAIT_STATS buf_waits++;#endif stat = proc_sleep_on ( &(bhp->wait_proc), buf_spinlock ); if ( stat ) { /* Memory leak */ return(NULL); } if (!( bhp->flags & BUF_IO_IN_PROGRESS) && (!OBJ_EQ (bhp->id, fobj) || !(bhp->flags & BUF_VALID))) { if (RELEASE_MASTER) return(NULL); return(buf_get ( file_id, page_id, flags, len )); } } MAKE_MRU( bhp ); *len = BUFSIZE; } else {not_found: /* If you get here, the page isn't in the hash table */ bhp = bf_assign_buf ( ndx, &fobj, flags, len ); } /* Common code between found and not found */ if ( bhp && bhp->flags & BUF_NEWPAGE ) { *len = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?