/*
 * nasd_cheops_cache.h
 *
 * Cache module for Cheops (clerk and storage manager)
 *
 * Authors: Khalil Amiri, Sean Levy
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1996,1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD_CHEOPS_CACHE_H_
#define _NASD_CHEOPS_CACHE_H_

#include <nasd/nasd_types.h>
#include <nasd/nasd_mem.h>
#include <nasd/nasd_threadstuff.h>
#include <nasd/nasd_cheops_locks.h>

#define _NASD_CHEOPS_MAX_CACHE_SIZE         100

typedef struct _nasd_cheops_cache_s           _nasd_cheops_cache_t;
typedef struct _nasd_cheops_cache_ent_s       _nasd_cheops_cache_ent_t;
typedef struct _nasd_cheops_cache_hash_ent_s  _nasd_cheops_cache_hash_ent_t;
typedef struct _nasd_cheops_cache_stats_s     _nasd_cheops_cache_stats_t;
typedef int                          _nasd_cheops_cache_err_t;

/* not clear whether this is going to be ever needed */
typedef enum {
  _NASD_CHEOPS_CACHE_TYPE_SMAP, /* stripe map (for cheops objects) */
  _NASD_CHEOPS_CACHE_TYPE_GMAP, 
  _NASD_CHEOPS_CACHE_TYPE_DMAP, 
  _NASD_CHEOPS_CACHE_TYPE_IMAP
} _nasd_cheops_cache_type_t;

/* cache ent flags */
#define _NASD_CHEOPS_CACHE_ENT_BUSY       (1<<0) /* io in progress */
#define _NASD_CHEOPS_CACHE_ENT_DIRTY      (1<<1) /* dirty */
#define _NASD_CHEOPS_CACHE_ENT_FREE       (1<<2) /* free */
#define _NASD_CHEOPS_CACHE_ENT_LRU        (1<<3) /* lru */
#define _NASD_CHEOPS_CACHE_ENT_HOLD       (1<<4) /* held */

typedef struct _nasd_cheops_cache_key_s {
  int  object_id;
  int  record_id;
} _nasd_cheops_cache_key_t;

struct _nasd_cheops_cache_stats_s {
  nasd_uint64           hits;
  nasd_uint64           misses;
  nasd_uint64           updates;
  nasd_uint64           fixes;
  nasd_uint64           invalidates;
};

struct _nasd_cheops_cache_ent_s {
  NASD_DECLARE_MUTEX(m)
  NASD_DECLARE_COND(c)
  int                          flags;
  int                          hold_wait_refcnt; /* the number of threads waiting to lock this entry */
  caddr_t                      data;  
  _nasd_cheops_cache_key_t      key;     /* key depends on what kind of entries are being cached */
  _nasd_cheops_cache_ent_t      *bnext;  /* hash chain links */
  _nasd_cheops_cache_ent_t      *bprev;
  _nasd_cheops_cache_ent_t      *lnext;     /* LRU links */
  _nasd_cheops_cache_ent_t      *lprev;
  _nasd_cheops_cache_ent_t      *dnext;     /* dirty links */
  _nasd_cheops_cache_ent_t      *dprev;
  _nasd_cheops_cache_ent_t      *fnext;  /* next in the free list */
};

struct _nasd_cheops_cache_s {
  NASD_DECLARE_MUTEX(m)
  _nasd_cheops_rwlock_t          lock;
  int                            csize;      /* size of cache in number of entries */
  int                            bsize;      /* size of data buffer pointed by each entry */
  int                            nbuckets;      /* size of of hash table */
  int                            victim;
  _nasd_cheops_cache_type_t       ctype;
  _nasd_cheops_cache_ent_t        *buckets;   /* hash buckets*/
  _nasd_cheops_cache_ent_t        *free_list; /* free list */
  _nasd_cheops_cache_ent_t        *ents;      /* entry list */
  _nasd_cheops_cache_ent_t        lru;
  _nasd_cheops_cache_ent_t        dirty;
  caddr_t                        bufs;
  NASD_DECLARE_MUTEX(stats_m)
  _nasd_cheops_cache_stats_t      stats;
  int                            (*handle_read_fault)(_nasd_cheops_cache_key_t, caddr_t);
  int                            (*writeback)(_nasd_cheops_cache_ent_t *, int);
};

#define _NASD_CHEOPS_CACHE_INC_STAT(_cp_,_stat_) {                      \
  NASD_LOCK_MUTEX((_cp_)->stats_m);                                     \
  (_cp_)->stats._stat_++;                                               \
  NASD_UNLOCK_MUTEX((_cp_)->stats_m);                                   \
}
#define _NASD_CHEOPS_CACHE_LOCK(_cp_)           NASD_LOCK_MUTEX((_cp_)->m)
#define _NASD_CHEOPS_CACHE_UNLOCK(_cp_)         NASD_UNLOCK_MUTEX((_cp_)->m)
#define _NASD_CHEOPS_CACHE_ENT_LOCK(_e_)        NASD_LOCK_MUTEX((_e_)->m)
#define _NASD_CHEOPS_CACHE_ENT_UNLOCK(_e_)      NASD_UNLOCK_MUTEX((_e_)->m)
#define _NASD_CHEOPS_CACHE_ENT_WAIT(_e_)        NASD_WAIT_COND((_e_)->c, \
                                                               (_e_)->m)
#define _NASD_CHEOPS_CACHE_ENT_SIGNAL(_e_)      NASD_SIGNAL_COND((_e_)->c)
#define _NASD_CHEOPS_CACHE_ENT_BCAST(_e_)       NASD_BROADCAST_COND((_e_)->c)

/* API */

int _nasd_cheops_cache_destroy(
  _nasd_cheops_cache_t		*cp);
int _nasd_cheops_cache_create(
  int				  csize,
  int				  bsize,
  _nasd_cheops_cache_type_t	  ctype,
  _nasd_cheops_cache_t		**cpp);
int _nasd_cheops_cache_read(
  _nasd_cheops_cache_t		 *cp,
  _nasd_cheops_cache_key_t	  key,
  caddr_t			  re);
void _nasd_cheops_cache_show_stats(
  _nasd_cheops_cache_t		 *cp);
int _nasd_cheops_cache_mark_invalid(
  _nasd_cheops_cache_t		 *cp,
  _nasd_cheops_cache_key_t	  key);
int _nasd_cheops_cache_mark_dirty(
  _nasd_cheops_cache_t		 *cp,
  _nasd_cheops_cache_key_t	  key);
int _nasd_cheops_cache_hold_ent(
  _nasd_cheops_cache_t		 *cp,
  _nasd_cheops_cache_key_t	  key,
  _nasd_cheops_cache_ent_t	**ep);
int _nasd_cheops_cache_release_ent(
  _nasd_cheops_cache_t		 *cp,
  _nasd_cheops_cache_ent_t	 *ep);

#endif /* !_NASD_CHEOPS_CACHE_H_ */

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
