0.2.1
This release firms up the changes made in 0.2.0. It resolves some serious bugs involving the generator system, as well as client & nemesis lifecycle management which snuck through 0.1.19 and 0.2.0 testing. It adds an experimental namespace to aid in structuring membership state machines--something Jepsen users have been writing by hand for years. We've moved to Debian Buster, and Pavlo Baron has contributed a kubernetes remote for jepsen.control. There are also some minor performance and ergonomic improvements: clients can optionally indicate that their internal state is safely re-usable after crashing, tests are printed more politely, and Jepsen logs the Git hash and command-line arguments necessary to reproduce a given test.
The tutorial has also been updated for Jepsen 0.2.x, and the Docker environment has been updated to construct Debian Buster nodes with full init systems. That means you can to run tests which use vendor-provided init scripts!
Bugfixes
- checker/counter incorrectly advertised that it supported decrements when it did not. This could have resulted in counter tests which reported failures when the history was, in fact, legal. To Jepsen's knowledge, nobody has reported this issue. However, at least one third-party test did use the counter checker in this way. The checker now throws when provided negative increments.
- generator.interpreter originally updated generators with the thread<->process mapping from after a process crashed. This meant that generators which tried to handle an update involving an :info op would be unable to determine what thread had been responsible for that operation. This was the root cause of a crash in independent/concurrent-generator, which worked fine... until a process crashed. The interpreter now provides the original thread<->process mapping when updating generators.
- core/run!, at the end of a test, would improperly run client/teardown! and client/close! on just a single client and node, rather than all clients. This caused Jepsen to gradually leak clients between multiple test runs. Jepsen now correctly tears down all clients at the end of a test.
- nemesis/compose, when given a collection (rather than a map) of nemeses, now correctly propagates teardown calls to those nemeses.
- core/run!, at the end of a test, incorrectly tore down the original nemesis, rather than the nemesis returned from calls to nemesis/open!. Since most nemeses return themselves, this didn't affect most tests--but it did prevent correctly tearing down nemeses which, say, construct state during setup!. Jepsen now tears down the correct nemesis.
- generator/stagger incorrectly assumed that it should start yielding operations at the start of every test, instead of when it was first asked for an operation. As a result, staggers evaluated later in a multi-phase test would "race" to catch up with operations they weren't able to perform earlier. They've learned to chill out now.
- nemesis.combined/compose-packages no longer crashes when constructing a final-generator from packages whose final generators weren't sequences.
New Features
- nemesis.membership: an experimental namespace which supports writing membership-changing nemeses and generators. Users provide an implementation of the nemesis.membership.state/State protocol: a mostly-pure structure which defines how to observe the state of the cluster on a specific node, merging those node views, generating operations, applying those operations to the cluster, and (since clusters often resolve membership changes asynchronously) deciding when those operations have been completed. Given this object, the membership system handles spawning threads to observe the cluster state, evolves the given state machine towards a fixed state over time, and provides a stateful nemesis and generator that work together to perform membership changes. The resulting package can be combined with other faults through nemesis.combined.
- client/Reusable: a new protocol which clients can implement, allows a client to indicate that its state can safely be re-used when it issues a {:type :info} operation. The default behavior remains to close the client and open a fresh one, but if your clients are safe to re-use, you can use this protocol to improve performance and reduce log chatter.
- jepsen.control.k8s allows jepsen.control to talk to Kubernetes nodes.
- db/tcpdump offers a :clients-only? option which restricts logging to only client traffic from the Jepsen control node.
- Jepsen now logs the GIT hash and command line used at the start of each test, which makes it easier to reproduce results.
- jepsen.generator.test provides functions to aid in writing unit tests for your own generators.
- jepsen.generator.concat provides a more explicit version of
[gen1, gen2]
.
API Changes
- none
Minor Changes
- The tutorial has been rewritten for Jepsen 0.2.1.
- util/test->str converts tests to strings. Tests often have many keys (which should all be printed) but infinite sequences in their generators (which should only print a few elements). This function resolves that tension by printing all keys, but specifically limiting the length when printing generators.
- jepsen.core/run! automatically wraps nemeses in a validator, which helps identify and explain some basic nemesis mistakes.
- util/fixed-point iterates a function over an initial value until converged.
- Expanded documentation for some generators.
- os.debian/install, following a deprecation warning in apt, now uses --allow-x flags instead of --force-yes flags.
- jepsen.control.net/control-ip returns the IP of the control node, as seen by db nodes.
- jepsen's own project.clj sets awt.headless=true, which is needed for compilation/running of Jepsen itself (not tests!) on headless environments.