How data is stored
A database holds collections. A collection holds documents. Documents live in pages on disk.
Kova looks like a document database to the client and like a page store on disk. You name databases and collections. The server decides the files.
Names
- DatabaseThe
$dbon every command.shopanddbare different databases.adminexists on a fresh process and holds the catalog. - CollectionA named set of documents, stored as
database.collection.shop.ordersanddb.ordersdo not share rows. Names are case-sensitive:empandEMPare two collections. - DocumentOne BSON object. Nested documents and arrays are stored as you send them.
_ididentifies the document inside the collection. Omit it on insert and Kova assigns an ObjectId. - PageThe unit on disk. Many documents share a page. A document larger than the page continues onto overflow pages. The default page envelope is 16 KB, set by
page_size. - Buffer poolThe only cache that grows with what you read. A miss reads the page from disk. When the pool is full, the least recently used page is written back if it changed, then dropped. The default is 4096 pages per partition.
What survives a crash
Every insert, update, and delete is appended to a write-ahead log before the page changes. wal_fsync defaults to true, so the append is flushed. A checkpoint writes the dirty pages, records how far the log has been applied, and deletes the log segments behind that point. Startup opens the pages and replays only the tail of the log.
The layout under data/ is one directory per partition: partition-0, partition-1, and so on. Each has its pages and its log. A replica set also writes raft-<id>/.
Page payloads are compressed with zstd. The cache and your queries see the plain documents. The log stays uncompressed. If you set an encryption key, the page file and the log record are encrypted after compression. Startup with encrypted files and no key fails.
Four workers inside one process
One Kova process runs four partition workers. The collection name is hashed, and every document of that collection on this process lives on one worker. shop.orders is entirely on one partition. shop.customers may land on another. Commands for different collections run in parallel. Commands for one collection are ordered on that worker.
This split is inside the process. It is not sharding. Sharding sends different documents of the same collection to different processes, by hashing _id. That is a separate configuration, described on Sharding.
Indexes sit beside the pages
The pages are the database. A B-tree or hash index is rebuilt from those pages when the process starts, and kept up to date on every write. The catalog remembers which indexes exist. A text index (Tantivy) is the same idea for words: updated on write, rebuilt from the pages on startup, unless a view asked for an on-disk text index.
A point lookup by _id uses the id index. A predicate the planner can cover uses a secondary index. Anything else walks the collection's pages. explain reports which path ran. Details are on Indexes.
The catalog is queryable
Database names, collections, field types, indexes, users, roles, views, and autoincrement counters are rows in admin. You can find them. They are written at checkpoint from the memory the process already keeps, and read back on startup so the process does not scan every document to remember the schema. The Catalog page lists each collection and the fields on its rows.