DDGDS steht für
"Dynamisch Definiertes Giganutzer Daten-System".
Es ist eine
Massen-Multinutzer-Datenbank (MMDB)
für zum Beispil
große soziale oder E-Commerce-Websites.
Sie nutzt
D
Das GDS-Dateiformat (
GDS =
"Grouped Data String") auf besonders effiziente Art und Weise.
Während
Mediendateien mit ihrer jeweiligen
Dateiendung (etwa *.jpg) gespeichert werden, haben die
Datenbank-Dateien von DDGDS
keine Dateiendung.
Das DDGDS arbeitet mit
GDS-kompatiblen Arrays, die
Zahlen-Strings als Schlüssel verwenden (etwa "123") anstelle der tatsächlichen
alphanumerischen Srins (etwa "Haupt-Text"), die der Programmierer verwendet und die in einem separaten,
Dateitypen-Definitionen-Array _types
vorgehalten werden, nur zu verwenden mit speziellen
Schreib-/Lese-Funktionen, die
dynamisch die
Zuordnungen für den programmierer verwalten. Dies
spart so einiges an
Speicherplatz auf dem Server.
Hier ist ein
schematisches Beispiel einer
_types
-Definition:
0:Nutzer
0:Name
1:Auth
2:Avatar
3:Freunde
0:NutzerID
1:Spitzname
2:xAvatar
4:Gruppen
1:Gruppe
0:Titel
1:Logo
2:Mitgliederzahl
3:Admins
...
Die
Schlüsselnamen in einem Blocks müssen
einzigartig sein, da die Software mit einer
Rückwärts-Nachschlagetabelle arbeitet. In unserem Beispiel würde diese etwa wie folgt aussehen:
Nutzer:0
Name:0
Auth:1
Avatar:2
Freunde:3
NutzerID:0
Spitzname:1
xAvatar:2
Gruppen:4
Gruppe:1
Titel:0
Logo:1
Mitgliederzahl:2
Admins:3
...
Keine zwei Schlüsselnamen im selben Block dürfen auf dieselbe blockspezifische Indexnummer zeigen, weshalb die Schlüsselnamen innerhalb ihres Blocks einzigartig sein müssen. Während man
jederzeit neue Felder unten an einen Block
anfügen kann, sollte man aus Gründen der
Abwärtskompatibilität am besten
niemals die Einträge innerhalb eines Blocks
umsortieren, wenn er bereits in Benutzung ist, und man sollte man Einträge aus einem solchen Block auch
niemals löschen.
Einträge, die
veraltet sind, kann man in
einzigartige gesonderte Schlüsselnamen umbenennen, wie in diesem Beispiel (achte auf die zwei Felder "veraltet1" und "veraltet2"):
...
2:Brief
0:von_NutzerID
1:an_NutzerID
2:veraltet1
3:veraltet2
4:Überschrift
5:Textkörper
6:gesendet_DT
7:gelesen_DT
...
Alle
DDGDS-Arrays werden ,ausschlieĺich
indirekt verwendet von den Anwendungsprogrammierern, nämlich über
Verwaltungsfunktionen, niemals als die direkten Roh-Arrays.
Wir schauen uns nun
Eas-Beispiele (siehe
E
→Molaskes.info/Eas) für diese Funktionen an, wobei wir annehmen, dass wir von der Festplatte eine wie oben definierte Nutzerdatei eingelesen haben. Das GDS-dekodierte Array wird in der Variablen
NutzerVar
vorgehalten.
Um die oberste Ebene "leichter verdaulich" zu machen, rufen wir
NutzerVarX DDGDS'Get:NutzerVar
auf. Die Variable
NutzerVarX
wird dann ein reguläres Array mit Schlüsseln sein, mit vielleicht folgendem Inhalt:
"Name":"Lara Da Vinci"
"Auth":"0X2-7Wix_wU327UwxWj3-s3k"
"Avatar":"lara2.jpg"
"Freunde":35
"Gruppen":"i3Xu43F 93Wh_W2 wkSjwAx"
Die Gruppen hier sind eine Leerzeichen-separierte Liste von
Eintrags-IDs (mehr dazu später), aber viel wichtiger für uns ist hier, dass die Freunde, die in der Format-Definition oben einen
Unterblock bilden, nur als einzelner Zahlenwert zurückgegeben werden. Dies liegt daran, dass solche Unterblöcke immer eine
schlüssellose Liste/Array implizieren, in der jeder Eintrag in seiner Struktur durch den Unterblock definiert ist. Der Wert, den wir erhalten, ist die
Anzahl aller Elemente, also in diesem Fall die Anzahl von Laras Freunden.
Alternativ kann man auch jeden beliebigen Wert direkt auslesen, etwa über
DDGDS'Get:NutzerVar "Avatar"
, was hier
"lara2.jpg"
zurückgeben würde.
Wenn wir nun die Daten zum 6. Freund auslesen wollten (beachte, dass Indizes mit 0 beginnen), würden wir einfach
derFreund DDGDS'Get:NutzerVar "Freunde:5"
aufrufen, was die Variable
derFreund
etwa wie folgt füllen könnte:
"NutzerID":"bZ3oSu9"
"Spitzname":"Pauli"
"xAvatar":"mein Pauli.jpg"
Das
Schreiben funktioniert nur mit
direkten Feldbezügen; wenn Lara also ihr Avatar-Bild geändert hat, würden wir etwa
DDGDS'Set:NutzerVar "Avatar" "Lara_am_Strand.jpg"
, aufrufen, und einen neuen Freund hinzufügen für sie würde beispielsweise erfolgen über:
DDGDS'Set:NutzerVar "Freunde:35:NutzerID" "wj3Dh0G"
DDGDS'Set:NutzerVar "Freunde:35:Spitzname" "Minna"
DDGDS'Set:NutzerVar "Freunde:35:xAvatar" "minna.jpg"
Aus Gründen der Datensicherheit sollte das Schreiben von Leerwerten nicht zulässig sein, und man sollte vielmehr zum
Löschen von Einträgen eine designierte Funktion nutzen müssen, welche alle wichtigen Schlüssel:Wert-Zuordnungen intakt lässt. Schlüssellose Listeneinträge jedoch werden auch in den Rohdaten einfach gelöscht. Hier ein paar Beispiele für das Löschen von Elementen:
DDGDS'Delete:NutzerVar "Avatar"
DDGDS'Delete:NutzerVar "Freunde:35:Spitzname"
DDGDS'Delete:NutzerVar "Freunde:20"
Beachte, dass beim
Löschen schlüsselloser Listeneinträge alle Indizes der nachfolgenden Listen-Elemente um eins verringert werden. In unserem Beispiel würde der Eintrag "Freunde:35" nach dem Löschen von "Freunde:20" nun über "Freunde:34" anzusprechen sein.
Alle
Dateien im DDGDS erhalten eine
Eintrags-ID, welche der
Eas-BASE:64-encodierte
DateTime-Wert ihrer
Erstellzeit ist. Deren
Einzigartigkeit pro Verzeichnis wird sichergestellt durch ein
Datenbank-Sperrprotokoll (sperren durch Nutzer — Nutzer prüfen — schreiben — entsperren).
(
Eas BASE:64 unterscheidet sich von den meisten älteren Base64-Implementierungen, indem es
vollständig kompatibel ist
mit allen niederbasigeren mathematischen Notationen, mit 0–9 für die ersten zehn Ziffern (
Dezimalzahlen), dann die Großbuchstaben A–Z (
Hexadezimalzahlen und darüber hinaus, für Werte 10–35), dann der Unterstrich "_" für den Wert 36, dann die Kleinbuchstaben a–z für die Werte 37-62 und schließlich der Minusstrich "-" für den Wert 63.)
Wenn wir die Nutzerdaten von Laras Freund "Pauli"
laden wöllten, würden wir
DDGDS'Load:"Nutzer" "bZ3oSu9"
aufrufen, was tatsächlich die Datei mit dem Pfad
./Nutzer/b/Z/3/o/S/u/9/_
laden würde, wobei die
Eintrags-ID Zeichen für Zeichen aufgesplittet würde in einen
Unterverzeichnis-Pfad mit jeweils nicht mehr als 64 verschiedenenen Einträgen und die
Kerndaten in einer einfach mit einem Unterstrich "
_" benannten Datei gespeichert sind.
Wenn Pauli nun vorhätte, Laras neueste Privatnachricht zu lesen, würde der Servercode beispielsweise
DDGDS'Load:"Nutzer" "bZ3oSu9" "PN" "29D3-jX/w3Wkf31"
aufrufen, was tatsächlich die Datei
./Nutzer/b/Z/3/o/S/u/9/PN/29D3-jX/w3Wkf31
laden würde, wobei 29D3-jX Laras Nutzer-ID und w3Wkf31 die ID der eigentlichen Nachricht wäre.
Wenn Lara an ihrem Nutzerprofil Änderungen vorgenommen hat, können wir die Daten auf dem Server
aktualisieren über
DDGDS'Save:"Nutzer" "29D3-jX" NutzerVar
. Dieselbe Funktion wird auch zum
Erstellen neuer Einträge auf der Festplatte genutzt, etwa wenn eine neue Privatnachricht gesendet wird.
Aus Gründen des
Datenschutzes bzw. zur Wahrung der
Privatsphäre sollte es die erweiterten Funktionen
DDGDS'SaveX
und
DDGDS'LoadX
geben, wobei erstere die Datei
obfuskiert, was einfach nur bedeutet, dass sie für Menschen unleserlich gemacht wird, und letztere die Obfuskation wieder rückgängig macht, ehe die Datei zum Auslesen GDS-geparst wird. Dies ist etwa wichtig für
Privatnachrichten. Admins mit Direktzugriff auf die Serverdaten (etwa über FTP) könnten dann beispielsweise
nicht mehr lesen:
Mist, Schatz, mein Test war positiv!!! Was nun??? …
,
sondern würden
stattdessen nur etwas
sehen wie Folgendes:
3Iaw_ "oW!s.JRxii74 w:icEFW+ 3qyY -19?k_ xEw76xzC …
.
Die
tatsächliche Login-Authentifizierung sollte ein besonderes Verzeichnis nutzen mit
Unterverzeichnissen, die
aufgespreizte Login-Namen repräsentieren anstelle von Base64IDs.
Nutzernamen müssten dann
einzigartiges sein, wenn sie
transformiert werden in eine vereinfachte Authentifizierungsfom, etwa wenn der
Nutzername "René Knödel"
in den
Login-Namen "rene_knoedel"
umgewandelt wird, für welchen die Login-Authentifizierungs-Daten (Passwort-Authentifizierungs-Siegel und Nutzer-ID) abgespeichert würden in
./Login/r/e/n/e/_/k/n/o/e/d/e/l/_
.
Wenn ein Nutzer seinen Nutzernamen und sein Passwort eingegeben hat, würde die
Login-Authentifizierungs-Prüfung ungefähr so ablaufen:
Login Nutzername Passwort:
n LoginName:Nutzername
authDaten DDGDS'Load:"Login" n
pwSiegel DDGDS'Get:authDaten "Siegel"
? pwSiegel#(AuthSeal:Passwort) << 0
nutzerID DDGDS'Get:authDaten "Nutzer"
nutzerDaten DDGDS'Load:"Nutzer" nutzerID
lt NewLoginToken!
DDGDS'Set:nutzerDaten "Auth" lt
COOKIE:"Auth" nutzerID;":";lt
<< 1 — Login erfolgreich
/
(Das zufällige
Login-Token wird verwendet, um bei jedem Zugriff zu
verfizifieren, dass das
Login-Cookie des Nutzers wirklich
valide ist, das Ergebnis eines sauberen Logins mit dem korrekten Passwort.)