Molaskes: Paving and Leading the Way

Innovations by Molaskes:The DDGDS File System

DDGDS stands for "Dynamically Defined Giga-user Data System". It is a massively multiuser database (MMDB) to be used for instance in large social or e-commerce websites. It uses FThe GDS File Format (GDS = "Grouped Data String") very efficiently. While media files are stored with their proper file extensions (e.g. *.jpg), the database files of DDGDS are all extensionless. The DDGDS works with GDS-compatible arrays that use number strings as keys (for instance "12") instead of the actual alphanumeric keys (for instance "message_body") used by the programmer, which are kept in a separate file type definition array _types, using special read/write functions that dynamically handle the assignments for the programmer. This significantly saves disk space on the server. Here is a schematic example of a _types definition:
0:user
  0:name
  1:auth
  2:avatar
  3:friends
    0:userid
    1:nickname
    2:xavatar
  4:groups
1:group
  0:title
  1:logo
  2:members_count
  3:admins
...
‌ The key names in a block must be unique, as the software will work with a reverse lookup structure. In our example, this would look like the following:
user:0
  name:0
  auth:1
  avatar:2
  friends:3
    userid:0
    nickname:1
    xavatar:2
  groups:4
group:1
  title:0
  logo:1
  members_count:2
  admins:3
...
‌ No two key names in the same block must point to the same block-specific index number, which is why the key names must be unique within their block. While you can append anytime new fields to any block, for backward compatibility reasons you should never reorder the items in a block that is already in use, nor delete items from the block. Items that have become obsolete may be named by unique special key names such as in this example (note the two fields "unused1" and "unused2"):
...
2:letter
  0:from_userID
  1:to_userID
  2:unused1
  3:unused2
  4:title
  5:body
  6:sent_DT
  7:read_DT
... 
‌ All DDGDS arrays are accessed only indirectly through management functions by the application programmers, never as the raw arrays. We will look at Eas examples (see E→Molaskes.info/Eas) for these functions, assuming having read from disk a user file as defined above. The GDS-decoded array will be stored in the variable userVar. To make the top level "palatable", we use userVarX DDGDS'Get:userVar. The variable userVarX will then be a regular keyed array with perhaps the following contents:
"name":"Lara Da Vinci"
"auth":"0X2-7Wix_wU327UwxWj3-s3k"
"avatar":"lara2.jpg"
"friends":35
"groups":"i3Xu43F 93Wh_W2 wkSjwAx"
The groups here are a space-separated list of item IDs (more about that later), but more important for us is that the friends, which in the format definition above form a sub-block, are only given as a single number. This is because such sub-blocks always imply an unkeyed list/array with each element defined as in the sub-block. The value we got here is the count of the elements, so the number of Lara's friends in this case. Alternatively, you can read out any value directly, for instance via DDGDS'Get:userVar "avatar" which here would return "lara2.jpg". If we now wanted to read the 6th friend's data (mind that indexes start with 0), we would simply call curpal DDGDS'Get:userVar "friends:5", which may set the variable curpal to the following contents:
"userid":"bZ3oSu9"
"nickname":"Pauly"
"xavatar":"My Pauly.jpg"
Writing only works with direct fields, so if Lara changed her avatar picture, we might call DDGDS'Set:userVar "avatar" "lara_beach.jpg", and adding a new friend for her might be done with:
DDGDS'Set:userVar "friends:35:userid" "wj3Dh0G"
DDGDS'Set:userVar "friends:35:nickname" "Minna"
DDGDS'Set:userVar "friends:35:xavatar" "minna.jpg"
‌ For data safety reasons, writing empty values should not be allowed, and one should rather use a designated function to delete items, which is handled correctly by the function to keep key:index assignments where they are required. Unkeyed list entries however will actually be deleted also in the raw data. Here are some examples for deleting elements:
DDGDS'Delete:userVar "avatar"
DDGDS'Delete:userVar "friends:35:nickname"
DDGDS'Delete:userVar "friends:20"
Mind though that deleting unkeyed list items shifts all indexes in the same list that come after it. So in our example, the "friends:35" entry would shift to "friends:34" after deleting "friends:20". All files in DDGDS get an item ID that is the Eas BASE:64 encoded expression of its creation DateTime value. Its uniqueness per directory is ensured by a database locking protocol (lock-by-user—check-user—write—unlock). (Eas BASE:64 differs from most older Base64 implementations as it is fully compatible with any lower-base mathematical notatioons, using 0–9 for the first ten digits (decimals), then uppercase A–Z (hexadecimals and beyond, for values 10–35), then the underscore "_" character for the value 36, then lowercase a–z for the values 37–62, and finally the minus dash "-" charater for the value 63.) If we wanted to load the user data of Lara's friend "Pauly", we would call DDGDS'Load:"user" "bZ3oSu9", which would actually load the file ./user/b/Z/3/o/S/u/9/_, splitting the item ID character by character into a path of subdirectories of not more than 64 different entries each, and using a file simply named by the underscore "_" to store the main data. When Pauly wants to read Lara's latest private message, the server code might for instance call DDGDS'Load:"user" "bZ3oSu9" "pm" "29D3-jX/w3Wkf31" which would actually load the file ./user/b/Z/3/o/S/u/9/pm/29D3-jX/w3Wkf31, with 29D3-jX being Lara's userID and w3Wkf31 being the actual message's ID. After Lara has made changes to her user profile, we can update her data on the server via DDGDS'Save:"user" "29D3-jX" userVar. The same function is used to create new entries on the disk, for instance when sending a new private message. For data privacy reasons, there should be extended functions DDGDS'SaveX and DDGDS'LoadX, where the former obfuscates the file, which just means making it unreadable for humans (for example protecting against admins with direct access to the server data, such as via FTP), and the latter undoing the obfuscation before GDS-parsing it. This is for instance important for private messaging. Admins who maintain the server and might nosily investigate some of the data then would not read for example: Bad news, hun: My STD infection is confirmed. Dang! …‌ but would instead see something like this: 3Iaw_ "oW!s.JRxii74 w:icEFW+ 3qyY -190X?k_ xEw76xzC …. The actual login authentication should use a special directory with subdirectories representing split login names instead of Base64IDs. Usernames would have to be unique when transformed to a simplified authentication form, for instance rendering the user name "René Knödel" as the login name "rene_knoedel", the login authentication data (password authentication seal, and userID) for which would be stored in ./login/r/e/n/e/_/k/n/o/e/d/e/l/_. When the user has entered their username and password, the login authentication check would be performed in a way similar to this:
Login username password:
  n LoginName:username
  authdata DDGDS'Load:"login" n
  seal DDGDS'Get:authdata "seal"
  ? seal#(AuthSeal:password) << 0
  userID DDGDS'Get:authdata "user"
  userd DDGDS'Load:"user" userID
  lt NewLoginToken!
  DDGDS'Set:userd "auth" lt
  COOKIE:"auth" userID;":";lt
  << 1 — login success
/
(The randomized login token is used to verify for each access that the user's login cookie is actually valid, the result of a proper login with the correct password.)
05. The DDGDS File System
C Startpage + Contact
Esc Search / Table of Contents
Tab