mozilla / mentat

UNMAINTAINED A persistent, relational store inspired by Datomic and DataScript.
https://mozilla.github.io/mentat/
Apache License 2.0
1.65k stars 115 forks source link

Update TxObservers to filter by more complex criteria #621

Open fluffyemily opened 6 years ago

fluffyemily commented 6 years ago

Currently TxObservers only handle a set of matching attributes to filter whether it wants to be notified about a set of transactions. We need to be able to specify a set of filter criteria to further exclude notifications from an object.

For clients this might be - Providing an entid so a notification will only get fired for a specific record and not for all records that touch an attribute.

For materialized views this might be aggregation, negation or comparison logic, i.e. only notify me about transactions that have a value less than a constant, or that change number of times a url has been viewed.

fluffyemily commented 6 years ago

Copied from comments on https://github.com/mozilla-prototypes/sync-storage-prototype/issues/55 by @rnewman

Copying over my review comments about this:

The reason I added the watcher was to abstract away this growing set of "when this happens inside transact, do this" behaviors. Imagine that we want to add an observer that fires if a particular value is seen, a particular entity is touched, or any datom is retracted.

You can easily imagine the observer API you've built being expressed as a watcher that collects notes about tx_ids, later (when the tx is committed) using those notes to dispatch particular TxReports to particular observers. Indeed, you can use an arbitrary datom-level predicate to decide whether a report is of interest.

The watcher approach means we don't do any work unless there are caches/observers, and we don't allocate memory unless the watcher needs to.

Using TransactWatcher scopes the problem down to:

What changes do I need to make to TransactWatcher to support observer workloads? It probably needs to be told the tx_id.
How do I make a TransactWatcher from the observer service to hand off to an InProgress?
How do I get the value back out when it's done?
How do I combine the cache watcher and the observer watcher? Big chunks of the transactor are generic over W, so we should try to avoid making too many watcher types that are used in the same codebase — monomorphization will balloon our binary size. To me that points to struct DefaultTransactWatcher(cache_watcher: Option<InProgressCacheTransactWatcher>, observer_watcher: Option<ObserverWatcher>)…

The end result should be that the transactor doesn't know anything at all about observers, and doesn't track anything that the observer service needs, just as it doesn't track anything for the attribute cache — the watcher does all that.