Files
progettoso/README.md

178 lines
9.1 KiB
Markdown
Raw Normal View History

2022-05-20 19:53:43 +02:00
# Introduzione
2022-03-08 17:26:13 +01:00
2022-05-20 19:53:43 +02:00
Il progetto realizzato consiste in un file storage gestito da un server
multithreaded e un client che possono comunicarsi attraverso le funzioni
implementate dall'API. Il codice è presente sulla repository privata al
link: [tautocrono.it](http://tautocrono.it).\
Si può accedere usando le credenziali:
::: center
Username Password
---------- -----------------
2023-03-27 22:57:18 +02:00
Guest
2022-05-20 19:53:43 +02:00
:::
Il progetto è compilato in modo automatico tramite makefile con i
target: all, test1, test2, test3. Il target all fa partire un'altro
sottoprocesso make che eseguirà il target multi con degli argomenti
aggiuntivi, tipo `-j` in modo da rendere la compilazione multiprocesso.
Ci sono anche i target clean e cleanall che rimuovono gli eseguibili
creati con i precedenti target.
Sono inclusi anche dei file per testare le funzionalità del client e del
server nella cartella *testFiles*.
Gli oggetti vengono creati nella directory *obj/*, mentre gli eseguibili
vengono creati nella directory *build/*. La directory *src/* contiene il
codice che fa parte del main del server e del client; il resto del
codice è contenuto nella directory *lib/*.
È stata implementata sia la politica di rimpiazzamento FIFO che la
politica LRU.
# Server
Il server prende come unico argomento il path al file di configurazione.
Un esempio di file di configurazione è `config.ini` presente nella root
del progetto. La struttura del file è analoga a quella di un file
[INI](https://en.wikipedia.org/wiki/INI_file), quindi l'ordine degli
argomenti dentro a sezione è irrilevante. Il file di configurazione
viene letto da una libreria di \"*terza parte*\" ottenuta da
[rxi/ini](https://github.com/rxi/ini). Si sarebbe potuto usare la
libreria [Glib](https://gitlab.gnome.org/GNOME/glib) tuttavia si è
riscontrata una memory leak con valgrind.
La libreria threadpool e la libreria conn sono state tratte dalla
soluzione dell'esercitazione 11 pubblicata sulla pagina del corso. Si è
preferito l'utilizzo di `strsep` invece di `strtok` o `strtok_r` sia nel
programma server che client. Il codice è stato adattato leggermente da
quello presente nella libreria C GNU
([strsep](https://sourceware.org/git/?p=glibc.git;a=blob;f=string/strsep.c;h=b534a1ec17fd2e91087af04abe1c3f1ac3e74ce0;hb=HEAD))
in modo da utilizzare la funzione omonima su piattaforme BSD e MacOS.
## Main
Il thread principale accetta le connessioni in arrivo da i client su un
socket di tipo `AF_UNIX` con nome di default *socket*. Viene interrotto
dal thread `sighandler_thread` se ricevuto un segnale fra: `SIGHUP`,
`SIGINT` o `SIGQUIT`.
## serverWorker
Il thread main dopo aver accettato la connessione di un client crea un
thread \"*worker*\" che aggiunge alla threadpool (definita nei file
omonimi). Ogni worker serve una singola richiesta da parte di un
qualsiasi client connesso. Se le richieste contemporanee dei client
fossero maggiori della dimensione della threadpool, le richieste vengono
accodate in una *pending queue* di dimensione stabilita nel file di
configurazione del server. La singola richiesta viene letta dal worker
thread e viene poi eseguita la funzione associata alla richiesta
presente nella libreria *apiFile*. Alcune di queste operazioni possono
richiedere la presa di una lock associata a un file, quindi per gestire
queste richieste si è fatto uso di una struttura di dati interna
`waiting_t`. La richiesta accodata non è quindi gestita dal thread
corrente, ma dal thread che rilascerà la lock al file associato. Si
evitano quindi *polling* o l'utilizzo di *condition*.
## sighandler_thread
Il thread gestisce i segnali in arrivo al server. Se il segnale ricevuto
è di tipo `SIGINT` o `SIGQUIT`, il server termina prima possibile. Se il
segnale ricevuto è del tipo `SIGHUP` invece si attende che ogni worker
abbiano servito le richieste dei client precedentemente connessi.
# Storage
Il server gestisce la memorizzazione dei file tramite la libreria
*fileQueue*. Nel header file *fileQueue.h* la costante `ALGORITHM`
imposta la politica di rimpiazzamento. Le funzioni che differiscono in
comportamento sono: `dequeueN`, `lockFileInQueue`, `unlockFileInQueue`,
`openFileInQueue`, `find`, `request`, `searchFile`. Infatti l'elemento
che richiedono come input viene accodato alla fine della struttura nella
politica LRU. Le altre funzioni invece non modificano l'ordine degli
elementi.
La struttura principale è una linked list chiamata `nodeT` che contiene
i dati del file associato e un puntatore al prossimo elemento. Dato che
l'operazione di scrittura di un file in memoria non è atomica, si è
deciso di usare due misure dell'occupazione della memoria di un file:
`size` e `valid`. L'unico momento in cui potrebbero essere differenti è
quando il client ha richiesto la scrittura di dati, comunicando la
dimensione, quindi il server \"alloca\" tale dimensione come `size`,
lasciando invariato la dimensione `valid`. Dopo che il client ha inviato
i dati da inserire nel file, le dimensioni dovrebbero di nuovo
combaciare. Una singola operazione di scrittura può richiedere più di un
file rimosso per aver abbastanza memoria libera; questa operazione viene
attuata atomicamente e viene considerata come un'unica operazione di
rimpiazzamento.
# Logging
Il server usa la libreria \"`taglialegna`\" per scrivere i messaggi di
log su un file specificato nel file di configurazione. Le scritture
vengono sincronizzate tramite lock. Sono state scritte due funzioni che
permettono la scrittura: `taglia_write`, `taglia_log`. `taglia_log`
scrive anche un timestamp prima del messaggio di log. All'inizio
dell'esecuzione del server vengono stampate alcune informazioni lette
dal file di configurazione, come ad esempio la dimensione del threadpool
o la dimensione massima della struttura di cache del server. Al termine
vengono invece scritti alcuni dati di sunto delle operazioni, ad esempio
il numero massimo di file memorizzati o la dimensione massima raggiunta.
# Client
Oltre alle funzioni di API richieste dalla specifica è stata
implementata la funzione `setDirectory`, perchè si è interpretata come
se le opzioni `-d` e `-D` dovessero poter essere associate a più di un
comando. Tuttavia questa funzionalità non è presente nel client in modo
diretto dato che vengono inserite `-d`/`-D /dev/null` fra due opzioni
`-w`/`-W` o `-r`/`-R` successive. L'opzione `-d /dev/null` o
`-D /dev/null` è stata ottimizzata leggermente in modo da non fare
chiamate di sistema.\
Il client esegue prima l'opzione `-f`, in seguito l'opzione `-t`, poi in
ordine tutti gli altri argomenti. In caso di errore durante la scrittura
su un file dopo la creazione, il client richiede la rimozione del file.\
Per la comunicazione con il server si è optato per un protocollo
ispirato a quello html o ftp, costituito da due cifre, la prima denota
il risultato (positive completion/transient negative
completion/permanent negative completion), la seconda invece è una
specifica della prima. Non tutte le combinazioni sono state usate.
::: center
Number Meaning
---------------------------- ------------------------------------------------------------
2[\*]{style="color: gray"} positive completion reply
4[\*]{style="color: gray"} transient negative completion reply (command not executed)
5[\*]{style="color: gray"} permanent negative completion reply (errors)
[\*]{style="color: gray"}0 syntax
[\*]{style="color: gray"}1 information
[\*]{style="color: gray"}2 connection
[\*]{style="color: gray"}5 file system
:::
Di seguito una tabella in cui si associa ogni numero al codice usato:
::: center
Number Meaning Code
--------------------------- --------------------------------- ----------------------------
20 OK `MEOK`
[21]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
[22]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
25 file purged `MEFP`
[40]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
[41]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
42 shutting down `MESD`
45 requested file action not taken `MENT`
50 syntax error `MESY`
[51]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
[52]{style="color: gray"} [not used]{style="color: gray"} [`-`]{style="color: gray"}
55 server error `MESE`
:::
Il client invia per primo la dimensione del messaggio come `long`, poi
il messaggio. Il server risponde prima con due caratteri che
simboleggiano is response number, seguito dal errno se si è riscontrato
un errore, oppure i file richiesti o espulsi. Il server per inviare i
file richiesti o espulsi, prima invia il numero di file, poi per ogni
file la dimensione come `int64_t` e poi successivamente il file.