CHORD. Progettazione e realizzazione di un protocollo per la locazione di dati ne distribuito MATTEO CORBELLI

Documenti analoghi
Conseguenze Algoritmiche del fenomeno small world

P2p la teoria dei sistemi complessi per modellare reti p2p

Routing IP. IP routing

Scheme: struttura del programma e campo di azione

FILE E INDICI Architettura DBMS

ORDINE DI INSERIMENTO DELLE CHIAVI <35 >35

Lezione n.15. LA RETE EMULE-KADEMLIA to-peer Systems and Applications Capitolo 8

Informatica 3. Informatica 3. LEZIONE 21: Ricerca su liste e tecniche di hashing. Lezione 21 - Modulo 1. Introduzione (1) Introduzione (2) Ricerca:

4b. Esercizi sul livello di Rete Inoltro in IP

Strutture. Array dei nomi degli esami (MAX ESAMI è il massimo numero degli esami). Array con i crediti degli esami.

Organizzazione Fisica dei Dati (Parte II)

2 Reduced Dynamo: L Architettura e le Operazioni

Dati e Algoritmi I (Pietracaprina) Esercizi sul Text Processing

static dynamic random access memory

GESTIONE DELLA MEMORIA CENTRALE 6.1 D. - UNICAL

Implementazione di dizionari

Strutture di accesso ai dati: B + -tree

Homework assignment Ipv6 e protocolli di routing TUNNEL

Strutture di accesso ai dati: B + -tree

11.4 Chiusura transitiva

Inoltrare un messaggio.

Parte II: Reti di calcolatori Lezione 11 (35)

Instradamento in IPv4

Lezione n.10. Freenet Materiale didattico: articoli distribuiti a lezione

Strutture Dati per Inserimento Ordinato. Luca Abeni

Una breve introduzione all implementazione in C di algoritmi su grafo

Strutture dati per insiemi disgiunti

LINKEDLIST: implementazione iteratore. LINKEDLIST: iteratore INNERITERATOR INNERITERATOR

Lezione n.6 DHT: CHORD

Tecnologie e applicazioni web Autenticazione

Basi di Dati e Sistemi Informativi. Organizzazione fisica dei dati. Corso di Laurea in Ing. Informatica Ing. Gestionale Magistrale

SISTEMI DI ELABORAZIONE

Programmazione II. Lezione 9. Daniele Sgandurra 16/11/2010.

Simulazione di semafori e rotonde: verifica dell'efficienza al variare del traffico

Sommario. Tabelle ad indirizzamento diretto e hash Funzioni Hash

Strutture Dati per Inserimento Ordinato

Array e Oggetti. Corso di Laurea Ingegneria Informatica Fondamenti di Informatica 1. Dispensa 12. A. Miola Dicembre 2006

Liste concatenate. Violetta Lonati

Plazzotta Marco Sistemi e Reti Protocolli a livello di rete

Complementi ed Esercizi di Informatica Teorica II

INSERIRE I DATI NEL DATABASE

Parte II: Reti di calcolatori Lezione 7 (31)

PROBLEMA DEI CAMMINI MINIMI [CORMEN ET AL. CAP. 24] Il costo di cammino minimo da un vertice u ad un vertice v è definito nel seguente modo:

7.1 Progettare un algoritmo per costruire ciclo euleriano di un grafo non orientato.

Indici multilivello dinamici (B-alberi e B + -alberi) Alberi di ricerca - 1. Un esempio. Alberi di ricerca - 3. Alberi di ricerca - 2

Le liste. Prof. Francesco Accarino IIS Sesto San Giovanni Via Leopardi 132

Heap e code di priorità

Macchine astratte, linguaggi, interpretazione, compilazione

Esercizi Capitolo 7 - Hash

Massimo Benerecetti Tabelle Hash

SISTEMI DI ELABORAZIONE

Databases. Architettura di un DBMS: Struttura ad indice per i files, B + -Trees

