Convex-Dev/convex

Refstats for internal `Ref` refactoring

Opened this issue · 4 comments

Some ref stats for inspiration with the internal refactoring mentioned at today's meeting.

Using a genesis state:

(def s (convex.cvm/state (convex.cvm/ctx)))
(def r (ACell/createPersisted s))
;; r:   {:direct 34839, :embedded 33858, :persisted 33406, :soft 11, :stored 33406, :total 34850}
(def r2 (ACell/createPersisted (.getValue r)))
;; r:   {:direct 33858, :embedded 33858, :persisted 1, :soft 992, :stored 1, :total 34850}
;; r2:  {:direct 33858, :embedded 33858, :persisted 992, :soft 992, :stored 992, :total 34850}

Using a large vector of Longs:

(def v (convex.cell/vector (map convex.cell/long (range 1000000))))
(def r (ACell/createPersisted v))
;; r:   {:direct 1066669, :embedded 1062501, :persisted 1066668, :soft 0, :stored 1066668, :total 1066669}
(def r2 (ACell/createPersisted (.getValue r)))
;; r:   {:direct 1062501, :embedded 1062501, :persisted 1, :soft 4168, :stored 1, :total 1066669}
;; r2:  {:direct 1062501, :embedded 1062501, :persisted 4168, :soft 4168, :stored 4168, :total 1066669}

Using a small vector:

(def v (convex.cell/* [:a :b :c]))
(def r (ACell/createPersisted v))
;; r:   {:direct 4, :embedded 4, :persisted 3, :soft 0, :stored 3, :total 4}
(def r2 (ACell/createPersisted (.getValue r)))
;; r:   {:direct 4, :embedded 4, :persisted 4, :soft 0, :stored 4, :total 4}
;; r2:  {:direct 4, :embedded 4, :persisted 4, :soft 0, :stored 4, :total 4}

One consideration is that there are valid-ish reasons for holding to an old cell after it has been persisted. E.g. a cell X is kept and used for some work but at some point it is persisted deep in a collection Y. It's not intuitive that one would have to retrieve the new "version" of X from the new version of Y returned by ACell.createPersisted in order to keep using it. At least it would be cumbersome, especially in multithreaded situations.

But based on today's discussion it doesn't sound like a problem, does it? Using the new version and discarding the old one is supposed to be an optimization that allows soft refs to kick in while improving subsequent writes (requirement for a peer).

Yes, it should be fine to hold onto old refs, as long as you are careful about memory usage limits etc. Basically you only want to keep a (bounded+reasonable) number of direct refs around.

Believe all this is now fixes in recent network / storage refactoring for 0.7.10

Behavior looks different but the core issue about orthogonal persistency is still there.
Now I get 0 soft refs with the following (whereas it produces 11 soft refs previously, which was still far from that 3% target we were discussing). Rewriting it again does not change anything in the ref stats:

(.cell.ref.stat (.db.write (.db.write *state*)))

{:embedded 50581,:persisted 49972,:direct 52236,:stored 49972,:soft 0,:total 52236}