Prepare a public source checkout
The walkthrough uses Flyology.DB, the local Files object-storage backend, Alire 2.1.1, and an Ada 2022 toolchain. It needs network access only when it clones the source and materializes the exact qualified Object Storage dependency.
The example uses compact fixed IDs only because the runner requires one fresh root. An application must allocate and persist never-reused IDs in every applicable namespace.
Build the source and exact dependency
Clone the public repository. The maintained materializer checks out the reviewed Object Storage revision under the ignored development directory.
git clone https://github.com/flyology-ada/flyology-db.git
cd flyology-db
bash scripts/materialize-development-dependencies.sh
alr buildThe materializer refuses a conflicting or dirty dependency. It does not select a newer dependency revision.
Run one database before reading the implementation
Pass one absolute Files root that does not exist. Its physical parent must already exist. The path must contain no symbolic-link ambiguity, empty component, dot component, or parent component.
bash examples/run-files-getting-started.sh \
"$PWD/flyology-db-example-data"The command creates a database, commits and reads values, publishes checkpoints, and closes every owner. It then reopens the database twice. On success, it prints this line before the general success lines:
Flyology.DB Files retained-checkpoint live-suffix family reopen: OKKeep the generated root. The runner never deletes it. The remaining sections explain the opening create, write, and read stage from the maintained Ada source.
Choose explicit limits and one family
The example configures one records family. It also persists bounds for histories, transactions, mutations, live state, runs, and read tracking.
-- This walkthrough makes each operational choice explicit. The values
-- below size only one fresh demonstration and are not library defaults or
-- recommendations for another workload.
Maximum_Object_Size : constant OS.Byte_Count := 65_536;
Timeout : constant Duration := 10.0;
Bucket : constant String := "flyology-db-getting-started";
Prefix : constant String := "database";
Limits : constant DB.Database_Limits :=
(Maximum_Column_Families => 2,
Maximum_Manifest_History => 7,
Maximum_Batch_History => 4,
Maximum_Transactions_Per_Batch => 2,
Maximum_Mutations_Per_Transaction => 2,
Maximum_Mutations_Per_Batch => 2,
Maximum_Live_Entries => 4,
Maximum_Transaction_Payload_Bytes => 256,
Maximum_Batch_Payload_Bytes => 512,
Maximum_Live_State_Bytes => 4_096,
Maximum_Total_L0_Runs => 3,
Maximum_Checkpoint_Identities => 9,
Maximum_Point_Reads_Per_Transaction => 4,
Maximum_Scan_Ranges_Per_Transaction => 1);
Families : constant DB.Column_Family_Configuration_Array :=
[DB.Configure_Column_Family
(ID => 1,
Name => Bytes ("records"),
Max_Key_Bytes => 32,
Max_Value_Bytes => 64,
Memtable_Max_Bytes => 1_024,
Memtable_Max_Entries => 4,
Maximum_L0_Runs => 2)];The local Bytes helper converts each demonstration string into a byte array. The application must choose limits from its workload. These values are fixtures, not library defaults.
Bind storage and create the database
The storage binding borrows the Files store. Keep both owners alive while the database uses them. Create receives the database ID, publication IDs, persisted limits, family configuration, and deadline.
Binding.Bind (Storage, Store'Access, Bucket, Prefix);
DB.Create
(Item,
Storage'Access,
Demo_Database_ID,
Create_Manifest_ID,
Create_Transition_ID,
Limits,
Families,
Timeout,
Receipt => Create_Info,
Result => Result);
if Result = DB.Outcome_Unknown then
DB.Resolve_Create
(Item, Storage'Access, Create_Info, Timeout, Result => Result);
end if;
Expect
(Result, DB.Success, "database create did not resolve conclusively");The binding borrows the Files store, so the store must outlive the database. If Create sets Result to Outcome_Unknown, the example resolves the original receipt. It does not start Create again with replacement IDs.
Write and commit one value
Begin one snapshot transaction. Open the configured family, Put the key and value, then commit the transaction.
DB.Begin_Transaction
(Item, Checkpoint_Transaction_ID, DB.Snapshot, Writer, Result);
Expect (Result, DB.Success, "writer begin failed");
declare
Family : DB.Column_Family;
begin
DB.Open_Column_Family (Item, 1, Family, Result);
Expect (Result, DB.Success, "family open failed");
DB.Put
(Item, Writer, Family, Checkpoint_Key, Checkpoint_Value, Result);
Expect (Result, DB.Success, "put failed");
end;
DB.Commit
(Item, Writer, Timeout, Receipt => Commit_Info, Result => Result);
if Result = DB.Outcome_Unknown then
DB.Resolve (Item, Commit_Info, Timeout, Result => Result);
end if;
Expect (Result, DB.Success, "commit did not resolve conclusively");A successful Commit consumes the transaction. If Commit sets Result to Outcome_Unknown, call Resolve with the same receipt. Do not submit the application transaction again.
Read the committed value in a new transaction
The example begins a separate read transaction at a fixed snapshot. It opens the same family, calls Get, and checks the returned bytes.
DB.Begin_Transaction (Item, Reader_ID, DB.Snapshot, Reader, Result);
Expect (Result, DB.Success, Context & " reader begin failed");
DB.Open_Column_Family (Item, 1, Family, Result);
Expect (Result, DB.Success, Context & " records family open failed");
DB.Get (Item, Reader, Family, Checkpoint_Key, Data, Result);
Expect (Result, DB.Success, Context & " checkpoint get failed");
Require
(Same (Data, Checkpoint_Value),
Context & " checkpoint value bytes differ");Expect, Require, and Same are checks in the maintained example, not Flyology.DB operations. The helper calls Rollback after the reads because the transaction has no mutations to commit.
Keep custody of the retained root
The command prints the root again from its exit trap. Inspect or archive the files after every process exits. Remove them only through your own explicit cleanup policy.
This example proves a functional path on one exact source and dependency tree. It does not provide automatic backup, retention, garbage collection, migration, or production qualification.
Add checkpoint recovery next
The first transaction proves the basic call lifecycle. The next chapter explains why and when the example publishes a checkpoint before it closes the database.