even without nemesis, s3 get/put/delete is not linearizable (is this normal?)

This commit is contained in:
Alex Auvolat 2023-04-18 17:47:53 +02:00
parent 70c1d3db46
commit dc5245ce65
3 changed files with 64 additions and 37 deletions

View file

@ -1,22 +1,32 @@
# jepsen.garage # jepsen.garage
A Clojure library designed to ... well, that part is up to you. Jepsen checking of Garage consistency properties.
## Usage ## Usage
FIXME Requirements:
- vagrant
- VirtualBox, configured so that nodes can take an IP in a private network `192.168.56.0/24`
- a user that can create VirtualBox VMs
- leiningen
- gnuplot
Set up VMs:
```
vagrant up
```
Run tests:
```
lein run test --nodes-file nodes.vagrant
```
## License ## License
Copyright © 2023 FIXME Copyright © 2023 Alex Auvolat
This program and the accompanying materials are made available under the This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at terms of the GNU General Public License v3.0.
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the Eclipse
Public License, v. 2.0 are satisfied: GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or (at your
option) any later version, with the GNU Classpath Exception which is available
at https://www.gnu.org/software/classpath/license.html.

View file

@ -1,7 +1,8 @@
{ pkgs ? import <nixpkgs> {} }: { pkgs ? import <nixpkgs> {} }:
pkgs.mkShell { pkgs.mkShell {
nativeBuildInputs = [ nativeBuildInputs = with pkgs; [
pkgs.leiningen leiningen
pkgs.vagrant vagrant
gnuplot
]; ];
} }

View file

@ -1,14 +1,18 @@
(ns jepsen.garage (ns jepsen.garage
(:require [clojure.tools.logging :refer :all] (:require [clojure.tools.logging :refer :all]
[clojure.string :as str] [clojure.string :as str]
[jepsen [cli :as cli] [jepsen [checker :as checker]
[cli :as cli]
[client :as client] [client :as client]
[control :as c] [control :as c]
[db :as db] [db :as db]
[generator :as gen] [generator :as gen]
[nemesis :as nemesis]
[tests :as tests]] [tests :as tests]]
[jepsen.checker.timeline :as timeline]
[jepsen.control.util :as cu] [jepsen.control.util :as cu]
[jepsen.os.debian :as debian] [jepsen.os.debian :as debian]
[knossos.model :as model]
[slingshot.slingshot :refer [try+]] [slingshot.slingshot :refer [try+]]
[amazonica.aws.s3 :as s3] [amazonica.aws.s3 :as s3]
[amazonica.aws.s3transfer :as s3transfer])) [amazonica.aws.s3transfer :as s3transfer]))
@ -82,9 +86,9 @@
(log-files [_ test node] (log-files [_ test node]
[logfile]))) [logfile])))
(defn op-get [_ _] {:type :invoke, :f :get-object, :value nil}) (defn op-get [_ _] {:type :invoke, :f :read, :value nil})
(defn op-put [_ _] {:type :invoke, :f :put-object, :value (str (rand-int 50))}) (defn op-put [_ _] {:type :invoke, :f :write, :value (str (rand-int 9))})
(defn op-del [_ _] {:type :invoke, :f :del-object, :value nil}) (defn op-del [_ _] {:type :invoke, :f :write, :value nil})
(defrecord Client [creds] (defrecord Client [creds]
client/Client client/Client
@ -102,7 +106,7 @@
(setup! [this test]) (setup! [this test])
(invoke! [this test op] (invoke! [this test op]
(case (:f op) (case (:f op)
:get-object (try+ :read (try+
(let [value (let [value
(-> (s3/get-object (:creds this) grg-bucket grg-object) (-> (s3/get-object (:creds this) grg-bucket grg-object)
:input-stream :input-stream
@ -110,21 +114,21 @@
(assoc op :type :ok, :value value)) (assoc op :type :ok, :value value))
(catch (re-find #"Key not found" (.getMessage %)) ex (catch (re-find #"Key not found" (.getMessage %)) ex
(assoc op :type :ok, :value nil))) (assoc op :type :ok, :value nil)))
:put-object :write
(let [some-bytes (.getBytes (:value op) "UTF-8") (if (= (:value op) nil)
bytes-stream (java.io.ByteArrayInputStream. some-bytes)] (do
(s3/put-object (:creds this) (s3/delete-object (:creds this)
:bucket-name grg-bucket :bucket-name grg-bucket
:key grg-object :key grg-object)
:input-stream bytes-stream (assoc op :type :ok, :value nil))
:metadata {:content-length (count some-bytes)}) (let [some-bytes (.getBytes (:value op) "UTF-8")
(assoc op :type :ok)) bytes-stream (java.io.ByteArrayInputStream. some-bytes)]
:del-object (s3/put-object (:creds this)
(do :bucket-name grg-bucket
(s3/delete-object (:creds this) :key grg-object
:bucket-name grg-bucket :input-stream bytes-stream
:key grg-object) :metadata {:content-length (count some-bytes)})
(assoc op :type :ok, :value nil)))) (assoc op :type :ok)))))
(teardown! [this test]) (teardown! [this test])
(close! [this test])) (close! [this test]))
@ -139,10 +143,22 @@
:os debian/os :os debian/os
:db (db "v0.8.2") :db (db "v0.8.2")
:client (Client. nil) :client (Client. nil)
:nemesis (nemesis/partition-random-halves)
:checker (checker/compose
{:perf (checker/perf)
:timeline (timeline/html)
:linear (checker/linearizable
{:model (model/register)
:algorithm :linear})})
:generator (->> (gen/mix [op-get op-put op-del]) :generator (->> (gen/mix [op-get op-put op-del])
(gen/stagger 1) (gen/stagger 0.02)
(gen/nemesis nil) (gen/nemesis nil)
(gen/time-limit 20))})) ; (gen/nemesis
; (cycle [(gen/sleep 5)
; {:type :info, :f :start}
; (gen/sleep 5)
; {:type :info, :f :stop}]))
(gen/time-limit (+ (:time-limit opts) 5)))}))
(defn -main (defn -main
"Handles command line arguments. Can either run a test, or a web server for "Handles command line arguments. Can either run a test, or a web server for