SecondaryJsonStore

A store read beside its writer, opened with JsonStore.openSecondary: it offers every read of ReadableJsonStore and never writes. It takes no lock, so it works while another process has the store open as a JsonStore, and with no writer at all (SPEC.md §8.1).

It reads one state of the store at a time, the one its last refresh (or the open) read: everything the writer had acknowledged before that began, and possibly writes it hadn't acknowledged yet. Every read uses the newest such state, and a result keeps the state it started on until it is closed, however often the store is refreshed meanwhile. A secondary doesn't refresh by itself; call refresh whenever newer data is wanted.

DocIds, NodeRefs and Cursors mean the same in the writer and its secondaries, so a cursor from one resumes on the other, as long as the store isn't reset in between. A secondary learns of an insert only once the writer has logged it, so a cursor's Cursor.mayMissLateCommits can't account for small inserts the writer had in flight.

Closing it releases its file handles; the space of files its writer deleted meanwhile comes back then. Thread-safe.

Properties

Link copied to clipboard

What this store was created with; fixed for its life (see CreationOptions).

Functions

Link copied to clipboard
abstract override fun blocking(): BlockingSecondaryJsonStore

The same store without coroutines: a view that shares this store's state, valid until this store is closed. The view has no close of its own; closing this store is what releases it.

Link copied to clipboard
abstract fun close()
Link copied to clipboard
abstract suspend fun count(query: DocumentKeyQuery, atMost: Long = Long.MAX_VALUE): Long

How many documents the key-order search returns for query, counting no further than atMost; see the other count.

abstract suspend fun count(query: JsonPathQuery, atMost: Long = Long.MAX_VALUE): Long

How many hits the JSONPath search returns for query, counting no further than atMost; see the other count.

abstract suspend fun count(query: KeyValueQuery, atMost: Long = Long.MAX_VALUE): Long

How many hits search returns for query on the current state, counting no further than atMost (SPEC.md §4.7): the same candidates and matches, with the query's after, type, mode and nested-hit filter, but no hit's JSON is read, and limit and maxBytes don't apply. count(query, n) == n tells whether there are at least n hits, and stops at the n-th. Refuses what search refuses; a negative atMost throws IllegalArgumentException.

Link copied to clipboard
abstract suspend fun countOfType(type: String): Long

The exact number of objects of type; reads the entry of every one of them.

Link copied to clipboard
abstract fun diff(a: CompareOperand, b: CompareOperand, options: DiffOptions = DiffOptions()): Flow<Difference>

The differences between a (left) and b (right), streamed in canonical order (SPEC.md §9.3): depth first, object members by key, array elements by index. Each collection runs the comparison on one new snapshot, on the store's dispatcher, and stops after DiffOptions.maxDifferences. Errors as in isEqual, thrown when collecting.

Link copied to clipboard
abstract fun explain(query: JsonPathQuery): QueryPlan

How search would find the candidate documents of query, without running it.

Link copied to clipboard
abstract suspend fun get(key: String): DocId?

The visible document whose key is key in a store with a CreationOptions.documentKey, or null when none is (SPEC.md §3.3); with Normalization.NFC, key is normalized first. A store without document keys throws IllegalStateException.

Link copied to clipboard
abstract fun info(): StoreInfo

How many documents the store holds, and has deleted; read from memory, so it costs nothing to ask.

Link copied to clipboard
abstract suspend fun isEqual(a: CompareOperand, b: CompareOperand, options: CompareOptions = CompareOptions()): Boolean

Whether the values a and b are equal (SPEC.md §9): typed, numbers by decimal value, strings by code points, object members in any order, array elements in order. Reads one snapshot of the store with memory independent of the values' sizes; values given as JSON are read and split first.

Link copied to clipboard
abstract fun listTypes(): List<TypeInfo>

Every type name ever assigned, sorted by name, with an approximate count of its objects.

Link copied to clipboard
abstract suspend fun objectsOfType(type: String, after: NodeRef? = null, limit: Int = 100): List<NodeRef>

Up to limit objects of type in (docId, nodePre) order from the current state, strictly after after when it's given; resume with the last one returned. Throws InvalidTypeNameException for an invalid name.

Link copied to clipboard
abstract fun objectsOfTypeFlow(type: String, after: NodeRef? = null): Flow<NodeRef>

Every object of type in (docId, nodePre) order, strictly after after when it's given, as a flow. Each collection reads one new snapshot on the store's dispatcher and holds it until the collection ends, so what one collection emits is consistent: the objects of the type as the operations acknowledged before it started left them. Throws InvalidTypeNameException for an invalid name, when collecting.

Link copied to clipboard
abstract suspend fun objectsOfTypePage(type: String, after: Cursor? = null, limit: Int = 100): TypePage

Up to limit objects of type in (docId, nodePre) order from the current state, strictly after after when it's given, and where the next page starts: TypePage.cursor, null when no objects were left. Only the cursor of a TypePage resumes it, anything else throws InvalidCursorException.

Link copied to clipboard
abstract suspend fun pathOf(node: NodeRef): String

Where node is in its document, as an RFC 9535 Normalized Path from the document root (SPEC.md §3.2): $['orders'][3], and $ for the root. Reads one fragment per level from the root down to the node.

Link copied to clipboard
abstract suspend fun refresh(): Boolean

Catches up with what the store's writer has written since this store last read it, and returns whether the state reads see changed. Reads already running, and results already open, keep the state they started on. Calls are serialized: a call waits for one running. Runs on the store's dispatcher.

Link copied to clipboard

Starts a search of documents in key order (SPEC.md §3.3) on the current state; close the result when done. A store without document keys throws IllegalStateException.

abstract fun search(query: JsonPathQuery): SearchResult

Starts a JSONPath search on the current state (SPEC.md §10.4): the distinct nodes the query selects from every document, in the query's order of (docId, nodePre). Close the result when done.

abstract fun search(query: KeyValueQuery): SearchResult

Starts a search on the current state, reading on the caller's thread; close the result when done. A search the index controls of CreationOptions leave unanswerable throws QueryRejectedException with QueryRejectedException.Reason.NOT_INDEXED (SPEC.md §4.6).

Link copied to clipboard
abstract fun select(node: NodeRef, path: JsonPath): SelectResult

The nodes path selects from the value of node, as RFC 9535 defines its nodelist: in the RFC's order, with duplicates, each with its Normalized Path, where $ is node (SPEC.md §10.3). The result reads the current state lazily; close it when done.

Link copied to clipboard
abstract suspend fun typeOf(node: NodeRef): String?

The type of node, or null, which nodes that aren't objects always get. Errors as in JsonStore.assignType.

Link copied to clipboard
abstract suspend fun verify(progress: VerifyProgress = VerifyProgress { _, _, _ -> }): VerifyReport

Reads everything the store can read back and reports what doesn't check out (SPEC.md §8): record and block checksums, the fragments each COMMIT still in the log names, and every fragment-index entry against the record it locates. Nothing is changed or repaired.

Link copied to clipboard
abstract fun writer(): LockHolder?

The process that has the store open as its writer, as it recorded itself when it opened the store, or null when no process has it open, or none could tell. The record is advisory, as StoreLockedException.holder is: a writer that couldn't write it still holds the store. Reads the record on each call.