GESTIONE DELLA MEMORIA CENTRALE

Lezione n.7 Distributed Hash Tables

Elezione di un leader in una rete ad anello

CORSO DI RETI DI CALCOLATORI II (Docente Luca Becchetti) Esercizi su instradamento e tabelle di routing 1

Ad ogni utente è legato un profilo che lo abilita all uso di alcune funzioni.

Lezione n.5 DISTIBUTED HASH TABLES: CHORD. Laura Ricci 10/03/2009

Le classi in java. Un semplice programma java, formato da una sola classe, assume la seguente struttura:

Prof. Roberto De Prisco. TEORIA - Lezione 10. ARP e RARP. Università degli studi di Salerno Laurea e Diploma in Informatica

Progetti Algoritmi e Strutture Dati A.A Si intende realizzare una coda di priorità mediante un max-heap.

2.2 Alberi di supporto di costo ottimo

Istruzioni per la Compilazione Online Domanda Servizio Civile

Ad esempio, creazione di una lista di numeri interi e di una lista di oggetti di tipo Persona:

Il linguaggio C. Puntatori e dintorni

Introduzione. Java HTTP. G. Prencipe

Tabelle Hash. Massimo Benerecetti. Informatica. Lezione n. Parole chiave: Inserire testo. Corso di Laurea:

Tecniche di Ordinamento dei Vettori

Sistemi distribuiti e reti di calcolatori

Istruzioni per la Compilazione Online Domanda Servizio Civile

UNIVERSITÀ DEGLI STUDI DI PAVIA FACOLTÀ DI INGEGNERIA. Algoritmi

Evoluzioni Software s.n.c. SLpw Guida all'uso Pag.1 di 49

Esercizi Union-Find e su Grafi. Ugo Vaccaro

I formati delle istruzioni

Lezione n.8 LPR- Informatica Applicata

Struttura di un applicazione Instant Developer

Strutture fisiche e strutture di accesso ai dati

Magazzino: software di gestione di un database di strumenti musicali

MANUALE UTENTE SCUOLE

Architetture di rete. 4. Le applicazioni di rete

Lezione n.4 DISTRIBUTED HASH TABLES: INTRODUZIONE 6/3/2009. Laura Ricci

Tecnologie e applicazioni web JSON Web Token (JWT)

Protocollo ARP IP forwarding

Esercizio 2: Algebra dei Puntatori e Puntatori a Puntatori

In questa lezione Strutture dati elementari: Pila Coda Loro uso nella costruzione di algoritmi.

Allocazione dinamica della memoria

IP forwarding Firewall e NAT

Convergenza più rapida. Maschere a lunghezza variabile. Minore traffico di routing. Trasferimento di dati affidabile (Reliable Transfer Protocol)

A lezione sono stati presentati i seguenti passi per risolvere un problema:

Gestione della memoria

Calcolatori Elettronici: indirizzi e oggetti

Comportamento del Sistema

Prima Lezione: Indirizzi IP Bit di rete Bit di host

Installazione e configurazione DSFPA (Datasoftware Fattura Pubblica Amministrazione)

VoipExperts.it - CISCO <=> AVAYA

SISTEMI DI ELABORAZIONE

Transcript:

CHORD Progettazione e realizzazione di un protocollo per la locazione di dati ne distribuito MATTEO CORBELLI

