This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-07-31
Channels
- # announcements (2)
- # babashka (145)
- # beginners (260)
- # calva (17)
- # chlorine-clover (7)
- # clj-kondo (9)
- # cljsrn (1)
- # clojure (88)
- # clojure-dev (65)
- # clojure-europe (31)
- # clojure-france (4)
- # clojure-nl (4)
- # clojure-uk (61)
- # clojuredesign-podcast (1)
- # clojurescript (31)
- # code-reviews (1)
- # cursive (32)
- # data-science (2)
- # datascript (9)
- # datomic (39)
- # docker (3)
- # events (1)
- # figwheel (95)
- # figwheel-main (4)
- # fulcro (17)
- # kaocha (2)
- # keechma (1)
- # malli (1)
- # meander (35)
- # nrepl (4)
- # off-topic (1)
- # pathom (8)
- # re-frame (4)
- # reagent (8)
- # reitit (3)
- # releases (1)
- # remote-jobs (2)
- # shadow-cljs (182)
- # sql (30)
- # tools-deps (89)
- # xtdb (31)
heyo, any other jdbc+sqlite users out there? sometimes if there's an error or i interrupt the process the sqlite file gets and stays locked. curious if there's anything i could do to avoid that and if there's any workarounds
nvm, realized there wasn't a reason for me to not use lmdb (i just wanted the most performant and persistent JAR-embeddable implementation)
What is the scaling story of crux? Datomic has a single writer, but reads can be scaled horizontally. What is the similar statement for crux?
Reads scale horizontally also. Each node handles writes by itself, so you have a single writer limitation there too, effectively.
@dominicm That is, as long as you use kafka? Using rocksdb as backend will constrict you to one node, as rocksdb only supports one writer. Do I understand that right?
@sveri right. Rocksdb is not yet distributed (although I vaguely recall such a thing existing).
What about JDBC backend?
Would it be possible to have multiple tx_events tables in a database with JDBC?
The key thing to understand is that each node synchronizes with your event store. Your bottleneck is constrained by: - time to write to event storage - time to read event storage into indexes on each node
JDBC's speed at taking writes will be dictated by your underlying database & table. I don't know how the underlying table looks, but I bet a timescale hyperlog table would perform far better than a normal table. But you're essentially limited by your ability to append that table I think. I don't know much about the jdbc implementation. So take those guesses with a grain of salt and measure measure measure.
We currently only use JDBC for the golden stores - the transaction log and the document store (ie not for the query indices). Regarding the performance characteristics that we use for those - the transaction log adds rows to the end of a table, the document store is essentially a content-addressable kv-store
It'd be quite reasonable to mix-and-match those, too - Kafka for the transaction log (for its write characteristics) and JDBC for the document store
Each Crux node then consumes the transaction log and document store, and updates its own set of query indices - this is where RocksDB/LMDB shine
There's some good variety in crux-bench
https://github.com/juxt/crux/blob/6d50c3688cef9e25d04fa497498c0908baf76688/crux-bench/src/crux/bench.clj#L206-L281
Is there any best practice when using Crux to implement a "global" counter, such as a human readable integer order number. One possible solution could be to have a document with the current value of the counter and then use a transaction-fn to read the value and add it to any new order, another could be to keep an index of orders in a document {:1 :internal-order-id-1 :2 :internal-order-id-2}, again updating and creating within a transaction-fn. What would be the trade-offs and am I missing any obvious solution?
This seems reasonable - it's naturally a problem that requires serialised transactions so a transaction function seems a good fit.
At first glance, I'd consider a put-order
tx-fn that could take the order doc, increment the counter document and assoc the new order-id into the order before putting it
Are there plans to implement something like :patch instead of only :put for crux? I imagine that the challenges can be incredibly hard, like patching a document with a future valid-time, but I also think it can be a killer feature :)
I think there's an implementation in user space, I asked about this recently and @taylor.jeremydavid answered 🙂
@U3Y18N0UC here's the chat mentioned from a few days ago: https://clojurians-log.clojureverse.org/crux/2020-07-22/1595412638.309300 I think it is definitely solvable in user-space using transaction functions, but in general though we would only be likely to add a "native" patch operation if we change the nature of the underlying data model in some way. We might also consider it if we could make stronger guarantees about the efficiency, for instance with a doc-store that benefit from structural sharing
Thanks a lot for all the discussion! May I ask what is a query index? Is it the eavt/aevt/avet B-Tree?
Hi 🙂 Crux indexes are stored using a single set of sorted key-value pairs in Rocks/LMDB (Rocks is an LSM tree, but LMDB is a kind of B-tree). We don't use the eavt/aevt/avet structures specifically but the general idea is the same. For a good overview I can recommend this talk: https://www.youtube.com/watch?v=YjAVsvYGbuU This is where are our index prefixes are defined: https://github.com/juxt/crux/blob/master/crux-core/src/crux/codec.clj#L30-L51
@dominicm do you think it's possible to, like, transact a change in :age
field with valid-time
in the future with this userspace implementation, and it'll respect changes on other fields that happened before that valid-time?
I think this can be made to work, but you must funnel all updates to your entity through your txfn, such that the future valid-time
version is always correct