Scopul sistemului
Sprijină accesul la fișierele de pe computerele din rețea. Sistemul «virtual» suportă toate operațiile de bază cu fișiere (creare, ștergere, citire, scriere etc.) prin schimbul de tranzacții (mesaje) pe protocolul TCP.
Domenii de aplicare
Funcționalitatea sistemului este eficientă în următoarele cazuri:
- în aplicații native pentru dispozitive mobile și embedded (smartphone-uri, sisteme de control integrat etc.) care necesită acces rapid la fișiere pe servere la distanță în condiții de conectivitate instabilă (în cazul deconectării temporare);
- în SGBD-uri foarte solicitate, dacă prelucrarea cererilor se realizează pe unele servere, iar stocarea datelor – pe altele;
- în rețele corporate distribuite pentru colectarea și prelucrarea informațiilor, care necesită o viteză mare de schimb de date, rezervare și fiabilitate;
- în sisteme complexe cu arhitectură pe microservicii, unde întârzierile în schimbul de informații între module sunt de o importanță critică.
Structura
Sistemul Cage (există o implementare – versiune beta pe Python 3.7 în OS Windows) include două părți principale:
- Cageserver – program de server de fișiere (pachet de funcții) care rulează pe computerele din rețea, la care se necesită acces la fișiere la distanță;
- clasă Cage cu o bibliotecă de metode pentru software-ul client, care simplifică codificarea interacțiunii cu serverele.
Utilizarea sistemului pe partea clienților
Metodele clasei Cage înlocuiesc operațiile obișnuite, «rutinare» ale sistemului de fișiere: crearea, deschiderea, închiderea, ștergerea fișierelor, precum și citirea/scrierea datelor în format binar (cu specificarea poziției și dimensiunii datelor). Conceptual, aceste metode sunt apropiate de funcțiile de fișiere din limbajul C, unde deschiderea/închiderea fișierelor se face «pe canale» de intrare-ieșire.
Cu alte cuvinte, programatorul lucrează nu cu metodele «obiectelor fișier» (clasa _io în Python), ci cu metodele clasei Cage.
Atunci când se creează o instanță a obiectului Cage, se stabilește o conexiune inițială cu serverul (sau cu mai multe servere), se trece prin autorizare cu Id-ul clientului și se primește o confirmare cu numărul portului alocat pentru toate operațiile cu fișiere. Atunci când obiectul Cage este eliminat, acesta trimite serverului comanda de a întrerupe conexiunea și de a închide fișierele. Conexiunea poate fi inițiată și de către servere.
Sistemul îmbunătățește viteza de citire/scriere prin intermedierea fragmentelor frecvent utilizate ale fișierelor la programele client în cache (memoria tampon) RAM.
Software-ul client poate utiliza un număr nelimitat de obiecte Cage cu diverse setări (capacitatea memoriei tampon, dimensiunea blocurilor la schimbul cu serverul etc.).
Un obiect Cage poate schimba date cu mai multe fișiere pe mai multe servere. Parametrii de conectare (IP-ul sau DNS-ul serverului, portul principal pentru autorizare, calea și numele fișierului) sunt specificați la crearea obiectului.
Având în vedere că fiecare obiect Cage poate funcționa simultan cu mai multe fișiere, se folosește un spațiu de memorie comun pentru bufferizare. Dimensiunea cache-ului – numărul de pagini și dimensiunea lor – este setată dinamic la crearea obiectului Cage. De exemplu, un cache de 1 GB înseamnă 1000 de pagini de 1 MB, sau 10.000 de pagini de 100 KB, sau 1 milion de pagini de 1 KB. Alegerea dimensiunii și numărului de pagini este o sarcină specifică pentru fiecare caz de aplicare.
Se pot utiliza simultan mai multe obiecte Cage pentru a defini diverse setări ale memoriei tampon în funcție de caracteristicile accesului la informații în diverse fișiere. Algoritmul de bază aplicat este cea mai simplă metodă de bufferizare: după epuizarea volumului de memorie specificat, noile pagini înlocuiesc paginile vechi în conformitate cu principiul ieșirii cu un număr minim de accesări. Bufferizarea este deosebit de eficientă în cazul accesului inegal (din punct de vedere statistic), mai întâi la diverse fișiere și, în al doilea rând, la fragmentele fiecărui fișier.
Clasa Cage suportă intrare/ieșire nu doar prin adresele de date (specificând poziția și lungimea array-ului, «înlocuind» operațiile sistemului de fișiere), ci și la un nivel mai scăzut, «fizic» — prin numerele paginilor din memoria tampon.
Pentru obiectele Cage este suportată o funcție originală «hibernare» («suspend») – acestea pot fi „reamintite” (de exemplu, în cazul întreruperii conexiunii cu serverele sau la oprirea aplicației etc.) într-un fișier dump local pe partea clientului și restaurate rapid din acest fișier (după reluarea conexiunii, la repornirea aplicației). Aceasta permite o reducere semnificativă a traficului când aplicația client este activată din nou după o perioadă de „offline”, deoarece fragmentele de fișiere frecvent utilizate vor fi deja în cache.
Cage — este compus din aproximativ 3600 de linii de cod.
Principiile construirii serverelor
Serverele de fișiere Cageserver pot fi rulate cu un număr aleator de porturi, dintre care unul („principal”) este folosit doar pentru autorizarea tuturor clienților, iar celelalte — pentru schimbul de date. Programul serverului Cage necesită doar Python. În paralel, computerul cu serverul de fișiere poate efectua orice altă muncă.
Serverul se pornește mai întâi ca o combinație de două procese principale:
- „Conexiuni” – proces pentru efectuarea operațiunilor de stabilire a conexiunii cu clienții și a terminării acesteia la inițiativa serverului;
- „Operații” – proces pentru realizarea sarcinilor (operațiunilor) clienților în manipularea fișierelor, precum și pentru închiderea sesiunilor de conexiune la comanda clienților.
Ambele procese nu sunt sincronizate și sunt organizate ca bucle infinite de primire și trimitere a mesajelor pe baza coadelor multiproces, obiectelor proxy, blocajelor și socket-urilor.
Procesul „Conexiuni” alocă fiecărui client un port pentru trimiterea și primirea datelor. Numărul de porturi este specificat la pornirea serverului. Coerența între porturi și clienți este păstrată în memoria proxy partajată între procese.
Procesul „Operații” susține separarea resurselor de fișiere, permițând mai multor clienți diferiți să citească date din același fișier în colaborare (quasi-paralel, deoarece accesul este gestionat prin blocaje) dacă acest lucru a fost permis la deschiderea sa inițială de către „primul” client.
Prelucrarea comenzilor pentru crearea/ștergerea/ceau deschiderea/închiderea fișierelor server se realizează în cadrul procesului „Operații” strict secvențial folosind subsistemul de fișiere al sistemului de operare al serverului.
Pentru a accelera citirea și scrierea, aceste operațiuni sunt efectuate în fire (threads) generate de procesul „Operații”. Numărul de fire este, de obicei, egal cu numărul de fișiere deschise. Sarcinile de citire/scriere de la clienți sunt trimise într-o coadă comună, iar primul fir disponibil preia sarcina de la începutul acesteia. O logică specială permite excluderea operațiunilor de suprascriere a datelor în memoria RAM a serverului.
Procesul „Operații” monitorizează activitatea clienților și oprește serviciul acestora atât la cererea lor, cât și atunci când se depășește limita de timp de inactivitate.
Pentru a asigura fiabilitatea, Cageserver păstrează jurnale ale tuturor tranzacțiilor. Un jurnal comun conține copii ale mesajelor de la clienți cu sarcini de creare/deschidere/renomire/ștergere a fișierelor. Pentru fiecare fișier de lucru se creează un jurnal separat, în care sunt înregistrate copiile mesajelor cu sarcini de citire și scriere a datelor în acel fișier de lucru, precum și matricile de date scrise (noi) și matricile de date care au fost distruse în timpul suprascrierii (scrierii de noi date „peste” vechile).
Aceste jurnale oferă posibilitatea atât pentru recuperarea noilor modificări din copiile de rezervă, cât și pentru „restaurarea” conținutului actual la un punct dorit în trecut.
Cageserver conține aproximativ 3100 de linii de cod.

