Skip to content

Commit 6961c4d

Browse files
committed
Add nemeses support
Write via leader only Closes #16 Closes #17 Closes #21 Closes #25 Closes #34
1 parent cba5d2f commit 6961c4d

File tree

5 files changed

+117
-10
lines changed

5 files changed

+117
-10
lines changed

src/tarantool/counter.clj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838
(cl/with-error-handling op
3939
(cl/with-txn-aborts op
4040
(case (:f op)
41-
:add (do (j/execute! conn
42-
[(str "UPDATE " table-name " SET count = count + ? WHERE id = 0") (:value op)])
41+
:add (let [con (cl/open (jepsen/primary test) test)]
42+
(do (j/execute! con
43+
[(str "UPDATE " table-name " SET count = count + ? WHERE id = 0") (:value op)]))
4344
(assoc op :type :ok))
4445

4546
:read (let [value (:COUNT

src/tarantool/db.clj

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,31 @@
246246
(stop! test node)
247247
(wipe! test node))
248248

249+
;db/Primary
250+
;(setup-primary! [_ test node])
251+
252+
;(primaries [_ test]
253+
; (->> (node-state test)
254+
; (filter (comp #{:leader} :role))
255+
; (map :node)))
256+
257+
db/Process
258+
(start! [_ test node]
259+
(start! node {}))
260+
;{:initial-cluster-state (if @(:initialized? test)
261+
; :existing
262+
; :new)
263+
; :nodes @(:members test)}))
264+
265+
(kill! [_ test node]
266+
(c/su
267+
;(cu/stop-daemon! binary pidfile)))
268+
(cu/grepkill! :kill "tarantool")))
269+
270+
db/Pause
271+
(pause! [_ test node] (c/su (cu/grepkill! :stop "tarantool")))
272+
(resume! [_ test node] (c/su (cu/grepkill! :cont "tarantool")))
273+
249274
db/LogFiles
250275
(log-files [_ test node]
251276
[logfile])))

src/tarantool/nemesis.clj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
(ns tarantool.nemesis
2+
"Nemeses for Tarantool"
3+
(:require [clojure.pprint :refer [pprint]]
4+
[clojure.tools.logging :refer [info warn]]
5+
[dom-top.core :refer [real-pmap]]
6+
[jepsen [nemesis :as n]
7+
[net :as net]
8+
[util :as util]]
9+
[jepsen.generator :as gen]
10+
[jepsen.nemesis [combined :as nc]
11+
[time :as nt]]))
12+
13+
(defn nemesis-package
14+
"Constructs a nemesis and generators for Tarantool"
15+
[opts]
16+
(let [opts (update opts :faults set)]
17+
(nc/nemesis-package opts)))

src/tarantool/runner.clj

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
[control :as c]
1313
[independent :as independent]
1414
[generator :as gen]
15-
[nemesis :as nemesis]
1615
[tests :as tests]
1716
[util :refer [timeout meh]]]
1817
[jepsen.checker.timeline :as timeline]
@@ -21,7 +20,8 @@
2120
[tarantool [db :as db]
2221
[register :as register]
2322
[sets :as sets]
24-
[counter :as counter]]))
23+
[counter :as counter]
24+
[nemesis :as nemesis]]))
2525

2626
(def workloads
2727
"A map of workload names to functions that can take opts and construct
@@ -48,6 +48,10 @@
4848
;:pages pages/workload
4949
:register register/workload})
5050

51+
(def standard-workloads
52+
"The workload names we run for test-all by default."
53+
(keys workloads))
54+
5155
(def workload-options
5256
"For each workload, a map of workload options to all the values that option
5357
supports."
@@ -64,6 +68,32 @@
6468
;:pages {:serialized-indices [true false]}
6569
:register {}})
6670

