#ifndef __CACHE_H__
#define __CACHE_H__
#include <DirectoryServiceCore/DSMutexSemaphore.h>
#include <libkern/OSAtomic.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <kvbuf.h>
#define CACHE_POLICY_REPLACE_ON_COLLISION 0x00000001
#define CACHE_POLICY_UPDATE_TTL_ON_HIT 0x00000002
#define CACHE_ENTRY_TYPE_GROUP 0x00000001
#define CACHE_ENTRY_TYPE_HOST 0x00000002
#define CACHE_ENTRY_TYPE_SERVICE 0x00000004
#define CACHE_ENTRY_TYPE_USER 0x00000008
#define CACHE_ENTRY_TYPE_COMPUTER 0x00000010
#define CACHE_ENTRY_TYPE_MOUNT 0x00000020
#define CACHE_ENTRY_TYPE_ALIAS 0x00000040
#define CACHE_ENTRY_TYPE_PROTOCOL 0x00000080
#define CACHE_ENTRY_TYPE_RPC 0x00000100
#define CACHE_ENTRY_TYPE_NETWORK 0x00000200
#define CACHE_ENTRY_TYPE_REPLACE 0x40000000
#define CACHE_ENTRY_TYPE_NEGATIVE 0x80000000
#define CACHE_ENTRY_TYPE_ALL 0xffffffff
struct sCacheValidation
{
char *fNode;
uint32_t fToken;
bool fNodeAvailable;
int fRefCount;
OSSpinLock fSpinLock;
sCacheValidation( const char *inNode );
inline bool IsValid ( void ) { return (fToken == GetToken()); }
sCacheValidation *Retain ( void );
void Release ( void );
private:
uint32_t GetToken( void );
inline ~sCacheValidation( void )
{
free( fNode );
fNode = NULL;
}
};
struct sKeyListItem
{
sKeyListItem *fNext;
char *fKey;
inline sKeyListItem( sKeyListItem *inNext, char *inKey )
{
fNext = inNext;
fKey = inKey;
}
inline ~sKeyListItem( void )
{
free( fKey );
fNext = NULL;
fKey = NULL;
}
};
struct sKeyList
{
uint32_t fCount;
sKeyListItem *fHead;
sKeyList ( void );
~sKeyList ( void );
bool AddKey ( char *inKey );
void DeleteKey ( const char *inKey );
};
struct sCacheEntry
{
sCacheEntry *fPrev;
sCacheEntry *fNext;
sKeyList fKeyList;
sCacheValidation *fValidation;
uint32_t fTTL;
time_t fBestBefore;
time_t fLastAccess; uint32_t fHits; uint32_t fRefCount;
uint32_t fFlags;
kvbuf_t *fBuffer;
sCacheEntry ( uint32_t inTTL, time_t inTimeStamp, uint32_t inFlags, kvbuf_t *inBuffer );
void Isolate ( void );
void InsertAfter ( sCacheEntry *inAfter );
void InsertBefore ( sCacheEntry *inBefore );
bool Validate ( time_t inNow );
bool CompareWith ( sCacheEntry *inComparison, time_t inMRAWindow );
bool CompareAllKeys ( sKeyList *inKeys );
inline bool AddKey ( char *inKey )
{
if ( this != NULL )
return fKeyList.AddKey( inKey );
else
return false;
}
inline void AddValidation ( sCacheValidation *inValidation )
{
if ( this != NULL && inValidation != NULL )
{
fValidation->Release();
fValidation = inValidation->Retain();
}
}
inline sCacheEntry *Retain ( void ) { if ( this != NULL) fRefCount++; return this; }
inline void Release ( void ) { if ( this != NULL && (--fRefCount) == 0 ) delete this; }
private:
~sCacheEntry ( void );
};
struct sBucketListItem
{
sBucketListItem *fNext; const char *fKey; sCacheEntry *fEntry;
inline sBucketListItem( sBucketListItem *inNext, const char *inKey, sCacheEntry *inEntry )
{
fNext = inNext;
fKey = inKey;
fEntry = inEntry->Retain();
}
inline ~sBucketListItem( void )
{
fNext = NULL;
fKey = NULL; fEntry->Release();
}
};
struct sBucketList
{
uint32_t fCount;
sBucketListItem *fHead;
sBucketList ( void );
~sBucketList ( void );
bool AddItem ( const char *inKey, sCacheEntry *inEntry );
void DeleteItem ( const char *inKey, sCacheEntry *inEntry );
};
struct sEntryListItem
{
sEntryListItem *fNext;
sCacheEntry *fEntry;
inline sEntryListItem( sCacheEntry *inEntry ) { fNext = NULL; fEntry = inEntry->Retain(); }
inline ~sEntryListItem( void ) { fNext = NULL; fEntry->Release(); fEntry = NULL; }
};
struct sEntryList
{
sEntryListItem *fHead;
sEntryListItem *fTail;
sEntryList ( void );
~sEntryList ( void );
void AddEntry ( sCacheEntry *inEntry );
};
class CCache
{
public:
sCacheEntry *fHead; sCacheEntry *fTail;
DSMutexSemaphore fCacheLock;
uint32_t fBucketCount;
sBucketList **fBuckets;
time_t fCacheTTL;
time_t fMRAWindow;
uint32_t fMaxSize;
uint32_t fPolicyFlags;
public:
CCache ( uint32_t inMaxSize, uint32_t inBuckets, time_t inMRAWindow, time_t inTTL, uint32_t inPolicyFlags );
~CCache ( void );
sCacheEntry *AddEntry ( kvbuf_t *inBuffer, const char *inKey, time_t inTTL, uint32_t inFlags );
void RemoveEntry ( sCacheEntry *inEntry );
bool AddKeyToEntry ( sCacheEntry *inEntry, const char *inKey, bool inUnique );
void RemoveKey ( const char *inKey );
kvbuf_t *Fetch ( sKeyList *inKeys, bool inMatchAll = false, uint32_t *outLowestTTL = NULL );
void Flush ( void );
int Sweep ( uint32_t inEntryType, bool inCheckDate );
int UpdateAvailability ( char *iNode, bool inState );
bool isCacheOverMax ( void );
uint32_t GetCount ( void );
private:
void DoNotifies ( uint32_t inFlags );
bool RemoveCollision ( const char *inKey );
uint32_t HashKey ( const char *inKey );
void IsolateEntry ( sCacheEntry *inEntry );
void InsertEntryAfter ( sCacheEntry *inAfter, sCacheEntry *inEntry );
sCacheEntry *ReorderEntry ( sCacheEntry *inEntry );
sCacheEntry *FindEntry ( const char *inKey );
};
#endif