Skip to content

Commit

Permalink
Fix bug with handling of zero-duration operations
Browse files Browse the repository at this point in the history
The code that handled conversion from `[]Operation` to `[]entry` sorted
operations by time, but it didn't properly handle the case where there
were multiple operations with zero duration (call timestamp equal to
return timestamp) and the same timestamp, which can happen if the clock
is not fine-grained enough. For a subset of entries where the timestamp
is the same, the call entries need to be ordered before the return
entries.
  • Loading branch information
anishathalye committed Apr 13, 2021
1 parent 0dc2d9b commit 012101c
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
7 changes: 6 additions & 1 deletion checker.go
Expand Up @@ -37,7 +37,12 @@ func (a byTime) Swap(i, j int) {
}

func (a byTime) Less(i, j int) bool {
return a[i].time < a[j].time
if a[i].time != a[j].time {
return a[i].time < a[j].time
}
// if the timestamps are the same, we need to make sure we order calls
// before returns
return a[i].kind == callEntry && a[j].kind == returnEntry
}

func makeEntries(history []Operation) []entry {
Expand Down
26 changes: 26 additions & 0 deletions porcupine_test.go
Expand Up @@ -98,6 +98,32 @@ func TestRegisterModel(t *testing.T) {
}
}

func TestZeroDuration(t *testing.T) {
ops := []Operation{
{0, registerInput{false, 100}, 0, 0, 100},
{1, registerInput{true, 0}, 25, 100, 75},
{2, registerInput{true, 0}, 30, 0, 30},
{3, registerInput{true, 0}, 30, 0, 30},
}
res, info := CheckOperationsVerbose(registerModel, ops, 0)
if res != Ok {
t.Fatal("expected operations to be linearizable")
}

visualizeTempFile(t, registerModel, info)

ops = []Operation{
{0, registerInput{false, 200}, 0, 0, 100},
{1, registerInput{true, 0}, 10, 200, 10},
{2, registerInput{true, 0}, 10, 200, 10},
{3, registerInput{true, 0}, 40, 0, 90},
}
res, _ = CheckOperationsVerbose(registerModel, ops, 0)
if res != Illegal {
t.Fatal("expected operations to not be linearizable")
}
}

type etcdInput struct {
op uint8 // 0 => read, 1 => write, 2 => cas
arg1 int // used for write, or for CAS from argument
Expand Down

0 comments on commit 012101c

Please sign in to comment.