The Technology Behind YottaDB
YottaDB features advanced technology, built on a proven code base, that delivers enhanced simplicity, security, stability and performance.
At the core of YottaDB is a daemon-less key-value database engine that executes within the address space of the application process, which makes in-memory calls to a YottaDB API. Combining the database engine and application logic in a single process yields several benefits:
A simpler architecture means that in the event of abnormal process termination or other process failure, the other processes of the application can continue. With a daemon, failure of a daemon process stalls the operation of multiple processes and perhaps even multiple applications.
Complexity is the enemy of security. With YottaDB’s daemon-less architecture, the security model is based on the mature, clearly documented, and well understood user-group-world permissions for processes to access database files, and is amenable to additional layered access controls such as SELinux or AppArmor.
The first process to open a database file sets up the control structures to manage it, and the last process to close the file cleans up the control structures. There is no daemon to start, stop, or tune.
With YottaDB’s database engine, processes cooperate with one another to manage the database, and the achievable throughput is limited by the underlying computing platform, rather than the potential single-point bottleneck of a daemon.
With the database engine in a shared library that executes within the address space of each process, application developers are free to develop applications in the language of their choice, from YottaDB’s roots in M/MUMPS to C and beyond.
Optimistic Concurrency Control
Unlike most high-end transactional database engines, YottaDB uses Optimistic Concurrency Control (OCC) to implement ACID transactions. Since transactions do not typically collide, optimistic techniques scale up better than pessimistic techniques such as locking. OCC and the daemon-less architecture reinforce each other to provide the extreme level of scalability that YottaDB users have come to expect.
How YottaDB OCC Works
Every database records a transaction number in its file header. Each database block header records the database transaction number when that block was last updated. When a process is inside a transaction:
- The database engine tracks the file and block number of each database block read, and the transaction number of that block. Since a block to be updated must first be read, this list includes blocks to be updated.
- When application logic updates the database, the update is retained in process-private memory and does not update the database. The update is visible to subsequently application logic within the process, but is not visible to any other process until the transaction commits.
- When the application logic signals that it is ready to commit the transaction, the database engine checks whether any block read within the transaction has a higher transaction number than that it has recorded. If none has — the typical case — the engine commits the transaction.
- If even one block has been updated since the process read it, the database engine discards its work and restarts the transaction logic. This restart is transparent to the application logic, which does not need to be coded to be aware of YottaDB transaction processing. This simplifies application code and improves maintainability. In the most common case, where a collision results from a random overlapping update by a concurrent process, it is able to commit on the second attempt.
- If the second attempt also fails to commit, the engine makes a third attempt, and if that fails, the engine concludes that pathological application logic is causing the collisions, and makes a fourth and final attempt during which updates by other processes are blocked, allowing the transaction to commit. [Applications should be written to avoid pathological colliding concurrent transactions; YottaDB provides tools and support services for application developers to identify such pathology should it occur.]
A logical database consists of a set of trees of nodes. Each tree is identified by a global variable name from 1 to 31 characters; each node has zero to 31 subscripts. On a computer system, persistence is provided by files in a filesystem. A global directory is a file that maps global variable trees and subtrees to database files that reside in filesystems. This mapping is flexible, powerful, and very useful.
Sample Data Example for International Applications
For an example that illustrates YottaDB’s completeness and flexibility for creating fully internationalized applications, consider an application requirement — sometimes legal, sometimes cultural — for user interfaces to be presented in many languages even as application logic remains unchanged. Consider the following historical capitals of Thailand (source: The Four Capitals of Thailand)
^Capital("Thailand")="Bangkok" ^Capital("Thailand",1238,1378)="Sukhothai" ^Capital("Thailand",1350,1767)="Ayutthaya" ^Capital("Thailand",1767,1782)="Thonburi" ^Capital("Thailand",1782)="Bangkok"
which might also have cross references as follows:
^Xref(“Capital”,”Thailand”,”Ayutthaya”)=”1350,1767” ^Xref(“Capital”,”Thailand,”Bangkok”)=1782 ^Xref(“Capital”,”Thailand”,”Sukhothai”)=”1238,1378” ^Xref(“Capital”,”Thailand”,”Thonburi”)=”1767,1782”
With an application that segregates language-specific strings into separate trees or subtrees, support for a Thai language user interface can be added by creating (a) a database file with support for the strings in Thai, and (b) a global directory that maps the Thai language specific strings to a database file that has the same nodes / subtrees as the global directory for the English interface, but whose values (or in the case of cross references, subscripts) are in the Thai language. For example, the Thai language global directory may have the nodes
^Capital("Thailand")="กรุ่งเทพฯ" ^Capital("Thailand",1238,1378)="สุโขทัย" ^Capital("Thailand",1350,1767)="อยุธยา" ^Capital("Thailand",1767,1782)="ธนบุรี" ^Capital("Thailand",1782)="กรุ่งเทพฯ"
as well as the cross-reference nodes
^Xref(“Capital”,”Thailand”,”กรุ่งเทพฯ”)=1782 ^Xref(“Capital”,”Thailand”,”อยุธยา”)=”1238,1378” ^Xref(“Capital”,”Thailand”,”ธนบุรี”)=”1767,1782” ^Xref(“Capital”,”Thailand”,”สุโขทัย”)=”1350,1767”
Note that the cross reference nodes are in a different order in Thai than they are in English. As subscripts in YottaDB is always sorted, cross references “just work” correctly.
The ability to provide multiple views or slices into the same data has many uses other than internationalization. In conjunction with database file access permissions, potentially with layered role-based access mandatory access control or by using encryption with different keys, different classes of users can be restricted to access only those global variables to which they should have access.