71+
(def nemeses
72+
"Types of faults a nemesis can create."
73+
#{:pause :kill :partition :clock})
74+
75+
(def standard-nemeses
76+
"Combinations of nemeses for tests"
77+
[[]
78+
[:pause]
79+
[:kill]
80+
[:partition]
81+
[:pause :kill :partition :clock]])
82+
83+
(def special-nemeses
84+
"A map of special nemesis names to collections of faults"
85+
{:none []
86+
:standard [:pause :kill :partition :clock :member]
87+
:all [:pause :kill :partition :clock :member]})
88+
89+
(defn parse-nemesis-spec
90+
"Takes a comma-separated nemesis string and returns a collection of keyword
91+
faults."
92+
[spec]
93+
(->> (str/split spec #",")
94+
(map keyword)
95+
(mapcat #(get special-nemeses % [%]))))
96+
6797
(def cli-opts
6898
"Options for test runners."
6999
[["-v" "--version VERSION"
@@ -73,13 +103,22 @@
73103
:parse-fn keyword
74104
:missing (str "--workload " (cli/one-of workloads))
75105
:validate [workloads (cli/one-of workloads)]]
106+
[nil "--nemesis FAULTS" "A comma-separated list of nemesis faults to enable"
107+
:parse-fn parse-nemesis-spec
108+
:validate [(partial every? (into nemeses (keys special-nemeses)))
109+
(str "Faults must be one of " nemeses " or "
110+
(cli/one-of special-nemeses))]]
111+
[nil "--nemesis-interval SECONDS" "How long to wait between nemesis faults"
112+
:default 3
113+
:parse-fn read-string
114+
:validate [#(and (number? %) (pos? %)) "must be a positive number"]]
76115
["-e" "--engine NAME"
77116
"What Tarantool data engine should we use?"
78117
:default "memtx"]])
79118

80119
(def crash-pattern
81120
"An egrep pattern we use to find crashes in the Tarantool logs."
82-
"Segmentation fault|too long WAL write|F>")
121+
"Segmentation fault|too long WAL write|F>|ER_TUPLE_FOUND")
83122

84123
(defn logged-crashes
85124
"Takes a test, and returns a map of nodes to strings from their Tarantool logs
@@ -112,7 +151,15 @@
112151
(defn tarantool-test
113152
[opts]
114153
(let [workload ((get workloads (:workload opts)) opts)
115-
nemesis nemesis/noop
154+
nemesis (nemesis/nemesis-package
155+
{:db db/db
156+
:nodes (:nodes opts)
157+
:faults (:nemesis opts)
158+
:partition {:targets [:primaries]}
159+
:pause {:targets [nil :one :primaries :majority :all]}
160+
:kill {:targets [nil :one :primaries :majority :all]}
161+
:interval (:nemesis-interval opts)})
162+
_ (info (pr-str nemesis))
116163
gen (->> (:generator workload)
117164
(gen/nemesis (:generator nemesis))
118165
(gen/time-limit (:time-limit opts)))
@@ -126,25 +173,38 @@
126173
(merge tests/noop-test
127174
opts
128175
{:client (:client workload)
129-
:nemesis nemesis
176+
:nemesis (:nemesis nemesis)
130177
:name (str "tarantool-" (:version opts))
131178
:os ubuntu/os
132179
:db (db/db (:version opts))
133180
:engine (:engine opts)
134181
:pure-generators true
135182
:generator gen
136-
:checker (checker/compose {:perf (checker/perf)
183+
:checker (checker/compose {:perf (checker/perf {:nemeses (:perf nemesis)})
137184
:clock-skew (checker/clock-plot)
138185
:crash (crash-checker)
139186
:timeline (timeline/html)
140187
:stats (checker/stats)
141188
:exceptions (checker/unhandled-exceptions)
142189
:workload (:checker workload)})})))
143190

191+
(defn all-tests
192+
"Takes parsed CLI options and constructs a sequence of test options, by
193+
combining all workloads and nemeses."
194+
[opts]
195+
(let [nemeses (if-let [n (:nemesis opts)] [n] standard-nemeses)
196+
workloads (if-let [w (:workload opts)] [w] standard-workloads)
197+
counts (range (:test-count opts))]
198+
(->> (for [i counts, n nemeses, w workloads]
199+
(assoc opts :nemesis n :workload w))
200+
(map tarantool-test))))
201+
144202
(defn -main
145203
"Handles command line arguments."
146204
[& args]
147205
(cli/run! (merge (cli/single-test-cmd {:test-fn tarantool-test
148206
:opt-spec cli-opts})
207+
(cli/test-all-cmd {:test-fn all-tests
208+
:opt-spec cli-opts})
149209
(cli/serve-cmd))
150210
args))

src/tarantool/sets.clj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
[checker :as checker]
77
[generator :as gen]
88
[independent :as independent]]
9+
[clojure.tools.logging :refer [info warn]]
910
[next.jdbc :as j]
1011
[next.jdbc.sql :as sql]
1112
[tarantool.client :as cl]
@@ -37,8 +38,11 @@
3738
(cl/with-error-handling op
3839
(cl/with-txn-aborts op
3940
(case (:f op)
40-
:add (do (sql/insert! conn table-name {:value v})
41-
(assoc op :type :ok))
41+
:add (let [con (cl/open (jepsen/primary test) test)]
42+
(info (jepsen/primary test))
43+
;(do (sql/insert! con table-name {:value v})
44+
(do (j/execute! con [(str "INSERT INTO " table-name "(value) VALUES (" v ")")])
45+
(assoc op :type :ok)))
4246

4347
:read (->> (sql/query conn [(str "SELECT * FROM " table-name)])
4448
(mapv :VALUE)

0 commit comments

Comments
 (0)