{"id":17791115,"url":"https://github.com/will62794/snapshot-isolation-spec","last_synced_at":"2026-01-12T06:45:44.132Z","repository":{"id":83147443,"uuid":"122022788","full_name":"will62794/snapshot-isolation-spec","owner":"will62794","description":"A formal specification of snapshot isolation.","archived":false,"fork":false,"pushed_at":"2024-11-21T02:19:02.000Z","size":80,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-07T16:44:54.036Z","etag":null,"topics":["formal-methods","tlaplus"],"latest_commit_sha":null,"homepage":"","language":"TLA","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/will62794.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-02-19T05:28:52.000Z","updated_at":"2024-11-21T02:19:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"15bde0d5-fec5-4e61-94ae-717c9c0ea09f","html_url":"https://github.com/will62794/snapshot-isolation-spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will62794%2Fsnapshot-isolation-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will62794%2Fsnapshot-isolation-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will62794%2Fsnapshot-isolation-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will62794%2Fsnapshot-isolation-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/will62794","download_url":"https://codeload.github.com/will62794/snapshot-isolation-spec/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246741182,"owners_count":20826063,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["formal-methods","tlaplus"],"created_at":"2024-10-27T10:49:39.232Z","updated_at":"2026-01-12T06:45:44.117Z","avatar_url":"https://github.com/will62794.png","language":"TLA","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Specification of Snapshot Isolation in TLA+\n\nThis is a TLA+ specification that can be used for exploring and understanding snapshot isolation. I wrote it partly as a personal exercise and partly as an attempt to share the ideas and semantics of snapshot isolation with other engineers in a precise manner. My goal was to make this spec as simple as possible without removing necessary details. I wanted to focus more on high level concepts than on how a particular system might actually implement snapshot isolation. The comments explain in more detail the structure of the model and the various correctness properties. I drew some inspiration (and a few of the more tricky definitions) from Chris Newcombe's specification of snapshot isolation, which is a bit more complex than mine. He presented a few of his specs in a \"Debugging Designs\" talk at a [HPTS conference in 2011](http://hpts.ws/papers/2011/agenda.html). His two snapshot isolation specs are very thorough and well documented.\n\n## Checking Properties with TLC\n\nThere a few properties already defined in the specification that you can try to verify yourself. Two concurrency anomalies that snapshot isolation allows, Write Skew and a [\"read only\" transaction anomaly](https://www.cs.umb.edu/~poneil/ROAnom.pdf) are included with examples, and there is a `ReadOnlyAnomaly` property that can be checked using TLC. The main invariant to check is that every history is serializable (which is expected to be violated by anomalous histories). To get started with a TLC model, you can use the following values for spec's `CONSTANT` parameters:\n\n\tEmpty   \u003c- Model value\n\ttxnIds \t\u003c- {t0, t1, t2}\t    (Symmetry set of model values)\n\tkeys \t\u003c- {k1, k2}         (Symmetry set of model values)\n\tvalues \t\u003c- {v1, v2}         (Symmetry set of model values)\n\nYou can choose `Spec` as the temporal formula and set either of the following two expressions as invariants to check:\n\n*Assert that all histories are serializable:*\n\n```tla\n IsSerializable(txnHistory)\n ```\n\n*Assert that there are no non-serializable histories with a read-only transaction anomaly:*\n\n```tla\n ~ReadOnlyAnomaly(txnHistory)\n ```\n\nBoth of these invariants should be violated in specific cases. By running the model checker you can see what kinds of histories violate these invariants.\n\n## Model Checking Statistics\n\nFor reference, I was able to produce a trace that violated the `~ReadOnlyAnomaly(txnHistory)` invariant in 1 hour and 4 minutes running TLC on a 12-core (Intel i7-4930K CPU @ 3.40GHz) Ubuntu Linux workstation. It generated a bit over 405 million distinct states and it took a 12 step trace to violate the invariant. While TLC was running it seemed to produce at least ~80GB of auxiliary data on disk, but I did not measure it precisely. You can see the detailed output of this run below:\n\nTLC command line parameters:\n```\n% java tlc2.TLC -cleanup -gzip -workers 12 -metadir /hdd/tlc_states -config MC.cfg MC.tla\n\nTLC2 Version 2.12 of 29 January 2018\nRunning breadth-first search Model-Checking with 12 workers on 12 cores with 7143MB heap and 64MB offheap memory (Linux 4.8.0-59-generic amd64, Oracle Corporation 1.8.0_131 x86_6\n4).\n```\n\nTLC invariant violation output (only last state of trace shown):\n\n```\nState 12: \u003cNext line 288, col 12 to line 290, col 36 of module SnapshotIsolation\u003e\n/\\ txnSnapshots = ( t0 :\u003e (k1 :\u003e Empty @@ k2 :\u003e v1) @@\n  t1 :\u003e (k1 :\u003e v1 @@ k2 :\u003e Empty) @@\n  t2 :\u003e (k1 :\u003e v1 @@ k2 :\u003e Empty) )\n/\\ dataStore = (k1 :\u003e v1 @@ k2 :\u003e v1)\n/\\ txnHistory = \u003c\u003c [type |-\u003e \"begin\", txnId |-\u003e t0, time |-\u003e 1],\n                   [type |-\u003e \"read\", txnId |-\u003e t0, key |-\u003e k1, val |-\u003e Empty],\n                   [type |-\u003e \"begin\", txnId |-\u003e t1, time |-\u003e 2],\n                   [type |-\u003e \"write\", txnId |-\u003e t1, key |-\u003e k1, val |-\u003e v1],\n                   [type |-\u003e \"commit\", txnId |-\u003e t1, time |-\u003e 3, updatedKeys |-\u003e {k1}],\n                   [type |-\u003e \"begin\", txnId |-\u003e t2, time |-\u003e 4],\n                   [type |-\u003e \"read\", txnId |-\u003e t2, key |-\u003e k1, val |-\u003e v1],\n                   [type |-\u003e \"read\", txnId |-\u003e t2, key |-\u003e k2, val |-\u003e Empty],\n                   [type |-\u003e \"write\", txnId |-\u003e t0, key |-\u003e k2, val |-\u003e v1],\n                   [type |-\u003e \"commit\", txnId |-\u003e t0, time |-\u003e 5, updatedKeys |-\u003e {k2}],\n                   [type |-\u003e \"commit\", txnId |-\u003e t2, time |-\u003e 6, updatedKeys |-\u003e {}] \u003e\u003e\n/\\ clock = 6\n/\\ runningTxns = {}\n\n529068865 states generated, 405673796 distinct states found, 357574338 states left on queue.\nThe depth of the complete state graph search is 13.\nThe average outdegree of the complete state graph is 8 (minimum is 0, the maximum 17 and the 95th percentile is 12).\nFinished in 01h 04min at (2018-02-21 23:41:43)\n```\n\nInterestingly, running TLC in simulation mode (using the `-simulate` flag) produces a violating trace in just under 3 minutes, on the same hardware. This speedup may be due to the fact that, to produce this particular anomaly, a sufficiently long trace is required. Searching the state space in a breadth first manner (TLC's default) would require the checking of all possible \"short\" traces before testing out any longer ones. In fact, running TLC simulation in parallel, with 12 cores, often produced a violating trace in under a minute. It seems that simulation mode may be better at finding \"interesting\" traces more quickly than standard model checking model, at least for this particular model.\n\n```\n  % java tlc2.TLC -simulate -cleanup -gzip -workers 12 -metadir /hdd/tlc_states -config MC.cfg MC.tla                                                                      !10179\nTLC2 Version 2.12 of 29 January 2018\nRunning Random Simulation with seed 6802238540282724400 with 12 workers on 12 cores with 7143MB heap and 64MB offheap memory (Linux 4.8.0-59-generic amd64, Oracle Corporation 1.8\n.0_131 x86_64).\n\n...\n\n\nState 13:\n/\\ txnSnapshots = ( t0 :\u003e (k1 :\u003e Empty @@ k2 :\u003e v2) @@\n  t1 :\u003e (k1 :\u003e v2 @@ k2 :\u003e Empty) @@\n  t2 :\u003e (k1 :\u003e v2 @@ k2 :\u003e Empty) )\n/\\ dataStore = (k1 :\u003e v2 @@ k2 :\u003e v2)\n/\\ txnHistory = \u003c\u003c [type |-\u003e \"begin\", txnId |-\u003e t0, time |-\u003e 1],\n   [type |-\u003e \"begin\", txnId |-\u003e t1, time |-\u003e 2],\n   [type |-\u003e \"read\", txnId |-\u003e t0, key |-\u003e k1, val |-\u003e Empty],\n   [type |-\u003e \"write\", txnId |-\u003e t1, key |-\u003e k1, val |-\u003e v2],\n   [type |-\u003e \"commit\", txnId |-\u003e t1, time |-\u003e 3, updatedKeys |-\u003e {k1}],\n   [type |-\u003e \"begin\", txnId |-\u003e t2, time |-\u003e 4],\n   [type |-\u003e \"read\", txnId |-\u003e t0, key |-\u003e k2, val |-\u003e Empty],\n   [type |-\u003e \"read\", txnId |-\u003e t2, key |-\u003e k1, val |-\u003e v2],\n   [type |-\u003e \"read\", txnId |-\u003e t2, key |-\u003e k2, val |-\u003e Empty],\n   [type |-\u003e \"write\", txnId |-\u003e t0, key |-\u003e k2, val |-\u003e v2],\n   [type |-\u003e \"commit\", txnId |-\u003e t2, time |-\u003e 5, updatedKeys |-\u003e {}],\n   [type |-\u003e \"commit\", txnId |-\u003e t0, time |-\u003e 6, updatedKeys |-\u003e {k2}] \u003e\u003e\n/\\ clock = 6\n/\\ runningTxns = {}\n\nThe number of states generated: 3489180\nSimulation using seed 6802238540282724400 and aril 4642022\nProgress: 3489180 states checked.\nFinished in 02min 42s at (2018-02-24 11:38:10)\n```\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill62794%2Fsnapshot-isolation-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwill62794%2Fsnapshot-isolation-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill62794%2Fsnapshot-isolation-spec/lists"}