-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add projections #135
Add projections #135
Conversation
Codecov ReportBase: 90.96% // Head: 89.36% // Decreases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## main #135 +/- ##
==========================================
- Coverage 90.96% 89.36% -1.61%
==========================================
Files 18 19 +1
Lines 3167 3292 +125
==========================================
+ Hits 2881 2942 +61
- Misses 286 350 +64
Flags with carried forward coverage won't be shown. Click here to find out more.
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
905a211
to
8ba4f18
Compare
f14a8be
to
befdaf0
Compare
befdaf0
to
08f383b
Compare
6681e39
to
eeae5b6
Compare
eeae5b6
to
09f0aa1
Compare
09f0aa1
to
70a38d3
Compare
17cf48d
to
55c8bd2
Compare
55c8bd2
to
b7f9bac
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm so glad about this addition! This is really cool :-)
I submitted several comments. I could split my feedback into two topics:
- Some documentation comments
- The way payloads are passed from the state machine to the projection function
About the payloads, I suggest we do like the rest of the library: call khepri_machine:gather_node_props()
to create a node properties map and pass this common format to khepri_projection:trigger()
, then decide in that function how to call the projection function.
I think we could pass the entire node properties maps (old and new) to the extended projection function, and reduce payloads to bare data for the simple one (possibly undefined
for the old data in case a payload is added). The simple function will never be called when the new payload has no data.
What do you think?
34d66d0
to
9c99147
Compare
9c99147
to
d97caae
Compare
Thanks for the feedback @dumbbell! I like the idea of passing For the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes, it looks good to me. I have a few more tiny comments on the documentation and one question for the simple projection function.
Ra 2.4.0 introduces new reply modes which control which member of a cluster performs the `gen_statem:reply/2` to a command. This can be used to block the caller until the command has been handled by a given member. The child commit will introduce a way to pass the new reply modes in `khepri:command_options()`.
This option wraps the equivalent option in `ra:process_command/3` - introduced in the dependency upgrade in the parent commit - which controls which member of the cluster calls `gen_statem:reply/2`. This can be used to block until a command has been handled by the local member which can prevent consistency issues with projections. A caller of `khepri:put/4` might assume that a subsequent `ets:lookup/2` (or similar) call is up-to-date immediately. By calling `khepri:put/4` with the `#{reply_from => local}` option, the caller can rely on this behavior.
da046b6
to
8cd3925
Compare
Projections are similar in spirit to database views. They are a subset of the store collected into an ETS table which is replicated to all members of the Khepri cluster. Implementation-wise, projections are similar to triggers except that projections are updated synchronously by the machine and are triggered on all changes to a given path pattern. Projections can be used for cases where reads are much more common than writes or in cases where read throughput and/or latency are important. This change initially introduces projections with the following additions to the API: * `khepri_projection:new/3` - Create a projection record. * `khepri_projection:name/1` - Retrieve the name (the ETS table name) of the projection. (Necessary because the projection record is opaque). * `khepri:register_projection/4` - Register a projection within the store against a given path pattern. As well as the internal implementation in `khepri_machine` and the associated documentation.
With this change, if any projections exist, they are listed in the output of `khepri:info/2`.
8cd3925
to
64df3a4
Compare
Projections are a system for creating replicated ETS caches available on all members of a Khepri cluster. A new function
khepri_projection:new/3
creates a projection resource:The projection resource may then be registered to a pattern of nodes with
khepri:register_projection/4
:Once registered, the projection's ETS table is created and then filled with any existing records matching the pattern. Paths and data are passed through the
ProjectionFun
to create records which are then stored in the table. Any future changes to records which match thePathPattern
are also applied to the projection table.The projection table is a named ETS table which may be queried directly with
ets
:Projections should be used to maximize query throughput and/or minimize query latency at the cost of consistency and memory consumption. Projections have the same consistency guarantees as queries tried with the
#{favor => low_latency}
option. Data stored in the projection table is at least partially duplicated between the store and the projection table, so increased memory consumption is expected for projections with path patterns matching many nodes.