Le cache sono le classi template piu' complesse ed interessanti della libreria. La loro funzione e' di associare a una chiave un valore prelevandolo se possibile da una cache dei valori in memoria.
Internamente contengono un dizionario per associare le chiavi ai valori, una coda per dare un ordine di entrata e di uscita dalla cache ed eventualmente degli array per aggiungere piu' valori ad una stessa chiava. Le chiavi sono sempre memorizzate in modo diretto (oggetti di tipo chiave) mentre i valori sono sempre memorizzati come puntatori.
Ne esistono piu' varianti a seconda dei casi di utilizzo:
TCache<K,V> Cache semplice di puntatori a oggetti V associati a chiavi K
TPriorityCache<K,V> Cache semplice con priorita' di puntatori a oggetti V associati a chiavi K
TCacheArray<K,V> Cache semplice (implementata come array) di puntatori a oggetti V associati a chiavi K
TCacheBlock<K,V> Cache di blocchi di puntatori a oggetti V associati a chiavi K
Cache generica di oggetti CBuf associati a chiave CKey
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti CBuf sono memorizzati in forma indiretta (puntatori a). Notare il costruttore: szQue è la dimensione della cache L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable ossia deve avere un operatore di copia (=), uno di conronto (==) e deve avere una funzione: unsigned HashValue() const; oppure deve esistere una funzione globale del tipo: unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti viene chiamata la funzione FillCache (ridefibile in classi derivate) per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia- mare la funzione Add dopo aver reperito l'oggetto associato alla chiave, per salvarlo nella cache.
La cache semplice associa ad ogni singola chiave un singolo valore. La cache viene costruita specificandone la capienza. Quando le associazioni contenute superano la capienza vengono eliminate quelle inserite per prime.
...
class FileItem
{
public:
FileItem();
int readFileFromDisk(const char* path);
void* getFileContent() {return data;}
private;
void* data;
};
...
class FileCache : public TCache<FixString, FileItem>
{
public:
FileCache(int size) : TCache<FixString, FileItem>(size)
{
}
// redefined to handle cache fault and add to cache
virtual const FileItem* FillCache( const FixString& );
};
...
const FileItem* FileCache::FillCache( const FixString& s )
{
// create the item not found in cache
FileItem *fi = new FileItem();
if(fi->readFileFromDisk(s)) {
delete fi;
return NULL;
}
// add the item to cache
Add(s, fi);
return fi;
}
...
...
// create a cache with the specified size
FileCache fc(4);
const FileItem* hosts = fc.Fetch("/etc/hosts");
const FileItem* resolv = fc.Fetch("/etc/resolv.conf");
const FileItem* hall = fc.Fetch("/etc/host.allow");
const FileItem* hden = fc.Fetch("/etc/host.deny");
// this don't reload the files from disk: use the cache content
const FileItem* hosts1 = fc.Fetch("/etc/hosts");
const FileItem* hall1 = fc.Fetch("/etc/host.allow");
// now the first entry ("/etc/hosts") will be removed from the cache
const FileItem* samba = fc.Fetch("/etc/samba/smb.conf");
...
...
Cache generica di oggetti CBuf associati a chiave CKey con priorità.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti CBuf sono memorizzati in forma indiretta (puntatori a). Notare il costruttore: szQue è la dimensione della cache (-1=nolimit) L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable ossia deve avere un operatore di copia (=), uno di conronto (==) e deve avere una funzione: unsigned HashValue() const; oppure deve esistere una funzione globale del tipo: unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti viene chiamata la funzione FillCache (ridefibile in classi derivate) per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia- mare la funzione Add dopo aver reperito l'oggetto associato alla chiave, per salvarlo nella cache. Ridefinendo opportunamente IsPriority si può decidere se utilizzare o o meno la priorità sulla cache. Se questa funzione restituisce != 0 ogni volta che Fetch va a buon fine, l'oggetto CBuf viene reinserito a a priorità massima nella cache. In questo modo in caso di scaricamento a causa riempimento, verranno scaricati gli elementi con accesso meno frequente.
La cache semplice associa ad ogni singola chiave un singolo valore. La cache viene costruita specificandone la capienza. Quando le associazioni contenute superano la capienza vengono eliminate quelle inserite prima, ma in ordine inverso di utilizzo.
...
class FileItem
{
public:
FileItem();
int readFileFromDisk(const char* path);
void* getFileContent() {return data;}
private;
void* data;
};
...
class FileCache : public TPriorityCache<FixString, FileItem>
{
public:
FileCache(int size) : TPriorityCache<FixString, FileItem>(size)
{
}
// redefined to handle cache fault and add to cache
virtual const FileItem* FillCache( const FixString& );
};
...
const FileItem* FileCache::FillCache( const FixString& s )
{
// create the item not found in cache
FileItem *fi = new FileItem();
if(fi->readFileFromDisk(s)) {
delete fi;
return NULL;
}
// add the item to cache
Add(s, fi);
return fi;
}
...
...
// create a cache with the specified size
FileCache fc(4);
const FileItem* hosts = fc.Fetch("/etc/hosts");
const FileItem* resolv = fc.Fetch("/etc/resolv.conf");
const FileItem* hall = fc.Fetch("/etc/host.allow");
const FileItem* hden = fc.Fetch("/etc/host.deny");
// this don't reload the files from disk: use the cache content
const FileItem* hosts1 = fc.Fetch("/etc/hosts");
const FileItem* hall1 = fc.Fetch("/etc/host.allow");
// now the second entry ("/etc/resolv.conf") will be removed from the cache
const FileItem* samba = fc.Fetch("/etc/samba/smb.conf");
...
...
Cache generica di oggetti CBuf associati a chiave CKey senza limitazioni sulle dimensioni, con indicizzazione.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti CBuf sono memorizzati in forma indiretta (puntatori a). L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable ossia deve avere un operatore di copia (=), uno di conronto (==) e deve avere una funzione: unsigned HashValue() const; oppure deve esistere una funzione globale del tipo: unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti viene chiamata la funzione FillCache (ridefibile in classi derivate) per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia- mare la funzione Add dopo aver reperito l'oggetto associato alla chiave, per salvarlo nella cache.
L'uso dell'array consente di inserire quanti elementi si vuole nella cache senza limiti di dimensioni, inoltre le funzioni di ricerca ritornano l'indice dell'array piuttosto che gli oggetti CBuf relativi.
La differenza principale fra TCacheArray e TCache consiste nell'uso di un array al posto di una coda per memorizzare i dati internamente. Di conseguenza questa cache non ha un limite predefinito di entry; occorrera' eventualmente implementare una logica esterna per la rimozione dalla cache degli elementi scaduti.
...
class FileItem
{
public:
FileItem();
int readFileFromDisk(const char* path);
void* getFileContent() {return data;}
int isExpiried(void* arg);
private;
void* data;
};
...
class FileCache : public TCacheArray<FixString, FileItem>
{
public:
FileCache() : TCacheArray<FixString, FileItem>()
{
}
// redefined to handle cache fault and add to cache
virtual int FillCache( const FixString& );
const FileItem* FetchData( const FixString& s )
{
int rv = Fetch(s);
return rv == -1 ? NULL : (*this)[ rv ];
}
void RemoveExpiried(void* arg)
{
FileItem* fi;
while((fi = FirstThat(testExpiried, arg)) != NULL)
delete fi;
}
static int testExpiried(const FileItem& fi, void* arg)
{
return fi.isExpiried(arg);
}
};
...
int FileCache::FillCache( const FixString& s )
{
// create the item not found in cache
FileItem *fi = new FileItem();
if(fi->readFileFromDisk(s)) {
delete fi;
return -1;
}
// add the item to cache
return Add(s, fi);
}
...
...
// create an unlimited cache
FileCache fc;
const FileItem* hosts = fc.FetchData("/etc/hosts");
const FileItem* resolv = fc.FetchData("/etc/resolv.conf");
const FileItem* hall = fc.FetchData("/etc/host.allow");
const FileItem* hden = fc.FetchData("/etc/host.deny");
// this don't reload the files from disk: use the cache content
const FileItem* hosts1 = fc.FetchData("/etc/hosts");
const FileItem* hall1 = fc.FetchData("/etc/host.allow");
// remove the expiried files
fc.RemoveExpiried(NULL);
...
...
Cache generica di oggetti CBuf associati a chiave CKey senza limitazioni sulle dimensioni con raggruppamento dei dati per chiave.
Gli oggetti CKey sono memorizzati in forma diretta, mentre gli oggetti CBuf sono memorizzati in forma indiretta (puntatori a). L'oggetto chiave (CKey) è soggetto alle restrizioni delle HashTable ossia deve avere un operatore di copia (=), uno di conronto (==) e deve avere una funzione: unsigned HashValue() const; oppure deve esistere una funzione globale del tipo: unsigned HashValue( const CKey& t );
Per prelevare gli oggetti dalla cache si usa la funzione Fetch; se la chiave esiste viene ritornato l'oggetto CBuf associato, altrimenti viene chiamata la funzione FillCache (ridefibile in classi derivate) per reperire all'esterno l'oggetto; FillCache potrà a sua volta chia- mare la funzione Add dopo aver reperito l'oggetto associato alla chiave, per salvarlo nella cache.
La cache associa ad ogni chiave un array di oggetti buffer: quando si aggiuge la chiave per la prima volta viene creato l'array ed inserito il primo elemento CBuf nell'array. Successive add con la stessa chiave aggiungeranno all'array associato alla chiave il nuovo elemento buf. Quando si preleva un valore dalla cache attraverso Fetch viene restituito l'array dei valori associati alla chiave fornita. L'array e' del tipo TIArrayAsVector (vedi TIArrayAsVector).
Questa versione della cache consente di associare ad una stessa chiave piu' valori, memorizzati internamente sotto forma di array indiretto.
...
class FileItem
{
public:
FileItem();
int readFileFromDisk(const char* path);
void* getFileContent() {return data;}
int isExpiried(void* arg);
private;
void* data;
};
...
typedef TIArrayAsVector<FileItem> ArrayFileItem;
typedef TIArrayAsVectorIterator<FileItem> IteratorFileItem;
...
class FileCache : public TCacheBlock<FixString, FileItem>
{
public:
FileCache() : TCacheBlock<FixString, FileItem>()
{
}
// redefined to handle cache fault and add to cache
virtual ArrayFileItem* FillCache( const FixString& );
void RemoveExpiried(void* arg)
{
int removed = 0;
do
{
TCacheBlockIterator<FixString, FileItem> itr(*this);
while(itr)
{
const FileItem& fi = itr.Value();
if(fi.isExpiried(arg))
{
ArrayFileItem* ptArr = Find(itr.Key());
ptArr->Destroy(;
removed = 1;
break;
}
itr++;
}
}
while(removed);
}
ArrayFileItem* getFilesFromDirectory( const FixString& s );
};
...
ArrayFileItem* FileCache::FillCache( const FixString& s )
{
ArrayFileItem* rv = NULL;
ArrayFileItem* fileInDir = getFilesFromDirectory(s);
IteratorFileItem itr(*fileInDir);
while(itr)
{
// add items to cache
rv = Add(s, itr.Current());
}
return rv;
}
...
...
// create an unlimited cache
FileCache fc;
ArrayFileItem* etc = fc.Fetch("/etc/");
ArrayFileItem* usr = fc.Fetch("/usr/");
ArrayFileItem* var = fc.Fetch("/var/");
// this don't reload the files from disk: use the cache content
ArrayFileItem* etc = fc.Fetch("/etc/");
// remove the expiried files
fc.RemoveExpiried(NULL);
...
...