lockman_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package lockman
  15. import (
  16. "context"
  17. "fmt"
  18. "sync"
  19. "testing"
  20. "time"
  21. "yunion.io/x/pkg/util/stringutils"
  22. )
  23. type FakeObject struct {
  24. Id string
  25. playerId int
  26. playerIdCount int
  27. }
  28. func (o *FakeObject) GetId() string {
  29. return o.Id
  30. }
  31. func (o *FakeObject) Keyword() string {
  32. return "fake"
  33. }
  34. func (o *FakeObject) push(playerId int) {
  35. if o.playerId >= 0 {
  36. if o.playerId != playerId {
  37. panic(fmt.Sprintf("obj locked by %d, locked again by %d", o.playerId, playerId))
  38. }
  39. } else {
  40. if o.playerIdCount != 0 {
  41. panic(fmt.Sprintf("obj unlocked but player id count %d", o.playerIdCount))
  42. }
  43. o.playerId = playerId
  44. }
  45. o.playerIdCount += 1
  46. }
  47. func (o *FakeObject) pop(playerId int) {
  48. if o.playerId != playerId {
  49. panic(fmt.Sprintf("obj previously locked by %d, now unlocked by %d", o.playerId, playerId))
  50. }
  51. o.playerIdCount -= 1
  52. if o.playerIdCount < 0 {
  53. panic("obj overly unlocked")
  54. } else if o.playerIdCount == 0 {
  55. o.playerId = -1
  56. }
  57. }
  58. func newSharedObject() *FakeObject {
  59. obj := &FakeObject{
  60. Id: stringutils.UUID4(),
  61. playerId: -1,
  62. playerIdCount: 0,
  63. }
  64. return obj
  65. }
  66. type testLockManagerConfig struct {
  67. players int
  68. cycles int
  69. shared *FakeObject
  70. lockman ILockManager
  71. }
  72. func testLockManager(t *testing.T, cfg *testLockManagerConfig) {
  73. players := cfg.players
  74. cycles := cfg.cycles
  75. shared := cfg.shared
  76. lockman := cfg.lockman
  77. bug = func(fmtStr string, fmtArgs ...interface{}) {
  78. t.Fatalf(fmtStr, fmtArgs...)
  79. }
  80. run := func(ctx context.Context, id int, cycle int, sleep time.Duration) {
  81. key := getObjectKey(shared)
  82. indents := []string{" ", " "}
  83. logpref := fmt.Sprintf("%p: %02d: %p", lockman, id, ctx)
  84. func() {
  85. fmt.Printf("%s: %s >acquire\n", logpref, indents[0])
  86. lockman.LockKey(ctx, key)
  87. shared.push(id)
  88. fmt.Printf("%s: %s >>acquired\n", logpref, indents[1])
  89. }()
  90. defer func() {
  91. fmt.Printf("%s: %s <<release\n", logpref, indents[1])
  92. shared.pop(id)
  93. lockman.UnlockKey(ctx, key)
  94. fmt.Printf("%s: %s <released\n", logpref, indents[0])
  95. }()
  96. time.Sleep(sleep)
  97. }
  98. var wg sync.WaitGroup
  99. for id := 0; id < players; id += 1 {
  100. wg.Add(1)
  101. go func(localId int) {
  102. ctx := context.WithValue(context.Background(), "ID", localId)
  103. for i := 0; i < cycles; i += 1 {
  104. run(ctx, localId, i, time.Duration(localId)*time.Second)
  105. }
  106. wg.Done()
  107. }(id)
  108. }
  109. wg.Wait()
  110. }