ABSTRACT Un problema fondamentale che pone a confronto applicazioni peer to peer è localizzare efficientemente in una rete il nodo che mantiene un particolare dato. Chord è un protocollo di ricerca distribuito che affronta questo problema. Chord fornisce supporto per una sola operazione: data una chiave, esso assegna la chiave ad un nodo. La locazione dei dati può essere facilmente implementata su Chord associando una chiave ad ogni dato, e mantenendo la coppia chiave/dato nel nodo a cui la chiave è assegnata. Chord mostra come i nodi possano effettuare efficientemente join o leave dal sistema, e possano continuamente rispondere alle richieste anche se il sistema è in continuo cambiamento. 1. INTRODUZIONE I sistemi e le applicazioni peer to peer sono sistemi distribuiti senza alcun controllo centralizzato o organizzazione gerarchica, dove l esecuzione del software in ogni nodo è equivalente in funzionalità. Una revisione delle caratteristiche delle recenti applicazioni peer to peer fornisce una lunga lista: memorizzazione ridondante, permanenza, selezione dei server vicini, anonimità, ricerca, autenticazione e naming gerarchico. Nonostante questo ricco set di caratteristiche, l operazione centrale nella maggior parte dei sistemi distribuiti è la locazione efficiente dei dati. Chord è un protocollo scalabile per la ricerca in sistemi dinamici peer to peer con frequenti arrivi e uscite di nodi. Il protocollo Chord supporta un operazione: data una chiave, assegna tale chiave ad un nodo. In base all applicazione che usa Chord, il nodo potrebbe essere responsabile per memorizzare un valore associato alla chiave. Chord usa una variante del consistent hashing per assegnare le chiavi ai nodi. Il consistent hashing tende a bilanciare il carico, dato che ogni nodo riceve all incirca lo stesso numero di chiavi, e coinvolge relativamente un piccolo movimento di chiavi quando i nodi entrano o escono dal sistema. I lavori precedenti sul consistent hashing assumono che i nodi siano informati sulla maggior parte dei nodi del sistema, rendendo impraticabile la scalabilità con un elevato numero di nodi. Per contrasto, ogni nodo Chord ha bisogno di informazione di routing riguardo ad un piccolo numero di nodi. Tre caratteristiche che distinguono Chord da altri protocolli di ricerca peer to peer sono la semplicità, la correttezza e le performance.

2. IL PROTOCOLLO CHORD Il protocollo Chord specifica come trovare le locazioni delle chiavi e come i nodi entrino o escano dal sistema. 2.1 Overview Innanzitutto Chord fornisce una computazione veloce distribuita di una hashing function che assegna le chiavi ai nodi responsabili per esse. Usa consistent hashing che ha diverse buone proprietà. Con alta probabilità la funzione hash bilancia il carico (tutti i nodi ricevono all incirca lo stesso numero di chiavi). Altrettanto con alta probabilità, quando un N esimo nodo entra (o esce) dalla rete, soltanto una frazione O(1/N) di chiavi viene mossa in una diversa locazione, il che è chiaramente il minimo necessario per mantenere un carico bilanciato. Chord fornisce la scalabilità del consistent hashing evitando il requisito che ogni nodo conosca tutti gli altri nodi. Un nodo Chord ha necessità di un piccolo numero di informazioni di routing relativamente agli altri nodi. Dal momento che questa informazione è distribuita, un nodo risolve la funzione hash comunicando con un piccolo numero di nodi. In una rete di N nodi, ogni nodo mantiene informazioni su circa un O(logN) di altri nodi, e la ricerca richiede O(logN) messaggi. Chord deve aggiornare l informazione di routing quando un nodo entra o esce dal sistema. 2.2 Consistent hashing La funzione di consistent hashing assegna ad ogni nodo e ad ogni chiave un identificativo di m bit usando una funzione di hash come SHA 1. L identificativo di un nodo è scelto calcolando l hash dell indirizzo IP del nodo, mentre l identificativo di una chiave è prodotto calcolando quello della chiave. Si userà per comodità il termine chiave per indicare la chiave e la sua immagine dovuta alla funzione hash. Altrettanto vale per il nodo. La lunghezza m dell identificativo deve essere abbastanza perché la probabilità che due nodi o chiavi abbiano lo stesso hash sia molto bassa. L hashing consistente assegna le chiavi ai nodi come segue. Gli identificativi sono ordinati in un identifier circle modulo 2 m. La chiave k è assegnata al primo nodo il cui identificativo è uguale o segue k nello spazio degli identificativi. Questo nodo è chiamato successor node della chiave k, denotato da successor(k). Se gli identificativi sono rappresentati come un cerchio di numeri da 0 a 2 m 1, allora successor(k) è il primo nodo in senso orario da k.

