SchemaCatalog
The model of what is in a store, derived from its documents as they are written.
val catalog = SchemaCatalog(directory)
DocumentStore.open(directory, StoreOptions(segmentObserver = catalog)).use { store ->
store.put(Key.of("user:1"), Variant.fromJson("""{"name":"ada","team":"analytics"}"""))
store.flush()
catalog.attach(store)
println(catalog.inferSchema().render())
catalog.indexCandidates().forEach(::println)
}Nothing here scans the store. Statistics are collected on the flush and compaction passes that were going to walk every document anyway, kept in a .cat sidecar next to each segment, and folded on demand. A compaction that merges two segments into one replaces two sketches with one as a consequence of the merge, so the model is never stale and there is no invalidation step to forget. attach covers whatever was written before the catalog existed, by reading the segments that are already there — which is the whole "model later" claim, and it is why an index recommendation can be asked for on a store nobody planned to model.
Two objects, and the order matters. The observer has to be installed in app.oreshkov.rabosh.core.StoreOptions before the store opens, because a flush can begin the moment it does; attach is what loads the sidecars and backfills the rest, and until it is called this catalog answers nothing. That is deliberate — a model that quietly reported on half a store would be worse than one that refuses. A caller who would rather not remember any of it opens a Rabosh from rabosh-api, which owns the ordering and reaches this catalog through one backfill pass shared with the index catalog.
Thread safety. Safe to call from any thread. The store's maintenance thread drives beginSegment, SegmentObservation.complete and retain while a reader may be inside inferSchema; the accumulation of one segment happens on one thread and is not shared.
Properties
Whether attach has been called. Nothing is answered before it has.
Tuning. See CatalogOptions.
Functions
Loads what is on disk, scans whatever is not, and starts maintaining the model.
The paths worth an index, best first.
Folds the live segments' sketches into one model.
Discards everything and rebuilds it from the segments.
The sketch of one segment, or null if it is not covered. For tests and for diagnostics.