This is an old revision of the document!
Hackathon-ul presupune rezolvarea unui task propus de către echipa de Sisteme de Operare, din materia parcursă în cadrul cursului si laboratoarelor de SO. Challenge-ul este propus spre a fi rezolvat de către o echipă de 2 studenți înscriși la cursul de Sisteme de Operare. Primele 3 cele mai bune implementări vor fi recompensate cu premii. În timpul desfășurării hackathon-ului, echipele vor primi live support din partea echipei de SO.
Sâmbătă, 7 mai 2022, în intervalul 9:00 - 17:30.
Hackathonul se desfășoară în mod hibrid. O echipă poate participa fie fizic (la facultate), fie online (pe MS Teams).
Echipele participante se vor putea înscrie la hackathon prin completarea formularului de aici până pe data de 4 mai 2022, ora 14:00. Se vor alege maxim 20 de echipe.
Fiecare membru al echipelor câștigătoare va fi premiat, în funcție de locul obținut:
Toate echipele participante sunt eligibile de echivalarea unui punct din notele pentru temă în cadrul materiei Sisteme de Operare (în funcție de complexitatea implementării și stadiului proiectului dezvoltat în timpul hackathonului).
Echipele câștigătoare vor fi anunțate marți, 10 mai 2022.
Dezvoltarea trebuie făcută exclusiv pe mașinile virtuale SO.
local
(pe calculatoarele voastre sau în mașinile voastre virtuale). Pot să apară diferențe între local și VM-uri, iar, pentru corectare, noi vom considera doar mașinile virtuale de la SO.
O soluție de in-memory cacher este, în general, un serviciu care permite stocarea (în memoria RAM care acționează ca un cache) a unor perechi key:value
pentru a facilita modul de lucru al altor servicii. Cele mai cunoscute soluții de in-memory cache sunt Memcached și Redis.
Principalul avantaj al folosirii unei astfel de aplicații este optimizarea păstrării și prelucrării datelor de care au nevoie serviciile, ușurând, în acest mod, încărcarea serviciilor.
Aceste aplicații sunt folosite, în special, în cadrul unei infrastructuri distribuite. Soluția de in-memory caching are rolul unui server, iar serviciile care o folosesc acționează ca niște clienți. Clienții fac subscribe către soluția de in-memory caching și comunică, de obicei, prin intermediul sockeților pentru a transmite datele care trebuie ținute în cache. Există numeroase companii și produse care folosesc soluții de in-memory caching. Găsiți aici exemple de companii care folosesc Redis și aici companii care folosesc memcached.
În cadrul hackathonului de la SO, ne propunem să implementăm o astfel de soluție de in-memory caching, însă ne vom axa doar pe partea de stocare și prelucrare de loguri. ElasticSearch și rsyslog sunt utilitare dedicate, folosite în industrie, pentru prelucrarea rapidă a liniilor de log și stocarea lor în mod optim.
Pentru a asigura buna funcționare a unui serviciu, existența logurilor este crucială. Pe baza acestora, putem verifica dacă totul funcționează corespunzător și putem să facem debugging atunci când ceva nu funcționează în modul așteptat. Toate serviciile oferă posibilitatea de logare de date (vezi directorul /var/log
în Linux și utilitarul EventViewer în Windows). Pentru a ușura managementul acestor date de logging și a nu încărca serviciul principal pentru operații de stocare, scriere, prelucrare, dorim să implementăm o aplicație care face acest lucru pentru noi.
Astfel, folosind conceptele învățate în cadrul cursurilor și laboratoarelor de Sisteme de Operare (thread-uri, sincronizare, lucru cu fișierele, lucru cu memoria), dorim să implementăm un in-memory cacher, numit liblmc
(liblogmemcache), pe modelul oferit de Redis și Memcached. Aplicația noastră va funcționa ca o bibliotecă expusă clienților (clienții au acces la funcțiile ce trebuie apelate) și un proces daemon care reprezintă serverul nostru care acceptă conexiuni de la clienți, salvează logurile în memorie, respectiv în fișiere de log, generează statistici sau oferă înapoi anumite linii de log.
Realizați o implementare minimală a unui serviciu cross-platform de in-memory cache care reține în memorie (RAM) logurile provenite de la diferite servicii din sistem. Proiectul va funcționa ca o arhitectură client-server, prin care:
lmcd
)connect
- Conectarea clientului la serviciul de in-memory cachingsubscribe
- Același lucru ca opțiunea de connect
(deoarece avem disconnect
și unsubscribe
, subscribe
are rolul de a adăuga uniformitate în lista de comenzi);add log
- Adăugarea unei linii de log în cache folosind lmcd
;flush
- Forțarea scrierii log-urilor într-un fișier de log per proces/serviciu conectat. Datele se salvează într-un fișier numit <logfile_path>/<service_name>.log
(ex: logs_logmemcache/client1.log
).getlogs [t1 [t2]]
- Extragerea (din memorie) a log-urilor dintre timestamp-ul t1 și timestamp-ul t2. Dacă t2 nu este specificat, atunci se extrag toate datele începând cu timestamp-ul t1. Dacă nici t1 și nici t2 nu sunt specificate, se extrag toate log-urile din memorie.disconnect
- închiderea conexiunii curente.unsubscribe
- dealocarea din memorie a datelor despre client și închiderea conexiunii curente.LINE_SIZE
). Astfel, o pagină de memorie virtuală poate reține PAGE_SIZE / LINE_SIZE
log-uri.Makefile
furnizate). Veți împărți codul în cod independent de platformă și cod dependent de platformă.libc
doar pentru afișarea la stdout
/stderr
a diverselor mesaje (printf
, fprintf
etc.) sau formatare de șiruri (sprintf
, snprintf
etc.). Pentru lucrul cu fișierele de log sau alte fișiere auxiliare, se vor folosi funcțiile POSIX/Win32.Proiectul conține două elemente principale:
struct lmc client; lmc_connect(&client); lmc_add_log(client, “add this line”); <...> lmc_disconnect(client);
send
/recv
pe care le puteți folosi în comunicare.
Pentru funcționalitatea extinsă (bonusuri) pe baza căreia se poate face departajarea între echipele câștigătoare, puteți aduce modificări atât în server, cât și în bibliotecă.
Structura de fișiere prezentată mai jos conține următoarele componente:
include
- director în care se află toate headerele folosite în proiectinclude/lmc.h
- header care expune funcțiile de bibliotecă; headerul care trebuie inclus de fiecare client pentru a putea folosi biblioteca lmc;include/server.h
- header care expune funcțiile dependente de arhitectură folosite de către serverinclude/utils.h
- header care expune funcțiile utile/ datele comune folosite de către bibliotecă și server.liblmc
- director care contine implementarea pentru bibliotecă.liblmc/lmc.c
- fișier sursă cu implementarea funcțiilor de bibliotecăliblmc/{lin,win}/lmc_os.c
- fișiere sursă cu apelurile funcțiilor specifice sistemului de operare (POSIX, Win32) folosite de către bibliotecăliblmc/lmc.def
- funcțiile expuse de bilbiotecă. Fișierul este necesar la compilarea bibliotecii liblmc.dll
pe Windows (nu mai este nevoie să folosim declspec(dllexport) și
declspec(import)
pentru folosirea bibliotecii partajate).Makefile.{lin,win}
- fișiere Makefile pentru Linux, respectiv, pentru Windows. În Linux, compilarea se face folosind utilitarul make din bash. În Windows, compilarea se face folosind utilitarul nmake din PowerShell. Atenție! Pe Linux, biblioteca se numește liblmc.so și executabilul lmcd. Pe Windows, biblioteca se numește liblmc.dll și executabilul se numbește lmcd.exe.server
- directorul care conține implementarea serverului.server/server.c
- funcționalitatea serveruluiserver/{lin,win}/server_os.c
- fișiere sursă cu apelurile funcțiilor specifice sistemului de operare (POSIX, Win32) folosite de către serverutils.c
- implementarea diverselor funcții utile care pot fi folosite de către server și bibliotecă.. |--- include | |--- lmc.h | |--- server.h | |--- utils.h |--- lmc | |--- lin | |--- lmc_os.c | |--- lmc.c | |--- lmc.def | |--- win | |--- lmc_os.c |--- Makefile.lin |--- Makefile.win |--- server | |--- lin | |--- server_os.c | |--- server.c | |--- win | |--- server_os.c |--- utils.c
Pentru funcționalitatea de bază a aplicației, trebuie implementate următoarele:
connect
- logica de conectare a unui client, păstrarea numelui clientului, precum și inițializarea structurilor interne.add
- adăugarea unei linii de log primite de la un client la cache-ul specific al clientului. O linie de log trimisă de la client către server are dimensiunea maximă LINE_SIZE și conține timestamp-ul (de la client) concatenat cu linia de log. Timestamp-ul are un format predefinit (TIME_FORMAT) și o lungime fixă (TIME_SIZE).flush
- scrierea logurilor pe disc. Datele se salvează într-un fișier numit <logfile_path>/<service_name>.log
(ex: logs_lmc/client1.log
).stats
- obținerea unor statistici despre numărul de pagini și memoria utilizată de un client. Formatul statisticilor este dat de către șirul STATS_FORMAT. getlogs
- obținerea tuturor log-urilor unui client (funcționalitatea de bază nu tratează cazul în care apar timestamp-uri. Serverul trimite către client un mesaj cu numărul de loguri, urmând ca să trimită, pe rând, fiecare log.unsubscribe
- eliberarea datelor despre un clientdisconnect
- închiderea sesiunii curente a unui client. Pentru departajare, se pot implementa următoarele funcționalități extra (puteți alege orice funcționalitate doriți voi din listă sau propune funcționalități noi, cu cât mai multe/de impact, cu atât mai bine):
Ctrl-C
) - închiderea tuturor conexiunilor active, dealocarea datelor etc.FLUSH_TIME
minute. Pentru aceasta, trebuie să înregistrați câte un timer care generează o întrerupere la FLUSH_TIME
minute și un handler de tratare a întreruperii care face flush pe disk a datelor fiecărui client.FLUSH_TIME
, LINE_SIZE
, directorul default de scriere a logurilor, numărul default de clienți, număr maxim de loguri ce pot fi stocate per proces etc. Atenție! Dacă sunt modificați anumiți parametrii care sunt folosiți de către bibliotecă (precum LINE_SIZE
), trebuie anunțat și clientul de modificări.getlogs
.snapshot
la un anumit interval a datelor serverului (pentru asigurarea restore-ului în cazul în care crapă procesul). Un exemplu de astfel de funcționalitate este oferit de Redis, care pentru a face snapshot, folosește apelul fork()
pentru a face snapshot memoriei procesului server.<logfile_path>/<service_name>.log
(ex: logs_lmc/client1.log
), acesta se redenumește (variante posibile: se adaugă un timestamp sau un număr de ordine la fișierul vechi).
README
(sumar) cum ați implementat și testat funcționalitatea respectivă
Deoarece este posibil ca să rămâneți fără timp la dispoziție pentru funcționalitățile extra, se acceptă ca acestea să fie implementate doar pentru o singură platformă, însă acest aspect se va reflecta în punctajul final.
Pentru simplificarea testării, aveți la dispoziție un checker care reprezintă o colecție de clienți (teste) pe care să îi folosiți atunci când implementați codul server-ului.
Nu uitați să porniți serverul (lmcd
/ lmcd.exe
) înainte să rulați checkerul.
În directorul cu checker-ul aveți sursa checker.c
și două fișiere Makefile (Makefile.lin
și Makefile.win
).Pentru compilarea și folosirea checker-ului, puteți folosi următoarele comenzi (presupunând că realizați dezvoltarea în directorul ../skel
relativ la directorul în care se află checker-ul):
user@Linux hackathon/checker$ make -f Makefile.lin SRCDIR=../skel user@Linux hackathon/checker$ ./checker [TAG|N]
user@Windows hackathon/checker$ nmake /f Makefile.win "SRCDIR=..\skel" user@Windows hackathon/checker$ .\checker.exe [TAG|N]
Pentru selectarea unui test, argumentul transmis poate avea una dintre următoarele valori:
TAG
- tag-ul unui test, din lista de teste din checker.c
. De exemplu basic-1
va porni primul test, op-3
va porni al șaptelea test.N
- indexul (one-based) al unui test din lista de teste din checker.c
. De exemplu 1
va porni primul test, 7
va porni al șaptelea test.În lipsa unui argument, se consideră în mod implicit că este folosit tag-ul “all” care va porni toate testele pe rând.
Pentru departajarea în cadrul concursului, vor fi luate în considerare:
Pentru a submite implementarea spre a fi analizată pentru concurs, trebuie să încărcați o arhivă cu soluția (toată structura de fișiere pe care ați folosit-o, fișierele Makefile și testele adiționale) aici. În arhivă trebuie să adăugați un fișier README cu componența echipei și cu funcționalitățile extra aduse implementării, precum și modul de testare a acestora.
README
trebuie adăugat link către repository-ul privat în care ați lucrat.
Soluții de in-memory cache folosite în industrie (Redis, Memcached):