Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
Nächste ÜberarbeitungBeide Seiten der Revision
dnbd3_fuse_cow [2022/09/08 15:55 CEST] – [Installation cow_merger_service] +systemd-Start chrdnbd3_fuse_cow [2022/09/09 18:28 CEST] – Threads und Locks mscherle
Zeile 49: Zeile 49:
  
 Ein ausgeführtes 'make install' installiert die ausführbaren Dateien dnbd3-fuse, dnbd3-fuse-cow-test sowie dnbd3-server nach /usr/local/bin. '/usr/local/bin' sollte im Pfad enthalten sein. Ein ausgeführtes 'make install' installiert die ausführbaren Dateien dnbd3-fuse, dnbd3-fuse-cow-test sowie dnbd3-server nach /usr/local/bin. '/usr/local/bin' sollte im Pfad enthalten sein.
 +
 +=== Autostart ===
 +
 +Der dnbd3-Server wird am besten direkt beim Systemstart über systemd gestartet. Dazu folgende Datei unter /etc/systemd/system/dnbd3-server.service ablegen …
 +
 +<code>
 +[Unit]
 +Description=DNBD3 server
 +Wants=network-online.target
 +After=network-online.target
 +
 +[Service]
 +Type=simple
 +ExecStart=/usr/local/bin/dnbd3-server -n -c /etc/dnbd3-server
 +Restart=on-failure
 +User=dnbd3
 +
 +[Install]
 +WantedBy=multi-user.target
 +</code>
 +
 +… und mittels 'systemctl enable dnbd3-server' zum automatischen Start registrieren. Ein Direktstart kann mittels 'systemctl daemon-reload', 'systemctl start dnbd3-server' erfolgen.
  
 ==== Installation cow_merger_service ==== ==== Installation cow_merger_service ====
Zeile 55: Zeile 77:
  
 == Ubuntu 22.04 == == Ubuntu 22.04 ==
 +
 Beispiel Ubuntu 22.04 Beispiel Ubuntu 22.04
  
Zeile 88: Zeile 111:
 </code> </code>
  
-=== Bau des cow_merger_service ===+=== Bau und Installation ===
  
 <code> <code>
Zeile 101: Zeile 124:
 </code> </code>
  
-Erzeugte Dateien (Serverprogramm und Konfigurationsdatei) werden in cow_merger_service/publish/ abgelegt. Kopieren Sie die ausführbare Datei cow_merger_service und die Konfiguration appsettings.json an einen geeigneten Ort, beispielsweise in ein eigenes Verzeichnis hinter /opt.+Erzeugte Dateien (Serverprogramm und Konfigurationsdatei) werden in cow_merger_service/publish/ abgelegt. Kopieren Sie die ausführbare Datei cow_merger_service und die Konfiguration appsettings.json an einen geeigneten Ort, beispielsweise in ein eigenes Verzeichnis hinter /opt. Hier wird angenommen, daß die beiden Datein in ein Verzeichnis /opt/cow_merger_service kopiert wurden.
  
-=== Start cow_merger_service ===+=== Autostart ===
  
 Der Start des cow_merger_services kann automatisiert werden. Erzeugen Sie dazu eine Datei in /etc/systemd/system/cow_merger_service.service folgenden Inhalts: Der Start des cow_merger_services kann automatisiert werden. Erzeugen Sie dazu eine Datei in /etc/systemd/system/cow_merger_service.service folgenden Inhalts:
Zeile 125: Zeile 148:
 </code> </code>
  
-… und führen anschließend den Befehle 'systemctl enable cow_merger_service' aus. 'systemctl daemon-reload && systemctl start cow_merger_service' startet den Dienst direkt.+… und führen anschließend den Befehl 'systemctl enable cow_merger_service' aus. 'systemctl daemon-reload && systemctl start cow_merger_service' startet den Dienst direkt.
  
