Dqlite uses Raft protocol to keep all the replicas in sync. Since only the leader node in Raft will be able to add WAL entry, while other followers will replicate the WAL entries from the leader, there will not be conflicting WALs proposed by multiple nodes. In cases when a client tries to perform a write transaction on a non-leader node, the transation will fail. In addition, each dqlite node runs in a single thread that runs in a loop to execute query on the underlying SqLite engine. When not enough nodes are available in light of network parition, writes to the database might hung until consensus is reached or a timeout if triggered so that the write fails.
The Dqlite stores tuples in files backed up by disk as supported by the underlying SQLite engine. In addition, the tuples format is specified, consiting of a header and a body. The header of size 64-bit is a collection of 4-bit code which specifies the type of the corresponding value of the tuple. The body consists of values of the tuple that follow immediately after the header. ``` Headers: [Code 1 | Code 2 | ... | Code 16] [Code 17 | ... | Code 32] ... Body: Value 1 | Value 2 | ... ``` For tuple with less than 16 values, the header will ba padded with 0. For tuple with more than 16 values, multiple headers will be used. The values in the body will be encoded by type-specific encoding schemes.
Upon executing a SQL statement, the request will be dispatched to the leader node's execution loop first, which will invoke the underlying SQLite engine to step over the statement. If the execution of statement requires actions across replicas, the control will be switched back to the main loop. After the main loop finishes replicating the Raft logs across replicas, the control will be switched back to the execution loop, and thus the underlying SQLite engine will continue stepping over.
Similar to SQLite, Dqlite performs checkpointing automatically when the length of the Write-Ahead-Logging (WAL) file reaches a thresdhold size of certain pages. (The default value in the Dqlite setting is 1000). The leader will delay the checkpoint operation if the WAL logs have not reached the thresdhold or the underlying sqlite database is "locked" (returns SQLITE_BUSY) by another connection. Upon performing the checkpoint, the leader will issue a checkpoint command and sends that command to the followers. Once the checkpoiting command is committed by all the followers, they will perform checkpoiting respectively in SQLITE_CHECKPOINT_TRUNCATE mode, that is blocking.
Since the underlying database engine is SQLite, Dqlite only supports row-based relational data model.