(independent/checker (checker/set)) example

11 views
Skip to first unread message

Anton Kaliaev

unread,
Feb 4, 2021, 4:44:12 AM2/4/21
to Jepsen Talk
Hi all,

I'm currently in a process of rewriting Tendermint tests to use Jepsen 0.2 https://github.com/tendermint/jepsen.

At the moment, I'm struggling to figure out how to make `(independent/checker (checker/set))` work. Is there an example somewhere?

Here is the full code:

      (let [keys (atom [])]
        {:client (SetClient. nil)
         :generator (independent/concurrent-generator
                     (* 2 n)
                     (range)
                     (fn [k]
                       (swap! keys conj k)
                       (gen/phases
                        (gen/once {:type :invoke, :f :init})
                        (->> (range)
                             (map (fn [x]
                                    {:type :invoke
                                     :f    :add
                                     :value x}))
                             (gen/stagger 1/2)))))
         :final-generator (deref-gen
                           (delay
                            (locking keys
                              (independent/concurrent-generator
                               (* 2 n)
                               @keys
                               (fn [k]
                                 (gen/each-thread (gen/once {:type :invoke
                                                             :f :read})))))))
         :checker {:set (independent/checker (checker/set))}}))))


where deref-gen is an old way to construct a delayed generator.

(defn deref-gen
  "Sometimes you need to build a generator not *now*, but *later*; e.g. because
  it depends on state that won't be available until the generator is actually
  invoked. Wrap a derefable returning a generator in this, and it'll be deref'ed
  only when asked for ops."
  [dgen]
  (reify gen/Generator
    (op [this test process]
      (gen/op @dgen test process))))

This results in java.lang.StackOverflowError: null exception.

Now, could someone guide me towards a correct way of performing one READ operation per key in a final generator (without using deref gen)? Or, in other words, a way to generate a bunch of write ops (with different keys) for a set and, later, read them.

Thanks a lot!
Anton

Kyle Kingsbury

unread,
Feb 4, 2021, 9:30:45 AM2/4/21
to ta...@jepsen.io
On 2/4/21 4:44 AM, Anton Kaliaev wrote:
Hi all,

I'm currently in a process of rewriting Tendermint tests to use Jepsen 0.2 https://github.com/tendermint/jepsen.

At the moment, I'm struggling to figure out how to make `(independent/checker (checker/set))` work. Is there an example somewhere?

It sounds like the problem here isn't with the checker, but perhaps with the generator?

where deref-gen is an old way to construct a delayed generator.

(defn deref-gen
  "Sometimes you need to build a generator not *now*, but *later*; e.g. because
  it depends on state that won't be available until the generator is actually
  invoked. Wrap a derefable returning a generator in this, and it'll be deref'ed
  only when asked for ops."
  [dgen]
  (reify gen/Generator
    (op [this test process]
      (gen/op @dgen test process))))

This results in java.lang.StackOverflowError: null exception.

I'm not quite sure what to make of this stacktrace--it looks like it's something in pretty-printing, but I'm not sure what's being printed. The full trace might be helpful. I imagine that if you're using this implementation of deref-gen, it might be something to do with that--the entire generator protocol was redesigned in 0.2.x, which I imagine has something to do with why this test is exploding. See the changelog in 0.1.19 and 0.2.0 for details, and jepsen.generator's docstring for detailed migration instructions.

Replacing deref-gen should, I think, be straightforward. I don't recall exactly how/why I wrote this part of the tendermint test, but I think you might try either a.) (delay @dgen) or b.) (fn [test context] @dgen) as a generator. Either should work, since Delay implements the Generator protocol directly (https://github.com/jepsen-io/jepsen/blob/main/jepsen/src/jepsen/generator.clj#L569), as do functions, and both can now return generators, rather than individual operations.

--Kyle

Anton Kaliaev

unread,
Feb 4, 2021, 10:19:33 AM2/4/21
to Jepsen Talk, ap...@jepsen.io
> It sounds like the problem here isn't with the checker, but perhaps with the generator?

Right! Sorry if the title is misleading. I just thought maybe someone has a working example :)

>  sure what to make of this stacktrace--it looks like it's something in pretty-printing, but I'm not sure what's being printed

The stack overflows when the Jepsen tries to print the test configuration (generators, client, concurrency, etc.). Without deref-gen (when I comment out :final-generator) it works fine (except there are no read operations of course):

 ((jepsen.generator.Synchronize
   {:gen (jepsen.generator.TimeLimit
          {:limit 60000000000,
           :cutoff nil,
           :gen (jepsen.generator.Any
                 {:gens [(jepsen.generator.OnThreads {:f #{:nemesis}, :gen nil})
                         (jepsen.generator.OnThreads
                          {:f #object[clojure.core$complement$fn__5669
                                      "0x7f825464"
                                      "clojure.core$complement$fn__5669@7f825464"],
                           :gen (jepsen.generator.OnThreads
                                 {:f #object[clojure.core$complement$fn__5669
                                             "0x4a42bb32"
                                             "clojure.core$complement$fn__5669@4a42bb32"],
                                  :gen (jepsen.independent.ConcurrentGenerator
                                        {:n 10,
                                         :fgen #object[jepsen.tendermint.core$workload$fn__28815
                                                       "0x2966d68"
                                                       "jepsen.tendermint.core$workload$fn__28815@2966d68"],
                                         :group->threads nil,
                                         :thread->group nil,
                                         :keys (0 1 2 3 4 5 6 7 ...),
                                         :gens nil})})})]})})})

Anyway, thanks for the pointers! I will give delay and (fn [test context] @dgen) a try.

Cheers,
Anton

Anton Kaliaev

unread,
Feb 4, 2021, 10:40:35 AM2/4/21
to Jepsen Talk, Anton Kaliaev, ap...@jepsen.io
Didn't know delay implements Generator protocol. It worked! Thanks again. I will post the final version of the code here later.
Reply all
Reply to author
Forward
0 new messages