Modulo Coordinator - Dettagli Tecnici
Contents
Requisiti
L'utilizzatore del modulo Coordinator inizializza il modulo richiamando il metodo statico init di CoordinatorManager. In tale metodo viene anche passata l'istanza di INtkdTasklet per fornire l'implementazione del sistema di tasklet.
Quindi il nodo istanzia il suo CoordinatorManager passando al costruttore:
peers_manager. L'istanza di PeersManager.
map. La mappa delle posizioni libere.
Quando il nodo ha completato la fase di bootstrap, l'utilizzatore del modulo chiama il metodo bootstrap_complete del CoordinatorManager.
Quando il nodo considera che la notifica della sua presenza abbia ormai raggiunto tramite ETP tutti i membri del g-nodo in cui è entrato, l'utilizzatore del modulo chiama il metodo presence_notified del CoordinatorManager.
Deliverables
Nel costruttore del CoordinatorManager viene creata una istanza di CoordinatorService (che descriveremo sotto) e viene registrata nel PeersManager.
Il modulo permette di chiedere ad un vicino del nodo informazioni sui posti liberi nei suoi g-nodi con il metodo get_neighbor_map di CoordinatorManager.
Il modulo permette di chiedere ad un vicino del nodo di prenotare per lui un posto nel suo g-nodo di livello l con il metodo ask_reservation di CoordinatorManager.
Servizio Coordinator
Classe server del servizio Coordinator
Il modulo deriva da PeerService la classe CoordinatorService.
Questa classe è interna al modulo. Contiene questi membri:
retrieve_cache_done. Booleano, inizializzato a False.
my_presence_should_be_known. Booleano, inizializzato a False.
bookings. Lista di liste di Booking. Memoria delle prenotazioni. L'elemento i-esimo è la lista di prenotazioni attive per il nostro g-nodo di livello i+1. La classe Booking ha una posizione (int pos) e un time-to-live (Timer ttl).
max_eldership. Lista di int. L'elemento i-esimo dice il valore più alto di progressione già assegnato ad una prenotazione per un nuovo g-nodo di livello i dentro il nostro g-nodo di livello i+1. Un valore più alto significa che il g-nodo è arrivato dopo, cioè esso è più giovane.
Quando viene chiamato il metodo bootstrap_complete del CoordinatorManager, la classe CoordinatorService fa queste operazioni:
- In una nuova tasklet:
Avvia le operazioni di recupero dei record di sua pertinenza con i metodi PeersManager.begin_retrieve_cache e PeersManager.next_retrieve_cache.
Trattandosi di un servizio non opzionale, non attende l'evento PeersManager.participant_maps_ready.
E' compito della classe CoordinatorService costruire la richiesta r di "recupero records".
Ad ogni chiamata che restituisce True va interpretata la risposta resp e vanno memorizzati i records di pertinenza. TODO spiegare cosa va indicato nella richiesta e quali membri vanno memorizzati sulla base della risposta.
Al termine imposta il suo flag retrieve_cache_done.
Quando viene chiamato il metodo presence_notified del CoordinatorManager, la classe CoordinatorService fa queste operazioni:
Imposta il suo flag my_presence_should_be_known.
Il metodo is_ready() della classe CoordinatorService si basa sui flag retrieve_cache_done e my_presence_should_be_known.
Metodo reserve
Ricordiamo che quando una richiesta ad un servizio peer-to-peer viene ricevuta dall'hash_node viene chiamato il metodo exec della classe che deriva la PeerService. Questa riceve una istanza di IPeersRequest e deve restituire una istanza di IPeersResponse.
Se il metodo exec della classe CoordinatorService viene chiamato con una istanza di CoordinatorRequest (si veda sotto) che ha il membro name = 'reserve' allora abbiamo ricevuto una richiesta di "prenota un posto nel tuo g-nodo di livello lvl". Le operazioni da fare sono:
Se ci sono problemi a deserializzare gli argomenti viene fatta pervernire una eccezione DeserializeError.
- Atomic on: queste operazioni devono essere eseguite atomicamente, senza permettere la schedulazione di altre tasklet.
Verifica che un posto libero esiste nel mio g-nodo di livello lvl. Altrimenti lancia una eccezione.
Scegli un posto pos.
- Segnala il posto come prenotato nella memoria.
Incrementa di 1 la max_eldership(lvl-1) nella memoria.
Con i dati in memoria prepara la risposta ret (pos=pos, eldership=max_eldership(lvl-1))
- Atomic off.
Avvia la prima replica con il metodo PeersManager.begin_replica. Come q mettiamo 15 (una private const nel codice). Come perfect_tuple il valore ottenuto con il metodo perfect_tuple della classe CoordinatorClient. E' compito della classe CoordinatorService costruire la richiesta r di "replica prenotazione su pos".
Attende l'esito, cioè il booleano restituito, la risposta resp da interpretare, l'oggetto IPeersContinuation cont da passare nelle chiamate successive.
La risposta resp dovrebbe essere semplicemente OK. Il booleano restituito è False solo se si è avuta l'eccezione NoParticipantsInNetwork.
Se l'esito è True:
Avvia la seconda replica con il metodo PeersManager.next_replica passando la IPeersContinuation.
Attende l'esito, cioè il booleano restituito e la risposta resp da interpretare.
La risposta resp dovrebbe essere semplicemente OK. Il booleano restituito è False solo se si è avuta l'eccezione NoParticipantsInNetwork.
Se l'esito è True:
- Avvia una tasklet in cui:
- While True:
Avvia una replica con il metodo PeersManager.next_replica passando la IPeersContinuation.
Attende l'esito, cioè il booleano restituito e la risposta resp da interpretare.
La risposta resp dovrebbe essere semplicemente OK. Il booleano restituito è False se abbiamo completato q repliche o se si è avuta l'eccezione NoParticipantsInNetwork.
Se l'esito è False:
- Esci dal ciclo. Termina la tasklet.
- While True:
- Avvia una tasklet in cui:
Completa ret con (elderships=anzianità dei miei g-nodi da lvl in su)
- Restituisce ret.
Classe client del servizio Coordinator
Il modulo deriva da PeerClient la classe CoordinatorClient.
Ridefinisce il suo metodo perfect_tuple. La chiave che può essere usata per calcolare l'hash_node è un intero l da 1 a levels. La lista di interi restituita è composta da l volte il valore 0.
Classi serializzabili per le comunicazioni
Viene definita la classe interna CoordinatorRequest. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersRequest. Serve per tutte le richieste che possono essere fatte al servizio. Tale classe contiene:
name. Una stringa che identifica la richiesta. I valori possibili sono: ['reserve', 'retrieve_cache', 'replica_reserve'].
lvl. Usato se name = 'reserve'. Un intero che indica il livello in cui riservare un posto.
Viene definita la classe interna CoordinatorReserveResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta solo per la richiesta 'reserve'. Tale classe contiene:
error_domain. Una stringa nullable.
error_code. Una stringa nullable.
error_message. Una stringa nullable. Queste sono tutte a null se l'esito è buono, mentre sono valorizzate se si vuole indicare una eccezione.
pos. Un intero. La posizione assegnata.
elderships. Una lista di interi. Le anzianità da l-1 (del g-nodo appena assegnato) fino a levels.
Viene definita la classe interna CoordinatorRetrieveCacheResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta solo per la richiesta 'retrieve_cache'. Tale classe contiene:
error_domain. Una stringa nullable.
error_code. Una stringa nullable.
error_message. Una stringa nullable. Queste sono tutte a null se l'esito è buono, mentre sono valorizzate se si vuole indicare una eccezione.
- ...
Viene definita la classe interna CoordinatorReplicaReserveResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta solo per la richiesta 'replica_reserve'. Tale classe contiene:
error_domain. Una stringa nullable.
error_code. Una stringa nullable.
error_message. Una stringa nullable. Queste sono tutte a null se l'esito è buono, mentre sono valorizzate se si vuole indicare una eccezione.
- ...