Cache del Master



La cache consente al master di tenere traccia di tutte le richieste inoltrate da Client/Slave ancora da soddisfare e di quelle gia' soddisfatte con i relativi files contenenti i risultati di tali ricerche. Mediante i metodi di accesso forniti dalla cache il master e' in grado di capire se la richiesta arrivata e' gia' stata soddisfatta, nel qual caso si ritornano i risultati raccolti, oppure se e' stata inoltrata piu' volte da parte dello stesso Client/Slave o se e' stata inoltrata da qualcun altro. Lo scopo di tali controlli e' quello di evitare di inoltrare agli slaves locali richieste gia' effettuate da altri o effettuate piu' volte dallo stesso mittente e di restituire dei risultati qualora la richiesta sia gia' stata soddisfatta.

Dettagli implementativi


La cache e' realizzata con una Hashtable le cui entry hanno la seguente struttura:

Struttura di un'entry della cache
La chiave e' costituita da:
La parte dati, invece, e' costituita da:

Metodi di accesso


Mediante i seguenti metodi (tutti synchronized) e' possibile accedere e modificare i dati in cache:

Entita' attive della cache


All'interno della cache operano due thread:
  1. ExpireThread: questo thread ha il compito di rimuovere tutte le entry della cache "scadute", cioe' quelle il cui Expire Time e' stato superato. Per fare questo il processo si risveglia periodicamente (il tempo di sleep e' contenuto nella costante Constants.risveglioThreadCache), preleva il tempo corrente in millisecondi e controlla tutte le entry il cui Expire Time e' diverso da -1. Se il tempo corrente e' maggiore o uguale a quello della entry esaminata, questa viene eliminata dalla cache assieme al file che contiene i risultati della richiesta corrispondente (ricordare che l'Expire Time viene settato quando viene inserito il nome del file dei risultati mediante il metodo set(ric,fileRis)). In questo modo si evita che i risultati delle ricerche vengano mantenuti troppo a lungo, occupando risorse del nodo master.
  2. UpdateSlaveThread: questo thread ha il compito di diffondere agli slave del nodo locale lo stato del master in modo che possa essere ripristinato in seguito a una rielezione dovuta a un guasto del master stesso. Per stato del master si intendono solo le richieste pendenti. E' stata fatta questa scelta perche' la diffusione delle richieste soddisfatte e dei relativi risultati impegnerebbe troppe risorse generando un traffico di rete troppo elevato. Riducendo le informazioni da diffondere si e' potuto optare per un protocollo senza connessione, cioe' UDP. Questo thread viene attivato ogni volta che viene chiamato uno dei metodi di accesso alla cache scritti in rosso e riportati poco sopra. Questi metodi inseriscono un messaggio del tipo "set/unset richiesta+flag" in una coda realizzata dalla classe interna MsgQueue. Questa ingloba un vector (la coda) e fornisce due metodi di accesso (synchronized) per inserire (put) e prelevare (get) i messaggi della coda. UpdateSlaveThread una volta avviato chiama il metodo get della coda: se essa e' vuota, viene sospeso (metodo wait) fino a che non vengono inseriti nuovi messaggi con put (che risveglia il processo sospeso con notify). Una volta prelevato un messaggio (il primo della coda, cioe' il primo ad essere depositato) UpdateSlaveThread lo invia a tutti gli slave del nodo locale. Per aumentare l'affidabilita' della trasmissione, dopo l'invio del messaggio lo thread attende un ack (vuoto) da ogni slave come conferma della ricezione di cio' che e' stato inviato. Se uno slave non risponde, il messaggio viene inviato nuovamente a quello slave per un massimo di 3 volte, dopodiche' lo slave viene ritenuto "morto" (per il mantenimento della lista degli slave "vivi" e di quelli "morti" si veda la classe SlaveVivi). Per evitare attese infinite, viene settato un timeout per la socket usata pari al valore contenuto in Constants.attesaRec e scaduto il quale si effettua una nuova ritrasmissione agli slave che non hanno risposto.