/*static char *SCCSID = "@(#)cachhash.c	6.3 91/05/23";*/

#define SCCSID "@(#)cachhash.c	6.3 91/05/23"
/********************************************************/
/*                                                      */
/*       IBM/Microsoft Confidential                     */
/*                                                      */
/*       Copyright (c) IBM Corporation 1987, 1989       */
/*       Copyright (c) Microsoft Corporation 1987, 1989 */
/*                                                      */
/*       All Rights Reserved                            */
/********************************************************/

#define FNO_NUM FNO_CACHHASH_C
#define INCL_TYPES                      // for basedef.h typedefs
#include <osconst.h>
#include <ostypes.h>
#include <basemac.h>
#include <basedef.h>
#include <fnofs.h>
#include <osmac.h>
#include <mi.h>
#include <vmexport.h>
#include <selxport.h>
#include <pgexport.h>
#include <tkexport.h>
#include <smexport.h>
#include <sft.h>
#include <cache.h>

/*
 *** AddHash -- Add a buffer to the hash table
 *
 *      HISTORY
 */

int AddHash(pbuf,hVPB)
register PBUFHDR  pbuf;  /*  ptr to buffer to set up    */
ulong_t hVPB;
{

        register PBUFHDR  pbufHashHead;
        register ushort_t h = (ushort_t)(HASHVAL(pbuf->BufRBA));

        MMPHPreAddHash();     /* performance hook (3204h) */
        pbufHashHead = HashFind (pbuf->BufRBA,hVPB);
        if (pbufHashHead != NULL) {
           MMPHPostAddHash();     /* performance hook (3285h) */
           return(1);
         }

        /*  Set the buffer's hash table address pointer  */
        pbuf->ppBufHTA  = BufHashTable + h;

        /*  Add to hash table  */
        pbufHashHead = BufHashTable[h];
        if (pbufHashHead == NULL) {
                /*  the hash list is empty.  pbuf's hash
                 *  chain pointers are both set to pbuf
                 *  (a circular, doubly-linked chain with one
                 *  element)
                 */

                pbuf->BufHashLru.pbufFwd = pbuf;
                pbuf->BufHashLru.pbufBak = pbuf;

        }
        else {

                /*  pbufis inserted into the hash chain after
                 *  the first buffer node in the hash
                 *  chain.
                 *
                 *  This seems kind of odd--the former head becomes the
                 *  tail once the new buffer is made the head.
                 */
                DCADDF (pbuf, BufHashLru, *pbufHashHead);
                BufAssert (pbuf->BufHashLru.pbufFwd != NULL);
        }

        /*  The new guy becomes the head of the hash chain.  */
        BufHashTable[h] = pbuf;

        /*  The buffer header is now ready.  */
        MMPHPostAddHash();     /* performance hook (3285h) */
        return(0);
}

/*
 ***    HashFind -- Find a sector in the cache
 *
 *      HashFind checks to see if a given physical sector is
 *      in the cache.  HashFind doesn't worry about whether or
 *      not the cache block is locked or not, and it assumes
 *      that the supplied sector number is already rounded down
 *      to a multiple of SPB
 *
 *      ENTRY   lsn = physical sector number
 *              hvpb = vpb
 *
 *      RETURNS the cache header address
 *              or NULL if not in cache
 *
 */

PBUFHDR
HashFind (lsn,hVPB)
ulong_t lsn;                      /* Physical Sector Number */
register ulong_t hVPB;
{
        register PBUFHDR pbuf;
        register PBUFHDR pbufStart;

        pbuf = BufHashTable [HASHVAL (lsn)];
        if (pbuf == NULL)
            return pbuf;

        pbufStart = pbuf;

        do {
            if (pbuf -> BufRBA == lsn && pbuf->BufhVPB == hVPB){
                return (pbuf);
            }

            pbuf = pbuf -> BufHashLru.pbufFwd;

        } while (pbuf != pbufStart);

        return (NULL);
}
/*
 *** RemoveHash -- Remove buffer from hash chains.
 *
 *      HISTORY
 */
void RemoveHash(pBuf)
register PBUFHDR  pBuf;  /*  ptr to buffer to unlink    */
{
    if (pBuf->BufHashLru.pbufFwd == pBuf) {

        /*  If it points at itself, it's the only member in its
         *  hash chain.  All we need to do is set the hash
         *  table entry to NULL.
         */
        *(pBuf->ppBufHTA) = NULL;
    }
    else {
        /* There are other buffers on the hash chain;  the buffer
         * we want has to be detached from the chain.
         */

        if (*(pBuf->ppBufHTA) == pBuf) {

            /* if it's at the head of the chain, we need to
             * update the Hash Table entry.
             */

            *(pBuf->ppBufHTA) = pBuf->BufHashLru.pbufFwd;
        }

        /*  Detach the hash chain connection  */
        DCREM (pBuf, BufHashLru);
    }
}

/*
 *** BufUnlink -- Unlink buffer from hash and LRU chains.
 *
 *      HISTORY
 */
void BufUnlink(pBuf)
register PBUFHDR  pBuf;  /*  ptr to buffer to unlink    */
{
    /*  Take *pBuf off the LRU chain.  The buffer's LRU pointers
     *  point at the buffer itself, so the casual observer can tell
     *  that it's not on the LRU chain.
     */
    DCREM (pBuf, BufLru);

    pBuf->BufLru.pbufFwd = pBuf;
    pBuf->BufLru.pbufBak = pBuf;
    RemoveHash(pBuf);

    pBuf->BufRBA = -1;
    BufAssert (!(pBuf->BufFlag & BUF_LWLOCK));
    BufAssert (!(pBuf->BufFlag & BUF_LOCK));

}