La Figura mostra un identifier circle con m=3. Il circle ha tre nodi: 0, 1, e 3. Il successore dell identificativo 1 è 1, così la chiave 1 dovrebbe essere allocata al nodo 1. Similmente la chiave 2 dovrebbe essere allocata al nodo 3, e la chiave 6 al nodo 0. Il consistent hashing è progettato per permettere ai nodi di entrare e lasciare la rete con il minimo disordine. Per mantenere l assegnazione effettuata dal consistent hashing quando un nodo n entra nella rete, inevitabilmente alcune chiavi assegnate al successore di n ora vengono assegnate ad n. Quando un nodo lascia la rete, ognuna delle sue chiavi viene riassegnata al successore di n. 2.3 Locazione scalabile delle chiavi Un numero veramente piccolo di informazioni di routing è necessario per implementare consistent hashing in un ambiente distribuito. Ogni nodo ha necessità di conoscere solo il nodo successore nel identifier circle. Le richieste per un dato id possono essere passate lungo l anello attraverso i puntatori ai successori fino a che non incontrano un nodo che succede l id. Una porzione del protocollo Chord mantiene questi puntatori ai successori, in modo da far sì che ogni ricerca sia risolta correttamente. Tuttavia questo schema di risoluzione è inefficiente: potrebbe richiedere di attraversare tutti gli N nodi per trovare l assegnazione adeguata. Per accelerare questo processo, Chord mantiene un informazione di routing addizionale. Questa informazione addizionale non è essenziale per la correttezza, che è garantita nel momento in cui l informazione sul successore viene mantenuta correttamente. Come prima, consideriamo m il numero di bit nell id nodo/chiave. Ogni nodo, n, mantiene una tabella di routing con al più m elementi, chiamata finger table. L i esimo elemento nella tabella del nodo n contiene l identità del primo nodo, s, che succede n di almeno 2 i 1 nel identifier circle, ovvero s =

successor(n + 2 i 1 ) dove 1<=i<=m (tutto moldulo 2 alla m). Chiamiamo il nodo s i esimo finger del nodo n. Un elemento della finger table include insieme il Chord identifier e l indirizzo IP(e numero di porta) del nodo rilevante. Notare che il primo finger di n è l immediato successore nel identifier circle ; per convenienza ci riferiremo ad esso come al successore piuttosto che al primo finger. Nell esempio mostrato in Fig. (b), la finger table del nodo 1 punta ai nodi successori degli identifiers (n + 2 0 )mod 2 3 = 2, (n + 2 1 )mod 2 3 = 3, e (n + 2 2 )mod 2 3 = 5, rispettivamente. Il successore del identifier 2 è il nodo 3, dal momento che è il primo nodo che segue 2, il successore dell identifier 3 è il nodo 3, e il successore di 5 è il nodo 0. Questo schema ha due importanti caratteristiche. Primo, ogni nodo mantiene informazione riguardo ad un piccolo numero di altri nodi, e conosce di più circa i nodi più prossimi che lo seguono nel identifier circle piuttosto che sui nodi molto lontani. Secondo, una finger table di un nodo generalmente non contiene abbastanza informazioni per determinare il successore di un arbitraria chiave k. Per esempio, il nodo 3 in Fig.3 non conosce il successore di 1, e il successore del nodo 1 non appare nella finger table del nodo 3. Cosa succede quando un nodo n non conosce il successore di una chiave k? Se n può trovare un nodo il cui ID è più vicino del proprio a k, allora tale nodo conoscerà di più riguardo al identifier circle nella regione di k di quanto sappia n. Quindi n cerca nella sua finger table un nodo j il cui ID preceda k da vicino, e inoltra a j la richiesta. Ripetendo questo processo, n impara circa i nodi con ID più vicini e più vicini a k. Introduciamo la funzione find_successor che lavora trovando l immediato nodo predecessore dell identificativo desiderato; il successore di tale nodo deve essere il successore dell identificativo. Quando un nodo esegue cerca un predecessore, funzione find_predecessor, contatta una serie di nodi muovendosi avanti nel Chord circle verso l id. Se il nodo contatta un nodo n tale che l identificativo si trova tra n e il suo successore, find_predecessor termina e restituisce n. Altrimenti il nodo n chiede a n cosa n conosce riguardo a chi precede l id più da vicino. Quindi l algoritmo fa sempre progressi verso il predecessore dell id. Come esempio,

