Modulo Coordinator - Dettagli Tecnici

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.

Appena il nodo entra in una rete o ne costituisce una nuova, istanzia il suo CoordinatorManager passando al costruttore:

Quando il nodo ha completato la fase di bootstrap del modulo QSPN, il nodo informa il suo CoordinatorManager chiamando il metodo bootstrap_completed a cui passa:

Prima di questo evento il nodo non è in grado di eseguire i metodi remoti chiamati da un suo vicino. Questa impossibilità viene segnalata con l'eccezione CoordinatorNodeNotReadyError.

Deliverables

Quando viene chiamato il suo metodo bootstrap_completed, il CoordinatorManager crea una istanza di CoordinatorService (che descriveremo sotto) e la registra 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 metodo ha come argomento lo stub per contattare il vicino. Prevede le eccezioni CoordinatorStubNotWorkingError e CoordinatorNodeNotReadyError.

Restituisce una istanza di ICoordinatorNeighborMap.


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 get_reservation di CoordinatorManager.

Il metodo ha come argomento lo stub per contattare il vicino e il livello a cui fare richiesta. Prevede le eccezioni CoordinatorStubNotWorkingError, CoordinatorNodeNotReadyError, CoordinatorInvalidLevelError e CoordinatorSaturatedGnodeError.

Restituisce una istanza di ICoordinatorReservation.

Comunicazioni tra vicini

Quando il modulo vuole chiedere ad un vicino informazioni sui posti liberi nei suoi g-nodi usa il metodo remoto retrieve_neighbor_map. Non ha argomenti. Prevede l'eccezione CoordinatorNodeNotReadyError, oltre alle solite StubError e DeserializeError. Restituisce una istanza di ICoordinatorNeighborMapMessage.

L'interfaccia ICoordinatorNeighborMapMessage è un segnaposto (vuota) esposto dalla libreria intermedia di ZCD che espone il metodo remoto. L'interfaccia ICoordinatorNeighborMap è esposta dal modulo Coordinator e ha i metodi descritti nell'analisi. L'implementazione del metodo remoto crea una istanza della classe NeighborMap. Questa è una classe serializzabile interna al modulo, che implementa entrambe le interfacce suddette.


Quando il modulo vuole chiedere ad un vicino di prenotare per lui un posto nel suo g-nodo di livello l usa il metodo remoto ask_reservation. Ha come argomento il livello l. Prevede le eccezioni CoordinatorNodeNotReadyError, CoordinatorInvalidLevelError e CoordinatorSaturatedGnodeError, oltre alle solite StubError e DeserializeError. Restituisce una istanza di ICoordinatorReservationMessage.

L'interfaccia ICoordinatorReservationMessage è un segnaposto (vuota) esposto dalla libreria intermedia di ZCD che espone il metodo remoto. L'interfaccia ICoordinatorReservation è esposta dal modulo Coordinator e ha i metodi descritti nell'analisi. L'implementazione del metodo remoto crea una istanza della classe Reservation. Questa è una classe serializzabile interna al modulo, che implementa entrambe le interfacce suddette.

Servizio Coordinator

Classe server del servizio Coordinator

Il modulo deriva da PeerService la classe CoordinatorService. All'interno di tale classe (per poter accedere ai suoi membri privati) definisce anche la classe DatabaseDescriptor che implementa l'interfaccia IFixedKeysDatabaseDescriptor.

La classe CoordinatorService è interna al modulo. Contiene questi membri:

Nel costruttore, dopo aver valorizzato i membri nel modo suddetto, viene fatta la registrazione sul PeersManager. Dopo, in una tasklet, si avvia il metodo fixed_keys_db_on_startup del PeersManager passando l'istanza fkdd e il livello del nuovo g-nodo costituito (che viene passato al costruttore). Questo per avvalersi degli algoritmi di gestione delle problematiche di mantenimento di un database a chiavi fisse.

Quando viene chiamato il metodo get_record_for_key dell'istanza fkdd, la classe CoordinatorService fa queste operazioni:

Quando viene chiamato il metodo set_record_for_key dell'istanza fkdd, la classe CoordinatorService fa queste operazioni:

Richieste fornite dal servizio

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, nel nostro caso la classe CoordinatorService. Questo metodo riceve una istanza di IPeersRequest (e la tupla che identifica il chiamante, ma in questo caso non la utiliziamo) e deve restituire una istanza di IPeersResponse.

Il metodo exec della classe CoordinatorService, per avvalersi degli algoritmi di gestione delle problematiche di mantenimento di un database a chiavi fisse, chiama il metodo fixed_keys_db_on_request del PeersManager passando l'istanza fkdd. Questo metodo del modulo PeerServices restituisce il controllo al modulo Coordinator richiamando sull'istanza fkdd il metodo execute definito così dall'interfaccia IFixedKeysDatabaseDescriptor:

Metodo reserve

Se il metodo execute della classe CoordinatorService.DatabaseDescriptor viene chiamato con una istanza di CoordinatorReserveRequest (si veda sotto) allora abbiamo ricevuto una richiesta di "prenota un posto nel tuo g-nodo di livello lvl". Le operazioni da fare sono:

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. Si può generare la tupla inizialmente con l'implementazione di base del metodo perfect_tuple (quindi occorre definire il metodo hash_from_key), ma poi la tupla restituita deve avere solo i primi l elementi.

Richieste fatte al servizio

Ricordiamo che questo servizio è non opzionale. Il nodo stesso che fa la richiesta è partecipante al servizio ed è sempre incluso nel g-nodo in cui la ricerca viene eventualmente circoscritta. Quindi l'eccezione PeersNoParticipantsInNetworkError rilanciata dal metodo call della classe base PeerClient può sempre essere trattata come un errore.

Ricordiamo inoltre che la gestione di un database a chiavi fisse è tale che un nodo può rifiutarsi di rispondere perché non esaustivo solo in operazioni di sola lettura. Nelle chiamate al metodo call della classe base PeerClient fatte per richieste che non sono di sola lettura (ad esempio la richiesta 'reserve') l'eccezione PeersDatabaseError può essere trattata come un errore.

Metodo reserve

Se il nodo corrente vuole prenotare un posto nel suo g-nodo di livello lvl fa al servizio Coordinator la richiesta CoordinatorReserveRequest con la chiave lvl. Per farlo chiama il metodo reserve nella classe CoordinatorClient.

Il metodo prende a parametro il livello lvl. Restituisce una istanza di Reservation. Può rilanciare le eccezioni: CoordinatorSaturatedGnodeError.

In caso di comportamento anomalo del nodo che risponde al servizio, il metodo della classe CoordinatorClient rilancia una eccezione CoordinatorSaturatedGnodeError. Non possiamo in ogni caso sapere se il nodo che risponde agisce in modo corretto; anche se sappiamo che non agisce correttamente non sappiamo se lo fa per errore o con malizia; non possiamo sapere se risponderà in modo palesemente errato anche alle richieste provenienti da altri nodi; in definitiva, cercare di porre rimedio diversamente sarebbe inutile.

Le operazioni da fare sono:

Classi serializzabili per le comunicazioni

Viene definita la classe interna CoordinatorKey. Si tratta di una classe serializzabile che deriva da Object. Serve per la rappresentare una chiave del servizio, cioè il livello del g-nodo da coordinare. Tale classe contiene:


Viene definita la classe interna CoordinatorRecord. Si tratta di una classe serializzabile che deriva da Object. Serve per la rappresentare un record del servizio, cioè la memoria condivisa del g-nodo da coordinare. Tale classe contiene:


Viene definita la classe interna CoordinatorReserveRequest. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersRequest. Serve per la richiesta 'reserve'. Tale classe contiene:


Viene definita la classe interna CoordinatorReserveResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta per la richiesta CoordinatorReserveRequest. Tale classe contiene:


Viene definita la classe interna CoordinatorReplicaRecordRequest. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersRequest. Serve per la richiesta 'replica'. Tale classe contiene:


Viene definita la classe interna CoordinatorReplicaRecordSuccessResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta per la richiesta CoordinatorReplicaRecordRequest. Significa esito positivo. Tale classe non ha membri.


Viene definita la classe interna CoordinatorUnknownRequestResponse. Si tratta di una classe serializzabile che implementa l'interfaccia segnaposto (vuota) IPeersResponse. Serve come risposta per le richieste che non sono state riconosciute dall'implementazione del server. Tale classe non ha membri.