//    NASD.h
//       The definition of the data structures of NASD
//

#define BLOCKSIZE 8192

#define SERVER_SCHEME_NONE    0   // no server
#define SERVER_SCHEME_BASE    1   // noncooperative
#define SERVER_SCHEME_GLOBAL  2   // global overflow server
#define SERVER_SCHEME_CHANCE1 3   // 1 chance
#define SERVER_SCHEME_CHANCER 4   // 1 chance and return-on-hit
#define SERVER_SCHEME_CHANCEH 5   // 1 chance on hint
#define SERVER_SCHEME_CHANCEX 6   // 1 chance on random
#define SERVER_SCHEME_CHANCEZ 7   // the best one chance

#define DEFAULTCACHESIZE 4096

#define INVALID_I_NUMBER 0

// the following data is copied from N-Chance paper
#define DISKSEEKTIME      14000    // microsecond
#define DISKTRANSFERTIME  1000     // for one block
#define MEMACCESSTIME     250      // for one block
#define NETROUNDTRIP      400      // 
#define NETLATENCY        200      //
#define NETTRANSFERTIME   400      // for one block

#define HASHTABLESIZE 40000

#define HASHVALUE(inode, bnum)   (((inode) + ((bnum)%40000) * 7)%40000)

#define FLAG_USED 0
#define FLAG_REF  1

struct TimeBD
{
  unsigned disktime;   // disk access time
  unsigned nettime;    // network transmission time
  unsigned memtime;    // memory access time
};

struct CacheBlock
{
  unsigned char flag;  // 0 for the used list, 1 for reflist
  unsigned d_num;   // device number
  unsigned i_num;   // inode number
  unsigned b_num;   // block number
  unsigned refcount; // reference bit
  
  struct CacheBlock * prev;
  struct CacheBlock * next;

  struct CacheBlock * up;
  struct CacheBlock * down;
};

class StorageServer
{
 public:
  struct CacheBlock HT[HASHTABLESIZE];
  struct CacheBlock * UsedList; // a double list with a sentinel
  struct CacheBlock * FreeList; // a single list

 public:
  unsigned putcount;   // the number of blocks received 

  unsigned missblock;   // the number of missed blocks
  unsigned totalblock;  // the number of referenced blocks

  unsigned cachesize;   // the total size of cache
  unsigned globalused;  // the number of blocks used for global scheme

 public:
  StorageServer();
  StorageServer(unsigned csize);
  ~StorageServer();

  // return 1 if find, return 0 otherwise; the reference state is also changed
  virtual int LookUp(unsigned idev, unsigned inode, unsigned bnum);

  // put data into the cache
  // return 1 means there is free block, return 2 means one block is replaced
  virtual int TransferData(unsigned idev, unsigned inode, unsigned bnum, unsigned rcount,
			   //			   unsigned &elapse, unsigned &netcount);
			   TimeBD &elapse, unsigned &netcount);
};

class NasdServer
{
 public:
  unsigned char schememode;

  struct CacheBlock HT[HASHTABLESIZE];
  struct CacheBlock * UsedList; // a double list with a sentinel
  struct CacheBlock * FreeList; // a single list
  
  struct CacheBlock * RefList;  // a double list with a sentinel
  struct CacheBlock * FreeRefList; // a single list, 3 times size of FreeList

 public:
  unsigned busybit[MAXSERVERNUM];

  unsigned serverid;    // server id

  unsigned iocount;     // the number of i/os caused by cache miss
  unsigned refcount;    // the number of references

  unsigned remotehit;   // the number of hits on other servers
  unsigned missblock;   // the number of missed blocks
  unsigned totalblock;  // the number of referenced blocks

  unsigned cachesize;   // the total size of cache
  unsigned globalused;  // the number of blocks used for global scheme
  unsigned localused;   // the number of blocks used for local disk

 public:
  NasdServer();
  NasdServer(unsigned char mode, unsigned sid, unsigned csize);
  ~NasdServer();

  virtual int HintOnDest();

  // return 1 if find, return 0 otherwise
  virtual int LookUp(unsigned idev, unsigned inode, unsigned bnum);

  // return remote device id if find, return -1 otherwise
  virtual int RLookUp(unsigned idev, unsigned inode, unsigned bnum);

  // put data into the cache
  // return 1 means there is free block, return 2 means one block is replaced
  // return 0 means rejected
  virtual int TransferData(unsigned idev, unsigned inode, unsigned bnum, unsigned rcount,
			   //			   unsigned &elapse, unsigned &netcount);
			   TimeBD &elapse, unsigned &netcount);

  // Read the data from the server, and elapse is the return time
  //    statflag  == 0 means no statistics
  // Return 1 if success, else return 0
  virtual int ReadData(unsigned idev, unsigned inode, unsigned b_begin, unsigned b_count, 
		       //		unsigned &elapse, unsigned &netcount, unsigned char statflag);
		       TimeBD &elapse, unsigned &netcount, unsigned char statflag);

  // the same as ReadData so far
  // Return 1 if success, else return 0
  virtual int WriteData(unsigned idev, unsigned inode, unsigned b_begin, unsigned b_count, 
			//		unsigned &elapse, unsigned &netcount, unsigned char statflag);
			TimeBD &elapse, unsigned &netcount, unsigned char statflag);

  // create a file on the disk
  // Return 1 if success, else return 0
  //virtual int Create(unsigned idev, unsigned &elapse, unsigned char statflag);

  // remove a file
  // Return 1 if success, else return 0
  //virtual int Unlink(unsigned idev, unsigned inode, unsigned &elapse, unsigned char statflag);
};