consideriamo il Chord ring in Fig. 3(b). Supponiamo che il nodo 3 voglia trovare il successore dell identifier 1. Dato che 1 appartiene all intervallo circolare [7,3), appartiene a 3.finger[3].interval (finger[i].interval è un intervallo (finger[i].start, finger[i+1].start)); il nodo 3 quindi verifica il terzo elemento nella sua tabella, che è 0. Dato che 0 precede 1, 3 chiederà al nodo 0 di trovare il successore di 1. Successivamente, il nodo 0 inferirà dalla sua finger table che il successore del id 1 è il nodo 1 stesso, e restituisce il nodo 1 al nodo 3. 2.4 Ingresso dei Nodi In una rete dinamica, i nodi possono entrare (e lasciare) il sistema ad ogni momento. Il principale cambiamento nell implementare queste operazioni è preservare l abilità di allocare ogni chiave nella rete. Per mantenere questo scopo, Chord ha bisogno di preservare due invarianti: 1. Ogni successore di un nodo è mantenuto correttamente. 2. Per ogni chiave k, successor(k) è responsabile per k. In modo da rendere la ricerca più veloce, è anche desiderabile che le finger table siano tenute corrette. Questa sezione mostra come mantenere questi due invarianti quando un singolo nodo entra nel sistema. Prima di descrivere le operazioni di entrata, mostriamo le sue performance. Per semplificare i meccanismi di entrata e uscita, ogni nodo in Chord mantiene un puntatore al predecessore. Il puntatore al predecessore di un nodo contiene il Chord identifier e l indirizzo IP dell immediato predecessore di tal nodo, e può essere usato per percorrere in senso antiorario l identifier circle. Per preservare i suddetti invarianti stabiliti, Chord deve eseguire tre fasi quando un nodo entra nella rete: 1. Inizializza il predecessore e i finger del nodo n 2. Aggiorna i finger e i predecessori dei nodi esistenti per riflettere l aggiunta di n 3. Notifica a livello software più alto in modo che si possa trasferire lo stato associato alle chiavi di cui il nodo n ora è responsabile Assumeremo che il nuovo nodo impari l identità di un nodo Chord esistente n da qualche meccanismo esterno. Il nodo n usa n per inizializzare il suo stato e aggiungere se stesso alla rete Chord esistente, come segue. Inizializzazione dei finger e del predecessore: Il nodo n impara il suo predecessore e i suoi finger chiedendo a n di fare una ricerca. Ingenuamente eseguendo

