dbcache.c

来自「db.* (pronounced dee-be star) is an adva」· C语言 代码 · 共 409 行

C
409
字号
/*************************************************************************** *                                                                         * * db.*                                                                    * * open source database, dbcheck utility                                   * *                                                                         * * Copyright (c) 2000 Centura Software Corporation. All rights reserved.   * *                                                                         * * Use of this software, whether in source code format, or in executable,  * * binary object code form, is governed by the CENTURA OPEN SOURCE LICENSE * * which is fully described in the LICENSE.TXT file, included within this  * * distribution of source code files.                                      *  *                                                                         * **************************************************************************/#include "db.star.h"#include "dbcache.h"static ID_ENTRY *addToCache (long, PAGE_CACHE *);static ID_ENTRY *idLookup   (long, short *, PAGE_CACHE *);static ID_ENTRY *touchEntry (ID_ENTRY *, PAGE_CACHE *);#define DB_DENYRW 0/* ======================================================================     Allocate and initialize a cache*/PAGE_CACHE *cache_alloc(){    register short i;    PAGE_CACHE *csh;    /* allocate cache */    if ((csh = (PAGE_CACHE *) psp_cGetMemory(sizeof(PAGE_CACHE), 0)) == NULL)        return NULL;    /* initialize cache */    csh->max_ent   = NUM_CACHE_PAGES;    csh->no_ent    = 0;    csh->mru_ent   = NULL;    csh->lru_ent   = NULL;    /* allocate spare cache page */    csh->new_id_entry = (ID_ENTRY *) psp_cGetMemory(sizeof(ID_ENTRY), 0);    if (!csh->new_id_entry)       goto failed;    csh->new_id_entry->data = psp_cGetMemory(CACHE_PG_SIZE, 0);    if (!csh->new_id_entry->data)        goto failed;    csh->used = (PAGE_FILE *) psp_cGetMemory(sizeof(PAGE_FILE), 0);    if (!csh->used)        goto failed;    csh->dchain = (PAGE_FILE *) psp_cGetMemory(sizeof(PAGE_FILE), 0);    if (!csh->dchain)        goto failed;    /* allocate cache pages */    for ( i = 0; i < csh->max_ent; ++i )    {        csh->id_lookup[i] = (ID_ENTRY *) psp_cGetMemory(sizeof(ID_ENTRY), 0);        if (!csh->id_lookup[i])            goto failed;        csh->id_lookup[i]->data = (void *) psp_cGetMemory(CACHE_PG_SIZE, 0);        if (!csh->id_lookup[i]->data)            goto failed;    }    return csh;failed:    cache_free(csh);    return (PAGE_CACHE *) NULL;}/* ======================================================================     Clear a cache*/void cache_clear(PAGE_CACHE *csh){    register int i;    /* clear cache */    csh->no_ent    = 0;    csh->mru_ent   = NULL;    csh->lru_ent   = NULL;    /* clear lookup table */    for ( i = 0; i < csh->max_ent; ++i )    {        csh->id_lookup[i]->id = 0;        csh->id_lookup[i]->prev_lru = NULL;        csh->id_lookup[i]->next_lru = NULL;    }}/* ======================================================================     Find and or load entry in cache by id*/void *cache_find(long id, PAGE_CACHE *csh){    ID_ENTRY *idp = NULL;    if (id == 0)        return NULL;    if ((idp = idLookup(id, NULL, csh)) == NULL)        idp = addToCache(id, csh);    else        touchEntry(idp, csh);    return idp ? idp->data : NULL;}/* ======================================================================     Free a cache*/void cache_free(PAGE_CACHE *csh){    register short i;    delete_temp_files(csh);    for ( i = 0; i < csh->max_ent; ++i )    {        if (csh->id_lookup[i])        {            if (csh->id_lookup[i]->data)                psp_freeMemory(csh->id_lookup[i]->data, 0);            psp_freeMemory(csh->id_lookup[i], 0);        }    }    if (csh->new_id_entry)    {        if (csh->new_id_entry->data)            psp_freeMemory(csh->new_id_entry->data, 0);        psp_freeMemory(csh->new_id_entry, 0);    }    if (csh->used)        psp_freeMemory(csh->used, 0);    if (csh->dchain)        psp_freeMemory(csh->dchain, 0);    psp_freeMemory(csh, 0);}void delete_temp_files(PAGE_CACHE *csh){    if (csh->used->desc != NULL)    {        psp_fileClose(csh->used->desc);        psp_fileRemove(csh->used->name);    }    if (csh->dchain->desc != NULL)    {        psp_fileClose(csh->dchain->desc);        psp_fileRemove(csh->dchain->name);    }    csh->dchain->desc = csh->used->desc = NULL;    csh->dchain->last_page = csh->used->last_page = 0;}/* ======================================================================     Add an entry into a cache*/static ID_ENTRY *addToCache(long id, PAGE_CACHE *csh){    short new_ent, old_ent;    ID_ENTRY *idp, *idq;    ID_ENTRY *old_id_entry = NULL;    /* load the new page into new_id_entry */    csh->new_id_entry->id = id;    csh->new_id_entry->prev_lru = NULL;    csh->new_id_entry->next_lru = NULL;    loader(id, csh->new_id_entry->data, csh);    /* find position to add new entry in cache */    idLookup(id, &new_ent, csh);    /* if cache is full, swap a page out */    if ( csh->no_ent == csh->max_ent )    {        /* remove lru_ent */        idq = csh->lru_ent;        csh->lru_ent = idq->prev_lru;        csh->lru_ent->next_lru = NULL;        if ((idq = idLookup(idq->id, &old_ent, csh)) == NULL)            return NULL;        /* write page to temp file */        if (zapper(idq->id, idq->data, csh) == -1)            return NULL;        if (old_ent < csh->no_ent - 1)        {            old_id_entry = csh->id_lookup[old_ent];            memmove(&csh->id_lookup[old_ent], &csh->id_lookup[old_ent + 1],                (csh->no_ent - old_ent - 1) * sizeof(ID_ENTRY *));        }        if (old_ent < new_ent)            --new_ent;        --csh->no_ent;    }    /* add entry into id_lookup table */    if (new_ent < csh->no_ent)    {        if (old_id_entry == NULL)            old_id_entry = csh->id_lookup[csh->no_ent];        memmove(&csh->id_lookup[new_ent+1], &csh->id_lookup[new_ent],            (csh->no_ent - new_ent) * sizeof(ID_ENTRY *));    }    if (old_id_entry == NULL)        old_id_entry = csh->id_lookup[new_ent];    /*        By now old_id_entry should be pointing at a page that can        be re-used; csh->new_id_entry points at the page that we        want to put into the cache.     */    idp = csh->id_lookup[new_ent] = csh->new_id_entry;    csh->new_id_entry = old_id_entry;    ++csh->no_ent;    /* place at head of mru entries */    if (csh->mru_ent != NULL)    {        idp->next_lru = csh->mru_ent;        csh->mru_ent->prev_lru = idp;    }    csh->mru_ent = idp;    if (csh->lru_ent == NULL)         csh->lru_ent = idp;    return idp;}/* ======================================================================     Lookup up an entry by id within a cache*/static ID_ENTRY *idLookup(long id, short *ent, PAGE_CACHE *csh){    register short i, l, u;    ID_ENTRY *idp = NULL;    /* use binary search to find id match */    for (i = l = 0, u = (short) (csh->no_ent - 1); u >= l; )    {        /* look for match on id */        i = (short) ((l + u) / 2);        idp = csh->id_lookup[i];        if (id < idp->id)            u = (short) (i - 1);        else if ( id > idp->id)            l = (short) (i + 1);        else        {            if (ent)                *ent = i;            return idp;        }    }    if ( ent )    {        if (idp && (id > idp->id))            i++;        *ent = i;    }    return NULL;}/* ======================================================================     Touch LRU & MRU entries within a cache*/static ID_ENTRY *touchEntry(ID_ENTRY *idp, PAGE_CACHE *csh){    if (idp->prev_lru == NULL)        return idp;    else        idp->prev_lru->next_lru = idp->next_lru;        if (idp->next_lru == NULL)        csh->lru_ent = idp->prev_lru;    else        idp->next_lru->prev_lru = idp->prev_lru;    idp->next_lru          = csh->mru_ent;    csh->mru_ent->prev_lru = idp;    idp->prev_lru          = NULL;    csh->mru_ent           = idp;    return idp;}/***************************************************************************//***************************************************************************//*                     Pagemap Routines                                    *//***************************************************************************//***************************************************************************/void loader(long id, void *data, PAGE_CACHE *csh){    long       page_no;    PAGE_FILE *pfile;    if (id >= USAGE_ID)    {        page_no = id - USAGE_ID;        pfile = csh->used;    }    else    {        page_no = id - DCHAIN_ID;        pfile = csh->dchain;    }    if (pfile->desc == NULL || page_no > pfile->last_page)    {        memset(data, 0, CACHE_PG_SIZE);        return;    }    psp_fileSeek(pfile->desc, page_no * CACHE_PG_SIZE);    if (psp_fileRead(pfile->desc, data, CACHE_PG_SIZE) != CACHE_PG_SIZE)        memset(data, 0, CACHE_PG_SIZE);}/***************************************************************************/short zapper(long id, void *data, PAGE_CACHE *csh){    char      *zero_data;    long       page_no;    long       pg;    PAGE_FILE *pfile;    if (id >= USAGE_ID)    {        page_no = id - USAGE_ID;        pfile = csh->used;    }    else    {        page_no = id - DCHAIN_ID;        pfile = csh->dchain;    }    if (pfile->desc == NULL)    {        if ((pfile->desc = psp_fileOpen(pfile->name, O_CREAT | O_TRUNC | O_RDWR, PSP_FLAG_DENYRW)) == NULL)        {            vtprintf(DB_TEXT("Open failed on dbcheck temporary file. errno = %d\n"), errno);            return(-1);        }    }    if (page_no > pfile->last_page)    {        /*            Writing beyond end of file - fill pages in between with zeros        */        if ((zero_data = (char *) psp_cGetMemory(CACHE_PG_SIZE, 0)) == NULL)        {            vtprintf(DB_TEXT("Out of memory\n"));            return(-1);        }        for (pg = pfile->last_page + 1; pg < page_no; pg++)        {            if (psp_fileSeekWrite(pfile->desc, pg * CACHE_PG_SIZE, zero_data, CACHE_PG_SIZE) != CACHE_PG_SIZE)            {                vtprintf(DB_TEXT("Write failed on dbcheck temporary file %s. errno = %d\n"),                         pfile->name, errno);                psp_freeMemory(zero_data, 0);                return(-1);            }        }        psp_freeMemory(zero_data, 0);    }    if (psp_fileSeekWrite(pfile->desc, page_no * CACHE_PG_SIZE, data, CACHE_PG_SIZE) != CACHE_PG_SIZE)    {        vtprintf(DB_TEXT("Write failed on dbcheck temporary file %s. errno = %d\n"),                 pfile->name, errno);        return(-1);    }    if (page_no > pfile->last_page)        pfile->last_page = page_no;    return(1);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?