Skip to content

Commit

Permalink
tidb: port bank-multitable test (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
cwen0 committed Mar 31, 2019
1 parent a6e7c16 commit bd684d2
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 56 deletions.
146 changes: 110 additions & 36 deletions tidb/src/tidb/bank.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
(:refer-clojure :exclude [test])
(:require [clojure.string :as str]
[jepsen
[client :as client]
[generator :as gen]
[checker :as checker]
]
[client :as client]
[generator :as gen]
[checker :as checker]]
[knossos.op :as op]
[clojure.core.reducers :as r]
[clojure.java.jdbc :as j]
[tidb.sql :refer :all]
[tidb.basic :as basic]
)
)
[clojure.tools.logging :refer :all]))

(defrecord BankClient [node n starting-balance lock-type in-place?]
client/Client
Expand Down Expand Up @@ -40,14 +38,14 @@
(let [{:keys [from to amount]} (:value op)
b1 (-> c
(j/query [(str "select * from accounts where id = ?" lock-type) from]
:row-fn :balance)
:row-fn :balance)
first
(- amount))
b2 (-> c
(j/query [(str "select * from accounts where id = ?"
lock-type)
to]
:row-fn :balance)
:row-fn :balance)
first
(+ amount))]
(cond (neg? b1)
Expand All @@ -63,8 +61,7 @@
(j/update! c :accounts {:balance b2} ["id = ?" to])
(assoc op :type :ok)))))))))

(teardown! [_ test])
)
(teardown! [_ test]))

(defn bank-client
"Simulates bank account transfers between n accounts, each starting with
Expand Down Expand Up @@ -102,18 +99,18 @@
(r/filter op/ok?)
(r/filter #(= :read (:f %)))
(r/map (fn [op]
(let [balances (:value op)]
(cond (not= (:n model) (count balances))
{:type :wrong-n
:expected (:n model)
:found (count balances)
:op op}
(not= (:total model)
(reduce + balances))
{:type :wrong-total
:expected (:total model)
:found (reduce + balances)
:op op}))))
(let [balances (:value op)]
(cond (not= (:n model) (count balances))
{:type :wrong-n
:expected (:n model)
:found (count balances)
:op op}
(not= (:total model)
(reduce + balances))
{:type :wrong-total
:expected (:total model)
:found (reduce + balances)
:op op}))))
(r/filter identity)
(into []))]
{:valid? (empty? bad-reads)
Expand All @@ -122,21 +119,98 @@
(defn bank-test-base
[opts]
(basic/basic-test
(merge
{:client {:client (:client opts)
:during (->> (gen/mix [bank-read bank-diff-transfer])
(gen/clients)
(gen/stagger 0))
:final (gen/clients (gen/once bank-read))}
:checker (checker/compose
{:perf (checker/perf)
:details (bank-checker)})}
(dissoc opts :client))))
(merge
{:client {:client (:client opts)
:during (->> (gen/mix [bank-read bank-diff-transfer])
(gen/clients)
(gen/stagger 0))
:final (gen/clients (gen/once bank-read))}
:checker (checker/compose
{:perf (checker/perf)
:details (bank-checker)})}
(dissoc opts :client))))

(defn test
[opts]
(bank-test-base
(merge {:name "bank"
:model {:n 5 :total 50}
:client (bank-client 5 10 " FOR UPDATE" false)}
opts)))
(merge {:name "bank"
:model {:n 5 :total 50}
:client (bank-client 5 10 " FOR UPDATE" false)}
opts)))