find_successor per ognuno degli m elementi della finger table potrebbe essere necessario un tempo di esecuzione pari a O(m logn). Per ridurre questo, n controlla se l i esimo finger è anche l i+1 esimo finger corretto, per ogni i. Questo avviene quando finger[i].interval non contiene alcun nodo, e quindi finger[i].node >= finger[i+1].start. Si può mostrare come il cambiamento riduca il numero aspettato di elementi finger che devono fare ricerca a un O(logN). Aggiornamento dei finger dei nodi esistenti: Il nodo n avrà bisogno di essere inserito nelle finger table di alcuni nodi esistenti. Per esempio in Fig. (a), il nodo 6 diventa il terzo finger dei nodi 0 e 1, e il primo e il secondo finger del nodo 3. La funzione update_finger_table aggiorna le esistenti finger table. Il nodo n diventerà l i esimo finger del nodo p se e solo se (1) p precede n di almeno 2 i 1, e (2) l i esimo finger del nodo p succede n. Il primo nodo, p, che unisce queste due condizioni è l immediato predecessore di n 2 i 1. Così, per un dato n, l algoritmo inizia con l i esimo finger del nodo n e continua a camminare in senso anti orario sul identifier circle finchè non incontra un nodo il cui i esimo finger precede n. Trasferimento delle chiavi: L ultima operazione che deve essere eseguita quando un nodo entra nella rete è spostare tutta la responsabilità sulle chiavi di cui ora il nuovo nodo è il successore. Cosa esattamente questo comporti dipende dal software di più alto livello usando Chord, ma tipicamente potrebbe riguardare lo spostamento dei dati associati ad ogni chiave nel nuovo nodo. Il nodo n può diventare il successore solo delle chiavi per cui era precedentemente responsabile il nodo che segue n immediatamente, così solo n deve contattare quel nodo per trasferire la responsabilità per tutte le chiavi rilevanti.

3. PROGETTAZIONE DEL SISTEMA In questo paragrafo vengono analizzate le implementazioni delle varie parti del sistema. 3.1 Configurazione del sistema Come detto in precedenza la topologia della rete è una struttura ad anello, in cui ogni nodo prende una posizione determinata dall hashing del suo indirizzo costituito da indirizzo IP + porta. Ogni nodo Chord ha la seguente struttura: Successore: nodo che succede all interno del identifier circle Predecessore: nodo che precede il nodo Finger Table: tabella di m elementi (nel caso implementato 8) che servono per l efficienza dell algoritmo Vettore delle chiavi di cui il nodo è responsabile Mentre la Finger Table è strutturata come segue: l i esimo elemento di questa tabella ha i seguenti campi Finger[i].start = (n+2 i 1 )mod 2 m (dove n è l id del nodo in questione) Finger[i].interval = [finger[i].start,finger[i+1].start) Finger[i].node = primo nodo maggiore o uguale a finger[i].start 3.2 Locazione delle chiavi In questo paragrafo vediamo come è stata implementata la funzione che alloca le chiavi all interno del sistema. Ogni dato che deve essere inserito all interno della rete, ha necessità di conoscere un qualsiasi nodo facente parte della rete stessa. A tale nodo viene effettuata una richiesta da parte di chi desidera inserire nel sistema il dato. Inoltre per il suddetto dato deve essere fornita una chiave, di cui viene successivamente fatto un hashing fornendo l identificativo in modo da distribuire uniformemente i dati all interno del sistema (supponiamo nella nostra implementazione che venga direttamente fornito l identificativo di tale chiave). Al nodo specificato viene quindi inoltrata una richiesta, in cui viene inviato l identificativo di cui sopra, dove si chiede di trovare il nodo che immediatamente succede l identificativo e che sarà il

responsabile del dato. Il nodo a cui viene fatta la richiesta cerca il predecessore dell identificativo osservando se l identificativo si trova tra se e il suo successore; in questo caso restituisce il suo successore, mentre se il suo identificativo corrisponde all i esimo elemento start della finger Table restituisce l i esimo successore della tabella. Altrimenti cerca nella finger Table il nodo più vicino all identificativo di cui è a conoscenza a cui ridirigere la richiesta e ne restituisce l indirizzo. A differenza del protocollo dove la richiesta veniva inoltrata dal nodo stesso, l implementazione vuole che l indirizzo a cui ridirigere la richiesta venga restituito al mittente, il quale si occuperà di avviare una nuova comunicazione. Si è scelta questa modalità per diminuire la latenza dei messaggi all interno della rete. Il procedimento appena descritto va effettuato iterativamente fino a quando non si trova il nodo che succede l identificativo. Una volta trovato il nodo, ci si connette a tale nodo e gli si passa l identificativo (è ovviamente pensabile e dovuto, ai fini di un corretto funzionamento, l implementazione della trasmissione oltre che dell identificativo anche dell intero file corrispondente). 3.3 Entrata dei nodi nella rete Osserviamo ora come è stata implementato il join dei nodi all interno della rete. Come detto in precedenza, quando un nodo decide di entrare nel sistema deve conoscere l indirizzo di un nodo già esistente. Le fasi che devono essere seguite sono principalmente tre: Join: Aggiornamento Trasferimento dei dati

