/*-
 * Copyright (c) 1991, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/*****************************************************************************
 * File: mcache.h
 *
 * This is a modfied version of the original Berkley code for
 * manipulating a memory pool. This version however is not 
 * compatible with the original Berkley version.
 *
 * This version uses HDF number types.
 *
 * AUTHOR - George V.- 1996/08/22
 *****************************************************************************/ 

/* $Id: mcache.h,v 1.2 1996/10/02 18:45:15 georgev Exp $ */

/*
 *  NOTE:
 *    Here pagesize is the same thing as chunk size and pages refer to chunks.
 *    I just didn't bother to change all references from pages to chunks.
 *
 *    -georgev
 */

#ifndef _MCACHE_H
#define _MCACHE_H

/* Required include */
#include "hqueue.h"    /* Circluar queue functions(Macros) */

/* Set return/succeed values */
#ifdef SUCCEED
#define RET_SUCCESS  SUCCEED
#define RET_ERROR    FAIL
#else
#define RET_SUCCESS  0
#define RET_ERROR    -1
#endif

/*
 * The memory pool scheme is a simple one.  Each in-memory page is referenced
 * by a bucket which is threaded in up to two (three?) ways.  All active pages
 * are threaded on a hash chain (hashed by page number) and an lru chain.
 * (Inactive pages are threaded on a free chain?).  Each reference to a memory
 * pool is handed an opaque MPOOL cookie which stores all of this information.
 */

/* Current Hash table size. Page numbers start with 1 
* (i.e 0 will denote invalid page number) */
#define	HASHSIZE	    128
#define	HASHKEY(pgno)  ((pgno -1) % HASHSIZE)

/* Default pagesize and max # of pages to cache */
#define DEF_PAGESIZE   8192
#define DEF_MAXCACHE   1

#define MAX_PAGE_NUMBER 0xffffffff  /* >= # of pages in a object */

/* The BKT structures are the elements of the queues. */
typedef struct _bkt 
{
  CIRCLEQ_ENTRY(_bkt) hq;	/* hash queue */
  CIRCLEQ_ENTRY(_bkt) q;	/* lru queue */
  VOID    *page;            /* page */
  int32   pgno;             /* page number */
#define	MCACHE_DIRTY  0x01  /* page needs to be written */
#define	MCACHE_PINNED 0x02  /* page is pinned into memory */
  uint8   flags;            /* flags */
} BKT;

/* The element structure for every page referenced(read/written) in object */
typedef struct _lelem
{
  CIRCLEQ_ENTRY(_lelem) hl;	    /* hash list */
  int32        pgno;            /* page number */
#ifdef STATISTICS
  int32	      elemhit;          /* # of hits on page */
#endif
#define ELEM_READ       0x01
#define ELEM_WRITTEN    0x02
#define ELEM_SYNC       0x03
  uint8      eflags;            /* 1= read, 2=written, 3=synced */
} L_ELEM;

#define	MCACHE_EXTEND    0x10	/* increase number of pages 
                                   i.e extend object */

/* Memory pool cache */
typedef struct MCACHE
{
  CIRCLEQ_HEAD(_lqh, _bkt)    lqh;	      /* lru queue head */
  CIRCLEQ_HEAD(_hqh, _bkt)    hqh[HASHSIZE];  /* hash queue array */
  CIRCLEQ_HEAD(_lhqh, _lelem) lhqh[HASHSIZE]; /* hash of all elements */
  int32	curcache;		      /* current num of cached pages */
  int32	maxcache;		      /* max number of cached pages */
  int32	npages;			      /* number of pages in the object */
  int32	pagesize;		      /* cache page size */
  int32 object_id;            /* access ID of object this cache is for */
  int32 object_size;          /* size of object to cache 
                                 must be multiple of pagesize for now */
  int32 (*pgin) (VOID *cookie, int32 pgno, VOID *page); /* page in conversion routine */
  int32 (*pgout) (VOID *cookie, int32 pgno, const VOID *page);/* page out conversion routine*/
  VOID	*pgcookie;                         /* cookie for page in/out routines */
#ifdef STATISTICS
  int32	listhit;                /* # of list hits */
  int32	listalloc;              /* # of list elems allocated */
  int32	cachehit;               /* # of cache hits */
  int32	cachemiss;              /* # of cache misses */
  int32	pagealloc;              /* # of pages allocated */
  int32	pageflush;              /* # of pages flushed */
  int32	pageget;                /* # of pages requested from pool */
  int32	pagenew;                /* # of new pages */
  int32	pageput;                /* # of pages put back into pool */
  int32	pageread;               /* # of pages read from object */
  int32	pagewrite;              /* # of pages written to object */
#endif /* STATISTICS */
} MCACHE;

#if defined c_plusplus || defined __cplusplus
extern      "C"
{
#endif                          /* c_plusplus || __cplusplus */

extern MCACHE *mcache_open (
    VOID *key,          /* IN:byte string used as handle to share buffers */
    int32 object_id,    /* IN: object handle */
    int32 pagesize,     /* IN: chunk size in bytes */
    int32 maxcache,     /* IN: maximum number of pages to cache at any time */
    int32 npages,       /* IN: number of chunks currently in object */
    int32 flags         /* IN: 0= object exists, 1= does not exist */);

extern VOID	 mcache_filter (
    MCACHE *mp,             /* IN: MCACHE cookie */
    int32 (*pgin)(VOID *cookie, int32 pgno, VOID *page) ,/* IN: page in filter */
    int32 (*pgout)(VOID *cookie, int32 pgno, const VOID *page) , /* IN: page out filter */
    VOID *pgcookie          /* IN: filter cookie */);

extern VOID	*mcache_new (
    MCACHE *mp,      /* IN: MCACHE cookie */
    int32 *pgnoaddr, /* IN/OUT: address of newly create page */
    int32 flags      /* IN:MCACHE_EXTEND or 0 */);


extern VOID	*mcache_get (
    MCACHE *mp, /* IN: MCACHE cookie */
    int32 pgno, /* IN: page number */
    int32 flags /* IN: XXX not used? */);

extern intn	 mcache_put (
    MCACHE *mp, /* IN: MCACHE cookie */
    VOID *page, /* IN: page to put */ 
    int32 flags /* IN: flags = 0, MCACHE_DIRTY */);

extern intn	 mcache_sync (
    MCACHE *mp /* IN: MCACHE cookie */);

extern intn	 mcache_close (
    MCACHE *mp /* IN: MCACHE cookie */);

extern int32  mcache_get_pagesize (
    MCACHE *mp /* IN: MCACHE cookie */);

extern int32  mcache_get_maxcache (
    MCACHE *mp /* IN: MCACHE cookie */);

extern int32  mcache_set_maxcache (
    MCACHE *mp,     /* IN: MCACHE cookie */
    int32  maxcache /* IN: max pages to cache */);

extern int32  mcache_get_npages (
    MCACHE *mp /* IN: MCACHE cookie */);

#ifdef STATISTICS
extern VOID	 mcache_stat(
    MCACHE *mp /* IN: MCACHE cookie */);
#endif /* STATISTICS */
#if 0 /* NOT USED */
extern intn	 mcache_page_sync (
    MCACHE *mp, /* IN: MCACHE cookie */
    int32 pgno, /* IN: page to sync */
    int32 flags /* IN: flags */);
#endif

#if defined c_plusplus || defined __cplusplus
}
#endif                          /* c_plusplus || __cplusplus */

#endif /* _MCACHE_H */