; One bank account per table
(defrecord MultiBankClient [node tbl-created? n starting-balance lock-type in-place?]
client/Client
(setup! [this test node]
(locking tbl-created?
(when (compare-and-set! tbl-created? false true)
(j/with-db-connection [c (conn-spec (first (:nodes test)))]
(dotimes [i n]
(Thread/sleep 500)
(info "Creating table accounts" i)
(j/execute! c [(str "create table if not exists accounts" i
"(id int not null primary key,"
"balance bigint not null)")])
(Thread/sleep 500)
(try
(Thread/sleep 500)
(info "Populating account" i)
(with-txn-retries
(j/insert! c (str "accounts" i) {:id 0, :balance starting-balance}))
(catch java.sql.SQLIntegrityConstraintViolationException e nil))))))

(assoc this :node node))

(invoke! [this test op]
(with-txn op [c (first (:nodes test))]
(try
(case (:f op)
:read
(->> (range n)
(mapv (fn [x]
(->> (j/query
c [(str "select balance from accounts" x)]
:row-fn :balance)
first)))
(assoc op :type :ok, :value))
:transfer
(let [{:keys [from to amount]} (:value op)
from (str "accounts" from)
to (str "accounts" to)
b1 (-> c
(j/query
[(str "select balance from " from lock-type)]
:row-fn :balance)
first
(- amount))
b2 (-> c
(j/query [(str "select balance from " to lock-type)]
:row-fn :balance)
first
(+ amount))]
(cond (neg? b1)
(assoc op :type :fail, :error [:negative from b1])
(neg? b2)
(assoc op :type :fail, :error [:negative to b2])
true
(if in-place?
(do (j/execute! c [(str "update " from " set balance = balance - ? where id = 0") amount])
(j/execute! c [(str "update " to " set balance = balance + ? where id = 0") amount])
(assoc op :type :ok))
(do (j/update! c from {:balance b1} ["id = 0"])
(j/update! c to {:balance b2} ["id = 0"])
(assoc op :type :ok)))))))))

(teardown! [_ test]))

(defn multitable-bank-client
[n starting-balance lock-type in-place?]
(MultiBankClient. nil (atom false) n starting-balance lock-type in-place?))

(defn multitable-test
[opts]
(bank-test-base
(merge {:name "bank-multitable"
:model {:n 5 :total 50}
:client (multitable-bank-client 5 10 " FOR UPDATE" false)}
opts)))
28 changes: 9 additions & 19 deletions tidb/src/tidb/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,31 @@
[tidb.nemesis :as nemesis]
[tidb.bank :as bank]
[tidb.sets :as sets]
[tidb.register :as register]
)
)
[tidb.register :as register]))

(def tests
"A map of test names to test constructors."
{"bank" bank/test
"sets" sets/test
"register" register/test
}
)
{"bank" bank/test
"bank-multitable" bank/multitable-test
"sets" sets/test
"register" register/test})

(def oses
"Supported operating systems"
{"debian" debian/os
"none" os/noop
}
)
"none" os/noop})

(def nemeses
"Supported nemeses"
{"none" `(nemesis/none)
"parts" `(nemesis/parts)
"majority-ring" `(nemesis/majring)
"start-stop-2" `(nemesis/startstop 2)
"start-kill-2" `(nemesis/startkill 2)
}
)
"start-kill-2" `(nemesis/startkill 2)})

(def opt-spec
"Command line options for tools.cli"
[
(jc/repeated-opt nil "--nemesis NAME" "Which nemeses to use"
[(jc/repeated-opt nil "--nemesis NAME" "Which nemeses to use"
[`(nemesis/none)]
nemeses)

Expand All @@ -65,9 +57,7 @@
:parse-fn #(Long/parseLong %)
:validate [pos? "Must be positive"]]

(jc/tarball-opt "http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz")
]
)
(jc/tarball-opt "http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz")])

(defn log-test
[t]
Expand Down
2 changes: 1 addition & 1 deletion tidb/src/tidb/sql.clj
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@
`(timeout 5000 (assoc ~op :type :info, :value :timed-out)
(with-error-handling ~op
(with-txn-retries
(j/with-db-transaction [~c (conn-spec ~node) :isolation :serializable]
(j/with-db-transaction [~c (conn-spec ~node)]
(j/execute! ~c ["start transaction with consistent snapshot"])
~@body)))))

0 comments on commit bd684d2

Please sign in to comment.