3.3.1 Join Innanzitutto si connette al nodo conosciuto ed invia la richiesta di find_successor a tale nodo, che, in modo del tutto simile a quello descritto al caso in cui si cerca la locazione di una chiave, trovando il predecessore dell identificativo del nodo specificato, restituisce se stesso e il suo successore permettendo così al nodo di settare il suo predecessore (il nodo stesso) e il suo successore. In seguito sempre mantenendo la connessione invia una richiesta in cui setta se stesso come successore del nodo che lo precede. Connettendosi poi al suo successore conclude il processo fornendo se stesso come predecessore. In questo modo viene garantita la correttezza del protocollo. Inoltre calcola la sua Finger Table utilizzando gli accorgimenti visti nella descrizione del protocollo per utilizzare il minor numero di messaggi possibile evitando un overload di comunicazione. Riportiamo per chiarezza il ragionamento svolto in precedenza: n controlla se l i esimo finger è anche l i+1 esimo finger corretto, per ogni i. Questo avviene quando finger[i].interval non contiene alcun nodo, e quindi finger[i].node >= finger[i+1].start. 3.3.2 Aggiornamento Nella fase di aggiornamento il nodo deve permettere alle finger table degli altri nodi di aggiornarsi; perché una finger table subisca variazioni dall entrata nel sistema di un nodo occorrono due condizioni. Il nodo n diventerà l i esimo finger del nodo p se e solo se (1) p precede n di almeno 2 i 1, e (2) l i esimo finger del nodo p succede n. 1. Per ogni i si calcola n 2 i 1, che chiameremo id, e si invia la richiesta sempre al nodo conosciuto in cui si chiede il predecessore dell id.

2. Al nodo restituito dall operazione precedente viene mandato un messaggio di aggiornamento della tabella; il nodo in questione verifica se deve modificare il successore dell i esimo finger e se è così oltre ad apportare le modifiche restituisce il suo predecessore a cui viene inoltrata la stessa richiesta. 3.3.3 Trasferimento dei dati Il nodo si connette al suo successore, il quale al momento attuale tiene la responsabilità di tutti i dati che devono essere spostati. In particolare invia una richiesta di aggiornamento dei dati passando anche l identificativo del suo predecessore. In questo modo il nodo a cui viene fatta la richiesta per ogni chiave può verificare se l identificativo della chiave si trova tra l identificativo ricevuto e quello del suo predecessore. Se l esito della verifica è positivo allora trasferisce la responsabilità del dato. Questa operazione viene implementata molto semplicemente come segue: Viene inviato l identificativo della chiave del dato Tale identificativo permette di creare a lato del nuovo nodo responsabile una chiave che viene poi aggiunta al vettore di chiavi D altra parte tale chiave viene eliminata dal vettore di chiavi del nodo che trasferisce la responsabilità 3.4 Leave di un nodo Se un nodo decide di lasciare la rete utilizza una procedura del tutto simile a quella di entrata. Le fasi sono le stesse descritte in precedenza. Innanzitutto occorre garantire la correttezza della rete andando a cancellare se stesso dal successore e dal predecessore. Mentre è collegato al successore inizia anche la fase di trasferimento dei dati, in quanto tutti i dati di cui è responsabile il nodo diventano di responsabilità del successore. In ultimo aggiorna le finger table degli altri nodi, la cui modalità di comunicazione con gli altri nodi è la stessa vista in precedenza.