Pornirea programului de server de fișiere Cageserver
La pornire, în dialog trebuie să fie definite:
— portul principal pentru autentificare;
— numărul de porturi pentru schimbul de tranzacții cu clienții autorizați (de la 1 și mai mult, pool-ul de numere începe cu următorul după numărul portului principal).
Utilizarea clasei Cage
class cage.Cage( cage_name=», pagesize=0, numpages=0, maxstrlen=0, server_ip={}, wait=0, awake=False, cache_file=»» )
Din această clasă se creează obiecte care interacționează cu serverele de fișiere și conțin memorie tampon.
Setări
- cage_name(str) — numele convențional al obiectului, care este folosit la identificarea clienților pe partea serverului
- pagesize(int) — dimensiunea unei pagini de memorie tampon (în octeți)
- numpages(int) — numărul de pagini de memorie tampon
- maxstrlen(int) — lungimea maximă a șirului de octeți în operațiile de scriere și citire
- server_ip(dict) — dicționar cu adresele utilizate servere, unde cheia este numele convențional al serverului (id-ul serverului în aplicație), iar valoarea este un șir cu adresa: “ip address:port” sau “DNS:port” (asocierea numelui cu adresele reale este temporară, poate fi schimbată)
- așteptați(int) — timpul de așteptare pentru un răspuns de la server la obținerea porturilor (în sec.)
- treazia(boolean) — un flag care indică metoda de creare a obiectului (False — dacă se creează un nou obiect, True — dacă obiectul este creat dintr-unul anterior «înghețat» — aplicând operația «hibernare», implicit False)
- cache_file(str) — numele fișierului pentru hibernare
Metode
Cage.file_create( server, path ) – a crea un fișier nou
Cage.file_rename( server, path, new_name ) – a redenumi fișierul
Cage.file_remove( server, path) – a elimina fișierul
Cage.open( server, path, mod ) – a deschide fișierul
Returnează fchannel numărul canalului. Parametrul mod — este modul de deschidere a fișierului: «wm» — monopol (citire/scriere), «rs» — doar citire, și partajat doar pentru citire de către alți clienți, «ws» — citire/scriere, și partajat doar pentru citire de către alți clienți.
Cage.close (fchannel) – a închide fișierul
Cage.write (fchannel, begin, data ) – a scrie un șir de bytes în fișier
Cage.read (fchannel, begin, len_data ) – a citi un șir de bytes din fișier
Cage.put_pages ( fchannel ) – «împinge» din buffer pe server toate paginile canalului specificat care au fost modificate. Se folosește în punctele algoritmului când trebuie să ne asigurăm că toate operațiile pe canal sunt fizic salvate în fișierul de pe server.
Cage.push_all () – «împinge» din buffer pe server toate paginile tuturor canalelor pentru instanța clasei Cage, care au fost modificate. Se folosește când trebuie să ne asigurăm că toate operațiile pe toate canalele sunt salvate pe server.
Sursa: habr.com
