La classe Map
Rappresenta una mappa di oggetti generici (dataclass) con uno spazio di levels x gsize. Cioè 4 x 256.
Ricorda che il livello 0 contiene l'id dei singoli nodi, mentre il livello 3 contiene l'id dei gnodi più vasti. Il livello 4 non si specifica, consisterebbe in un unico gnodo che contiene l'intero dominio di IPv4.
Ogni spazio viene creato usando il costruttore dataclass con i parametri lvl e id, così che l'oggetto che rappresenta un nodo nella mappa può avere l'informazione di dove si trova nella mappa (al momento la classe RouteNode non ne fa uso).
La dataclass deve avere il metodo is_free per dire se lo spazio in questione è usato o no.
E' possibile segnalare la presenza di un nuovo nodo nella mappa. Si fa con il metodo node_add. In questo momento viene emesso il signal NODE_NEW.
E' possibile anche rimuovere un elemento dalla mappa. Si fa con il metodo node_del. In questo caso viene anche emesso il signal NODE_DELETED.
E' possibile anche resettare un intero livello o l'intera mappa senza far emettere alcun segnale (map_reset, level_reset). Questa tecnica è usata dopo aver fatto un re-hook in un diverso gnodo e aver reimpostato il nuovo IP su tutti i Nic attivi (vedi la classe Hook).
Inoltre la classe Map tiene traccia del numero di nodi presenti di ogni livello, cioè il numero di spazi per cui is_free() = False. Lo memorizza nel membro node_nb[lvl].
Oltre ad avere questo numero immediatamente pronto nel membro node_nb[lvl], e come controparte il numero di nodi liberi calcolati come differenza nel metodo free_nodes_nb(lvl), la classe fornisce anche il metodo free_nodes_list(lvl) che restituisce l'elenco degli id dei nodi liberi di livello lvl.
Importante: questi dati tengono conto anche del fatto che in IPv4 alcuni indirizzi non sono validi, tipo 192.168.* o 224.* etc.
Nella classe Map l'attributo me memorizza il proprio spazio, cioè il proprio Netsukuku-IP (abbreviato nip).
Un nip è indicato nella forma di una sequenza di ID per i vari livelli dallo 0 al più alto.
self.me = [1,1,168,192]
Notare che il primo elemento della sequenza è il livello 0 (l'id del singolo nodo)
Un altro modo di rappresentare uno spazio nella mappa è un intero, detto semplicemente ip, dato dal calcolo 192*2563+168*2562+1*2561+1*2560.
Per convertire tra le 2 notazioni si possono usare i metodi ip_to_nip e nip_to_ip.
Per descrivere le altre funzionalità, supponiamo di avere a disposizione un altro indirizzo nella variabile nip.
nip = [2,2,168,192]
Il metodo is_in_level ci dice se un certo nodo o gnodo appartiene allo stesso nostro gnodo di livello x. In questo caso self.is_in_level(nip,0) darebbe False;
invece self.is_in_level(nip,1) darebbe True.
Il metodo nip_cmp dice di 2 Netsukuku-IP quale sia il primo livello differente. La ricerca parte dall'ultimo elemento delle sequenze (levels -1). Tra i 2 nip citati prima
nip_cmp(self.me, nip)
dovrebbe restituire 1.
Il metodo lvlid_to_nip(lvl, id) partendo da lvl e id guarda nella mappa e restituisce il nip equivalente. Lo fa partendo dal proprio nip (self.me) sostituendo il livello lvl con id e azzerando i livelli sotto lvl.
pack e merge
La classe Map fornisce un metodo map_data_pack che restituisce in una struttura tutti i dati della mappa (tranne le dimensioni levels e gsize che sono considerate note a priori).
Per la precisione si tratta di una tupla di 3 elementi: il proprio NIP, una copia della lista di liste di oggetti dataclass, una copia della lista del numero di oggetti non liberi.
Notare che, per passare questa struttura ad un metodo remotable occorre che la classe usata come dataclass sia registrata come serializable con il modulo rencode.
Inoltre fornisce il metodo map_data_merge che usa come argomento una struttura dati dello stesso formato prodotto da map_data_pack.
Questo metodo verifica a quale livello sia il gnodo comune fra il suo attributo me e quello della mappa ricevuta. Lo fa con nip_cmp che ritorna il primo livello differente. I valori della mappa ricevuta il cui indice è maggiore o uguale a questo livello (ottenuto con nip_cmp) rappresentano gli stessi nodi per me e per il nodo della mappa ricevuta. Quelli inferiori rappresentano nodi diversi e non hanno significato per me.
Una volta stabilito quali valori della mappa ricevuta sono significativi per me, il metodo map_data_merge valorizza la mia mappa con i soli nodi della mappa ricevuta e resetta i livelli sottostanti.
In realtà il nome merge può essere fuorviante: non significa che i vecchi dati della propria mappa rimangono. Rimane solo il vecchio NIP e gli altri dati provenienti dall'altra mappa (di norma ricevuta da un nodo remoto) diventano significativi in quanto riferiti al nostro NIP.
E' usato nella classe MapP2P, derivata di Map, quando la classe P2PAll (vedi il modulo P2P) recupera la mappa dei partecipanti da un suo nodo vicino attraverso il metodo remotable pid_getall.
Un'altra classe derivata di Map, la classe MapCache del modulo coord, dichiara remotable lo stesso metodo map_data_merge e la classe Coord lo usa per passare i dati da un Coordinator Node al suo successore.