4. MESSAGGI SCAMBIATI Find_Successor Parametri: l id di cui si vuole trovare il successore Funzione: verifica se l id specificato si trova tra se e il proprio successore Risposta: se la verifica ha esito positivo restituisce il messaggio Find, il proprio successore e se stesso; altrimenti invia il messaggio Redirect Request seguito dall indirizzo il cui elemento della finger table ha l id all interno del suo intervallo. Find_Predecessor Parametri: l id di cui si vuole trovare ilpredecessore Funzione: verifica se l id specificato si trova tra se e il proprio successore Risposta: se la verifica ha esito positivo restituisce il messaggio Find e se stesso; altrimenti invia il messaggio Redirect Request seguito dall indirizzo il cui elemento della finger table ha l id all interno del suo intervallo. Set_Successor Parametri: indirizzo e id di un nodo Funzione: settare il successore con le nuove informazioni ricevute Risposta: conferma dell avvenimento dell operazione Set_Predecessor Parametri: indirizzo e id di un nodo Funzione: settare il predecessore con le nuove informazioni ricevute Risposta: conferma dell avvenimento dell operazione Search_Node Parametri: l id di cui si vuole trovare il successore Funzione: verifica se l id specificato si trova tra se e il proprio successore Risposta: se la verifica ha esito positivo restituisce il messaggio Find e il proprio successore; altrimenti invia il messaggio Redirect Request seguito dall indirizzo del suo successore.

Get_Successor Parametri: nessuno Funzione: restituire il successore del nodo Risposta: indirizzo e id del successore Get_Predecessor Parametri: nessuno Funzione: restituire il predecessore del nodo Risposta: indirizzo e id del predecessore Update_Finger_Table Parametri: indirizzo, relativo id e un intero i che serve da indice Funzione: verifica se id appartiene all intervallo [proprio id, id di finger[i]) Risposta: in caso positivo risponde continue e l indirizzo a cui inoltrare la medesima richiesta; altrimenti risponde con stop. Delete_Me_From_Finger_Table Parametri: nodeid del nodo da eliminare, indice i e indirizzo del successore Funzione: verifica se l i esimo finger ha l id uguale a nodeid, nel qual caso lo modifica con il successore passato Risposta: in caso positivo risponde continue e l indirizzo a cui inoltrare la medesima richiesta; altrimenti risponde con stop. Find_Successor_Key Parametri: il keyid di cui si vuole trovare il successore Funzione: verifica se il keyid specificato si trova tra se e il proprio successore Risposta: se la verifica ha esito positivo restituisce il messaggio Find e il proprio successore; altrimenti invia il messaggio Redirect Request seguito dall indirizzo il cui elemento della finger table ha il keyid all interno del suo intervallo. Transfer_Key Parametri: keyid Funzione: trasferire nel nodo i dati relativi alla keyid

Risposta: risultato della transizione Update_Vector_Key Parametri: id del predecessore del nodo che fa richiesta Funzione: valuta se per ogni chiave di cui è responsabile il keyid appartiene all intervallo [id del predecessore del nodo che fa richiesta, id del nodo che fa richiesta) Risposta: se appartiene all intervallo restituisce transfer seguito dall id della chiave da trasferire, altrimenti nothing Delete_Node Parametri: id del nodo da eliminare Funzione: ha la responsabilità di occuparsi di tutto lo scambio di messaggi relativo all eliminazione di un nodo Risposta: nessuna 5. RIFERIMENTI STOICA, I., MORRIS, R., KARGER, D., KAASHOEK, M. F., AND BALAKRISHNAN, H. Chord: A scalable peer-to-peer lookup service for internet applications. In Proc. ACM SIGCOMM (San Diego, 2001).