-==== Konfiguration ====+===== Konfiguration ===== 
 + 
 +==== dnbd3-Server ==== 
 + 
 +Die Konfigurationsdatei **server.conf** wird standardmässig in /etc/dnbd3 abgelegt. Eine Beispieldatei ist in im bauverzeichnis unter **pkg/config/server.conf** zu finden. Diese kann nach /etc/dnbd3 kopiert werden; der Pfad wird kann dem dnbd3-Server mit dem Startparamerter **--config** übergeben. Die wichtigste Konfigurationsoption ist **basePath**, die das Verzeichnis bezeichnet, in dem die vom Server bereitgestellten Images liegen. Die Abbilddateien müssen auf .r[1-9][0-9]* enden. 
 + 
 +Der dnbd3-Server wird üblicherweise beim Systemstart [[#autostart|aktiviert]]. Ein Neustart des dnbd3-Servers erfolgt am zweckmäßigsten mittels 'systemctl restart dnbd3-server'
 + 
 +==== cow_merger_service ====
  
 Serverseitig sollten 3 Verzeichnisse erstellt werden: Serverseitig sollten 3 Verzeichnisse erstellt werden:
Zeile 136: Zeile 167:
 mkdir [DestinationDirectory] mkdir [DestinationDirectory]
 </code> </code>
- 
-=== dnbd3-Server === 
- 
-Die Konfiguration des dnbd3-Servers erfolgt per **server.conf**. Eine Beispielkonfiguration ist in **pkg/config/server.conf** zu finden. Diese kann an einen passenden Ort kopiert werden; der Pfad kann dem dnbd3-Server mit dem Startparamerter **--config** übergeben werden. Die wichtigste Konfigurationsoption ist **basePath**, die das Verzeichnis bezeichnet, in dem die von Server bereitgestellten Images liegen. Die Abbilddateien müssen auf .r[1-9][0-9]* enden. Nach Ablage der Images in diesem Ordner kann der Server gestartet werden. 
- 
-<code> 
-dnbd3-server --config [Pfad zur Config] 
-</code> 
- 
- 
-== Autostart dnbd3-server == 
- 
-Der dnbd3-Server wird am besten direkt beim Systemstart mittels systemd gestartet. Dazu folgende Datei unter /etc/systemd/system/dnbd3-server.service ablegen … 
- 
-<code> 
-[Unit] 
-Description=CoW merger service 
-Wants=network-online.target 
-After=network-online.target 
- 
-[Service] 
-Type=simple 
-WorkingDirectory=/opt/cow_merger_service 
-Environment="DOTNET_CLI_TELEMETRY_OPTOUT=TRUE" 
-ExecStart=/opt/cow_merger_service/cow_merger_service 
-Restart=on_failure 
-User=root 
- 
-[Install] 
-WantedBy=multi-user.target 
-</code> 
- 
-… und mittels 'systemctl enable dnbd3-server' zum automatischen Start registrieren. Ein Direktstart kann mittels 'systemctl daemon-reload', systemctl start dnbd3-server' erfolgen. 
  
 === cow_merger_service === === cow_merger_service ===
Zeile 327: Zeile 325:
  
 ===== Funktionsweise ===== ===== Funktionsweise =====
 +===Struktur der Daten===
 +Die Datenstruktur ist in zwei Hauptteile unterteilt. Die eigentlichen Daten die die Änderungen enthalten und die dazugehörenden Metadaten.
 +Die Änderungen werden in der data Datei gespeichert während die Meta daten in der meta Datei gespeichert werden.
 +Die Daten werden in Blöcken gespeichert, der dnbd3-Block ist 4096 Byte groß und 320 dnbd3-Blöcke werden in einen cow-Block zusammengefasst.
 +Ein cow block hat eine cow_block_metadata_t Struktur, die die entsprechenden Metadaten enthält. Die Metadaten werden verwendet, um festzustellen,
 +ob ein dnbd3-Block beschrieben wurde, wo dieser Block in der Datendatei gespeichert ist, wann er zuletzt geändert und wann er hochgeladen wurde.
 +Aber dazu später mehr.
 +
 +
 +===Blockmetadata===
 +Die Datenstruktur zur Speicherung von "cow_block_metadata_t" enthält eine Schicht 1 (L1) und eine Schicht 2 (L2). L1 enthält Pointer auf die L2's.
 +Das gesamte L1-Array wird zu Beginn initialisiert und kann nicht in der Größe verändert werden, daher begrenzt die Größe des L1-Arrays die Gesamtgröße des Images.
 +Die L2 werden dynamisch erstellt, wenn sie benötigt werden. Zu Beginn sind also alle L1-Pointer Null. Die L2's sind Arrays, die 1024 cow_block_metadata_t structs enthalten.
 +
 +<code>
 +typedef struct cow_block_metadata
 +{
 +    atomic_int_least64_t offset;
 +    atomic_uint_least64_t timeChanged;
 +    atomic_uint_least64_t uploads;
 +    atomic_char bitfield[40];
 +} cow_block_metadata_t;
 +</code>
 +
 +<code>
 +COW_L2_STORAGE_CAPACITY = 1024 * 320 * 4096 
 +COW_METADATA_STORAGE_CAPACITY = 320 * 4096 
 +</code>
 +
 +Jeder cow_block_metadata_t enthält ein 40 Byte langes, also 320 Bit großes Bitfeld. Das Bitfeld zeigt an, ob der entsprechende dnbd3-Block Daten enthält oder nicht.
 +Beginnt das Bitfeld z.B. mit 01..., so enthalten die ersten 4096 Byte keine Daten und die nächsten 4096 Byte enthalten Daten. 
 +Jeder cow_block_metadata_t speichert also die Metadaten von bis zu 320*4096 Bytes, wenn alle Bits auf 1 gesetzt sind. 
 +Das Offset-Feld enthält das Offset, an welcher Stelle  in der Datendatei die entsprechenden Daten gespeichert sind. 
 +Die timeChanged Feld enthält die Unix-Zeit, zu der der Block zuletzt geändert wurde. 
 +Sie ist 0, wenn er nie geändert wurde oder wenn die letzten Änderungen bereits hochgeladen wurden.
 +
 +Die L2-Arrays und cow_block_metadata_t sind nach den ursprünglichen Offsets des Images sortiert. 
 +So adressiert der erste L1-Zeiger, d.h. das erste L2-Array, die ersten 1024 * 320 * 4096 Bytes (L2Size * bitfieldsize * DNBD3Blocksize) der Daten und so weiter.
 +
 +Um zum Beispiel die "cow_block_metadata_t" für den Offset 4033085440 zu erhalten, würde man L1[3] nehmen, da
 +
 +<code>
 +4033085440 / ( COW_L2_STORAGE_CAPACITY ) ≈ 3.005
 +</code>
 +
 +Dann würde man den fünften cow_block_metadata_t im L2-Array nehmen wegen
 +<code>
 +(4033085440 mod COW_L2_STORAGE_CAPACITY) / COW_METADATA_STORAGE_CAPACITY = 5
 +</code>
 +
 +===Leseanfrage===
 +Wird eine Lese anfrage gestellt werden alle benötigten "cow_block_metadata_t" berechnet. In den bitfields wird dann geschaut ob die benötigten dnbd3 Blöcke Daten enthalten, also ob das bitfield an der stelle 1 ist.
 +Falls ja werden die daten aus der Daten Datei geladen. Das Offset ist dabei das cow_block_metadata_t Offset plus 4096 * blocknummer im Cow Block.
 +Falls das bit im bitfield jedoch 0 ist, gibt es zwei Fälle. Ist das offset kleiner als die Origial Image Größe werden die Daten mit 0 aufegfüllt (die Origial Image Größe Variable kann bei einem truncate die kleiner ist als das uhrprünglich Image weiter reuziert werden).
 +Abdernfalls werden die Daten von dem dnbd3 server geladen.
 +Da die Leseanfragen an den dnbd3 server asyncron ausgeführt werden, gibt es eine workCounter variable, die Anzahl der Parallelen anfragen plus der einzelnen lokalen enthält.
 +Erst wenn diese Variable 0 ist, wird die Fuse-Anfrage beendet.
 +
 +===Schreibanfrage===
 +Wenn bei einer Schreibanfrage der Anfang oder das Ende nicht mit einem Vielfachen von 4096 übereinstimmt, muss der Anfangs- und/oder Endblock aufgefüllt werden.
 +Das liegt daran, dass jeder 4096-Byte-Block vollständige Daten benötigt, denn wenn das Bit im Bitfeld für diesen Block gesetzt ist, werden alle Daten lokal gelesen.
 +Um den Block aufzufüllen, werden die fehlenden Bytes vom dnbd3-Server angefordert, wenn er sich noch im Bereich der ursprünglichen Imagegröße befindet.
 +Liegt er außerhalb der ursprünglichen Imagegröße (weil z.B. das Image größer geworden ist), werden die fehlenden Bytes mit 0 aufgefüllt.
 +Die Schreibanfrage errechnet aus dem Offset die entsprechenden cow_block_metadata_t.
 +Wenn die entsprechende cow_block_metadata_t noch nicht existiert, wird sie angelegt.
 +Die Daten werden in die Datendatei geschrieben, und zwar an den in cow_block_metadata_t gespeicherten Offset.
 +Dann wird das entsprechende Bit in den Bitfeldern gesetzt und die timeChanged aktualisiert.
 +Wenn mehr Daten zu schreiben sind, wird die nächste cow_block_metadata_t berechnet und die obigen Schritte werden wiederholt.
 +Die Variable workCounter wird auch hier verwendet, um sicherzustellen, dass das Auffüllen der Daten erfolgt, bevor die Fuse-Anfrage bendet wird.
 +
 +===Block-Upload===
 +Für das Hochladen von Blöcken gibt es einen Hintergrund-Thread, der periodisch eine Schleife über alle Cow-Blöcke zieht und prüft,
 +ob timeChanged ungleich 0 ist und die Zeitdifferenz zwischen now und timeChanged größer als COW_MIN_UPLOAD_DELAY ist.
 +Ist dies der Fall, wird der Block hochgeladen. Die timeChanged Variable vor dem Upload wird zwischengespeichert.
 +Nach dem Hochladen wird timeChanged auf 0 gesetzt, wenn es noch die gleiche Zeit wie die zwischengespeicherte hat (wenn nicht, gab es eine Änderung während des Hochladens und es muss erneut hochgeladen werden).
 +Sobald das Image ausgehängt ist, wird COW_MIN_UPLOAD_DELAY ignoriert und alle Blöcke, die eine andere Zeit als 0 haben, werden hochgeladen.
 +Das Hochladen erfolgt über einen REST-Request. Es gibt zwei verschiedene Limits für die Anzahl der parallelen Uploads, diese können in der config.h konfiguriert werden.
 +
 +===Dateien===
 +Wenn eine neue CoW-Sitzung gestartet wird, werden eine neue Meta-, Daten- und, falls in den Befehlszeilenargumenten festgelegt, eine status.txt-Datei erstellt.
 +
 +==status.txt==
 +Die Datei status.txt kann mit dem Kommandozeilenparameter --cowStatFile aktiviert werden.
 +
 +Die Datei enthält die folgende Informationen:
 +<code>
 +uuid=<uuid>
 +state=backgroundUpload
 +inQueue=0
 +modifiedBlocks=0
 +idleBlocks=0
 +totalBlocksUploaded=0
 +activeUploads:0
 +ulspeed=0.00
 +</code>
 +
 +  * Die **uuid** ist die Sitzungs-Uuid, die vom Cow-Server zur Identifizierung der Sitzung verwendet wird.
 +
 +  * Der **Status** ist **backgroundUpload**, wenn das Image noch eingehängt ist und die Cow- Blöcke im Hintergrund hochgeladen werden. Er ist **uploading**, wenn das Image ausgehängt wurde und alle noch nicht hochgeladenen Blöcke hochgeladen werden. Es ist **done**, wenn das Image ausgehängt wurde und alle Blöcke hochgeladen wurden.
 +
 +  * **Queue** sind die CoW Blöcke, die gerade hochgeladen werden oder auf einen freien Slot warten.
 +
 +  * **ModifiedBlocks** sind CoW Blöcke, die Änderungen aufweisen, die noch nicht auf den Server hochgeladen wurden, weil die Änderungen zu aktuell sind.
 +
 +  * **totalBlocksUploaded** die Gesamtanzahl der CoW Blöcke, die seit dem Einhängen des Images hochgeladen wurden.
 +
 +  * **activeUploads** ist die Anzahl der Blöcke, die gerade hochgeladen werden.
 +
 +  * **ulspeed** die aktuelle Upload-Geschwindigkeit in kb/s.
 +
 +Sobald alle Blöcke hochgeladen wurden, wird der Status auf erledigt gesetzt. Wenn Sie COW_DUMP_BLOCK_UPLOADS festlegen (in config.h), wird eine Liste aller Blöcke, sortiert nach der Anzahl der Uploads, in die Datei status.txt kopiert, nachdem der Block-Upload abgeschlossen ist.
 +
 +Mit dem Kommandozeilenparameter --cowStatStdout wird die gleiche Ausgabe der Statistikdatei in stdout ausgegeben.
 +
 +==meta==
 +Die Metadatei enthält die folgenden Header:
 +<code>
 +// cowfile.h
 +typedef struct cowfile_metadata_header
 +{
 +    uint64_t magicValue;                    // 8byte
 +    atomic_uint_least64_t imageSize;        // 8byte
 +    int32_t version;                        // 4byte
 +    int32_t blocksize;                      // 4byte
 +    uint64_t originalImageSize;             // 8byte
 +    uint64_t metaDataStart;                 // 8byte
 +    int32_t bitfieldSize;                   // 4byte
 +    int32_t nextL2;                         // 4byte
 +    atomic_uint_least64_t metadataFileSize; // 8byte
 +    atomic_uint_least64_t dataFileSize;     // 8byte
 +    uint64_t maxImageSize;                  // 8byte
 +    uint64_t creationTime;                  // 8byte
 +    char uuid[40];                          // 40byte
 +    char imageName[200];                    // 200byte
 +} cowfile_metadata_header_t;
 +</code>
 +Nach diesem Header beginnt bei Byte 8192 die oben erwähnte l1- und dann die l2-Datenstruktur.
 +==data==
 +Die Datendatei enthält den magicValue und am Offset 40 * 8 * 4096 (Kapazität eines cowfile_metadata_header_t) beginnt der erste Datenblock.
 +
 +==magic values in den Headern der Dateien==
 +Die magic values in beiden Dateien werden verwendet, um sicherzustellen, dass eine geeignete Datei gelesen wird und dass der Rechner die richtige Endianness hat.
 +<code>
 +//config.h
 +#define COW_FILE_META_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825E) // Magic Value to recognize a Cow meta file
 +#define COW_FILE_DATA_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825F) // Magic Value to recognize a Cow data file
 +</code>
 +
 +===Threads===
 +Diese Erweiterung verwendet zwei neue Threads:
 +<code>
 +tidCowUploader
 +tidStatUpdater
 +</code>
 +  * **tidCowUploader** ist der Thread, der die Blöcke auf den Cow-Server hochlädt.
 +
 +  * **tidStatUpdater** aktualisiert die Statistiken in stdout oder die Statistikdateien (je nach Parametern).
 +
 +===Locks===
 +Diese Erweiterung verwendet einen neuen Lock cow.l2CreateLock. Er wird verwendet, wenn ein neues L2-Array zugewiesen wird.
  
 <note warning>To do</note> <note warning>To do</note>
Drucken/exportieren