Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var BasicOpsTemplateMap = map[string]string{
"GetSetDelete": `
db:db1 new-transaction => tx:tx1
tx:tx1 delete key:0 => error:nil|ErrNotExist
tx:tx1 get key:0 => error:ErrNotExist
tx:tx1 set key:0 value:zero
tx:tx1 get key:0 => value:zero
tx:tx1 delete key:0
tx:tx1 get key:0 => error:ErrNotExist
tx:tx1 commit
`,
"ScanKeys": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 scan => it:it1
it:it1 fetch next:false
it:it1 fetch next:true
it:it1 fetch next:true
it:it1 fetch next:true => error:EOF
tx:tx1 rollback
`,
"AscendDescendScanEmpty": `
db:db1 new-transaction => tx:tx1
tx:tx1 ascend begin: end: => it:it1
it:it1 fetch next:true => key: value: error:EOF
it:it1 fetch next:false => key: value: error:EOF
it:it1 fetch next:true => key: value: error:EOF
tx:tx1 descend begin: end: => it:it2
it:it2 fetch next:true => key: value: error:EOF
it:it2 fetch next:false => key: value: error:EOF
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 scan => it:it3
it:it3 fetch next:true => key: value: error:EOF
it:it3 fetch next:false => key: value: error:EOF
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 commit
`,
"AscendDescendInvalid": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 ascend begin:2 end:1 => error:ErrInvalid
tx:tx1 descend begin:2 end:1 => error:ErrInvalid
tx:tx1 ascend begin:2 end:0 => error:ErrInvalid
tx:tx1 descend begin:2 end:0 => error:ErrInvalid
tx:tx1 ascend begin:1 end:0 => error:ErrInvalid
tx:tx1 descend begin:1 end:0 => error:ErrInvalid
tx:tx1 rollback
`,
"AscendEmpty": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 ascend begin:0 end:0 => it:it1
it:it1 fetch next:true => key: value: error:EOF
it:it1 fetch next:false => key: value: error:EOF
tx:tx1 ascend begin:1 end:1 => it:it2
it:it2 fetch next:false => key: value: error:EOF
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:2 end:2 => it:it3
it:it3 fetch next:true => key: value: error:EOF
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
"DescendEmpty": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 descend begin:0 end:0 => it:it1
it:it1 fetch next:false => key: value: error:EOF
it:it1 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:1 end:1 => it:it2
it:it2 fetch next:false => key: value: error:EOF
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:2 end:2 => it:it3
it:it3 fetch next:false => key: value: error:EOF
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
"AscendNonEmptyRange": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 set key:3 value:three
tx:tx1 set key:4 value:four
tx:tx1 ascend begin:0 end:5 => it:it1
it:it1 fetch next:false => key:0 value:zero
it:it1 fetch next:true => key:1 value:one
it:it1 fetch next:true => key:2 value:two
it:it1 fetch next:true => key:3 value:three
it:it1 fetch next:true => key:4 value:four
it:it1 fetch next:true => key: value: error:EOF
it:it1 fetch next:false => key: value: error:EOF
tx:tx1 ascend begin:0 end:4 => it:it2
it:it2 fetch next:false => key:0 value:zero
it:it2 fetch next:true => key:1 value:one
it:it2 fetch next:true => key:2 value:two
it:it2 fetch next:true => key:3 value:three
it:it2 fetch next:true => key: value: error:EOF
it:it2 fetch next:false => key: value: error:EOF
tx:tx1 ascend begin:0 end:1 => it:it3
it:it3 fetch next:false => key:0 value:zero
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:1 end:2 => it:it4
it:it4 fetch next:false => key:1 value:one
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:2 end:25 => it:it5
it:it5 fetch next:false => key:2 value:two
it:it5 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:25 end:35 => it:it6
it:it6 fetch next:false => key:3 value:three
it:it6 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
"DescendNonEmptyRange": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 set key:3 value:three
tx:tx1 set key:4 value:four
tx:tx1 descend begin:0 end:5 => it:it1
it:it1 fetch next:false => key:4 value:four
it:it1 fetch next:true => key:3 value:three
it:it1 fetch next:true => key:2 value:two
it:it1 fetch next:true => key:1 value:one
it:it1 fetch next:true => key:0 value:zero
it:it1 fetch next:true => key: value: error:EOF
it:it1 fetch next:false => key: value: error:EOF
tx:tx1 descend begin:0 end:4 => it:it2
it:it2 fetch next:false => key:3 value:three
it:it2 fetch next:true => key:2 value:two
it:it2 fetch next:true => key:1 value:one
it:it2 fetch next:true => key:0 value:zero
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:0 end:1 => it:it3
it:it3 fetch next:false => key:0 value:zero
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:1 end:2 => it:it4
it:it4 fetch next:false => key:1 value:one
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:2 end:25 => it:it5
it:it5 fetch next:false => key:2 value:two
it:it5 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:25 end:35 => it:it6
it:it6 fetch next:false => key:3 value:three
it:it6 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
"AscendOneEmptyRange": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 set key:3 value:three
tx:tx1 set key:4 value:four
tx:tx1 ascend begin: end:5 => it:it1
it:it1 fetch next:false => key:0 value:zero
it:it1 fetch next:true => key:1 value:one
it:it1 fetch next:true => key:2 value:two
it:it1 fetch next:true => key:3 value:three
it:it1 fetch next:true => key:4 value:four
it:it1 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin: end:4 => it:it2
it:it2 fetch next:false => key:0 value:zero
it:it2 fetch next:true => key:1 value:one
it:it2 fetch next:true => key:2 value:two
it:it2 fetch next:true => key:3 value:three
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin: end:2 => it:it3
it:it3 fetch next:false => key:0 value:zero
it:it3 fetch next:true => key:1 value:one
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:0 end: => it:it4
it:it4 fetch next:false => key:0 value:zero
it:it4 fetch next:true => key:1 value:one
it:it4 fetch next:true => key:2 value:two
it:it4 fetch next:true => key:3 value:three
it:it4 fetch next:true => key:4 value:four
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 ascend begin:2 end: => it:it4
it:it4 fetch next:false => key:2 value:two
it:it4 fetch next:true => key:3 value:three
it:it4 fetch next:true => key:4 value:four
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
"DescendOneEmptyRange": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 set key:1 value:one
tx:tx1 set key:2 value:two
tx:tx1 set key:3 value:three
tx:tx1 set key:4 value:four
tx:tx1 descend begin: end:5 => it:it1
it:it1 fetch next:false => key:4 value:four
it:it1 fetch next:true => key:3 value:three
it:it1 fetch next:true => key:2 value:two
it:it1 fetch next:true => key:1 value:one
it:it1 fetch next:true => key:0 value:zero
it:it1 fetch next:true => key: value: error:EOF
tx:tx1 descend begin: end:4 => it:it2
it:it2 fetch next:false => key:3 value:three
it:it2 fetch next:true => key:2 value:two
it:it2 fetch next:true => key:1 value:one
it:it2 fetch next:true => key:0 value:zero
it:it2 fetch next:true => key: value: error:EOF
tx:tx1 descend begin: end:2 => it:it3
it:it3 fetch next:false => key:1 value:one
it:it3 fetch next:true => key:0 value:zero
it:it3 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:0 end: => it:it4
it:it4 fetch next:false => key:4 value:four
it:it4 fetch next:true => key:3 value:three
it:it4 fetch next:true => key:2 value:two
it:it4 fetch next:true => key:1 value:one
it:it4 fetch next:true => key:0 value:zero
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 descend begin:2 end: => it:it4
it:it4 fetch next:false => key:4 value:four
it:it4 fetch next:true => key:3 value:three
it:it4 fetch next:true => key:2 value:two
it:it4 fetch next:true => key: value: error:EOF
tx:tx1 rollback
`,
}
View Source
var TxOpsTemplateMap = map[string]string{
"SerializedTxCommits": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 commit
db:db1 new-transaction => tx:tx2
tx:tx2 get key:0 => value:zero
tx:tx2 set key:0 value:ZERO
tx:tx2 commit
db:db1 new-transaction => tx:tx3
tx:tx3 get key:0 => value:ZERO
tx:tx3 delete key:0
tx:tx3 commit
db:db1 new-transaction => tx:tx4
tx:tx4 get key:0 => error:ErrNotExist
tx:tx4 commit
`,
"SerializedTxCommitsAndRollbacks": `
db:db1 new-transaction => tx:tx1
tx:tx1 set key:0 value:zero
tx:tx1 commit
db:db1 new-transaction => tx:tx2
tx:tx2 get key:0 => value:zero
tx:tx2 set key:0 value:ZERO
tx:tx2 rollback
db:db1 new-transaction => tx:tx3
tx:tx3 get key:0 => value:zero
tx:tx3 delete key:0
tx:tx3 rollback
db:db1 new-transaction => tx:tx4
tx:tx4 get key:0 => value:zero
tx:tx4 delete key:0
tx:tx4 commit
db:db1 new-transaction => tx:tx5
tx:tx5 get key:0 => error:ErrNotExist
tx:tx5 set key:0 value:ZERO
tx:tx5 commit
db:db1 new-transaction => tx:tx6
tx:tx6 get key:0 => value:ZERO
tx:tx6 commit
`,
"NonConflictingTxes": `
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
db:db1 new-transaction => tx:tx3
tx:tx1 set key:1 value:one
tx:tx2 set key:2 value:two
tx:tx3 set key:3 value:three
tx:tx1 commit
tx:tx2 commit
tx:tx3 commit
`,
"ConflictingReadOnlyTxes": `
db:db1 new-transaction => tx:init
tx:init set key:0 value:zero
tx:init commit
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
db:db1 new-transaction => tx:tx3
tx:tx1 get key:0 => value:zero
tx:tx2 get key:0 => value:zero
tx:tx3 get key:0 => value:zero
tx:tx1 commit
tx:tx2 commit
tx:tx3 commit
`,
"SerializableConflictingReadWriteTxes": `
db:db1 new-transaction => tx:init
tx:init set key:0 value:zero
tx:init commit
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
tx:tx1 set key:0 value:ZERO
tx:tx2 get key:0 => value:zero
tx:tx1 commit
tx:tx2 commit => error:nil|non-nil
`,
"SerializableConflictingDeletes": `
db:db1 new-transaction => tx:init
tx:init set key:0 value:zero
tx:init commit
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
tx:tx1 delete key:0
tx:tx1 set key:1 value:one
tx:tx2 delete key:0
tx:tx2 set key:2 value:two
tx:tx1 commit
tx:tx2 commit => error:nil|non-nil
`,
"NonConflictingDeletes": `
db:db1 new-transaction => tx:init
tx:init set key:1 value:one
tx:init set key:2 value:two
tx:init commit
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
tx:tx1 delete key:1
tx:tx2 delete key:2
tx:tx1 commit
tx:tx2 commit
`,
"AbortedReads": `
db:db1 new-transaction => tx:init
tx:init set key:key value:value
tx:init commit
db:db1 new-transaction => tx:tx1
tx:tx1 set key:key value:VALUE
tx:tx1 rollback
db:db1 new-transaction => tx:tx2
tx:tx2 get key:key => value:value
tx:tx2 commit
`,
"RepeatedReads": `
db:db1 new-transaction => tx:init
tx:init set key:key value:value
tx:init commit
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
tx:tx1 set key:key value:VALUE
tx:tx1 commit
tx:tx2 get key:key => value:value
tx:tx2 commit => error:nil|non-nil
db:db1 new-transaction => tx:tx3
tx:tx3 get key:key => value:VALUE
tx:tx3 commit
`,
"WriteSkewAnamoly": `
db:db1 new-transaction => tx:init
tx:init set key:account1 value:100
tx:init set key:account2 value:100
tx:init commit
# Invariant: Balances of account1 and account2 can go -ve, but their sum must
# never go below -$100.
db:db1 new-transaction => tx:tx1
db:db1 new-transaction => tx:tx2
# tx1 checks that sum is $200, so withdraws $200 from "account1" thinking
# remaining balance is still above -$100. tx2 does the same, but withdraws
# $200 from "account2" instead.
tx:tx1 get key:account1 => value:100
tx:tx1 get key:account2 => value:100
tx:tx1 set key:account1 value:-100
tx:tx1 commit
tx:tx2 get key:account1 => value:100
tx:tx2 get key:account2 => value:100
tx:tx2 set key:account2 value:-100
tx:tx2 commit => error:non-nil
`,
}
Functions ¶
Types ¶
type BankTest ¶
type BankTest struct { DB kv.Database // InitializeDB when true clears the database and initializes it with random // accounts. InitializeDB bool // contains filtered or unexported fields }
BankTest uses multiple goroutines to perform transactions simultaneously while verifying that expected invariant holds true at every snapshot. This test runs till input context is canceled or verification check has failed.
Multiple goroutines randomly transfer amounts between the accounts in parallel. The goroutine that is running the tests will take repeated snapshots of the database and verifies that sum of balances across all accounts doesn't change over time.
func (*BankTest) FindTotalBalance ¶
func (*BankTest) Run ¶
Run executes the test with nclient goroutines performing database transactions simultaneously.
func (*BankTest) TotalBalance ¶
Click to show internal directories.
Click to hide internal directories.