exclusive_pool.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // Copyright 2015 - Present, The Gogs Authors. All rights reserved.
  2. // Copyright 2018 - Present, Gitote. All rights reserved.
  3. //
  4. // This source code is licensed under the MIT license found in the
  5. // LICENSE file in the root directory of this source tree.
  6. package sync
  7. import (
  8. "sync"
  9. )
  10. // ExclusivePool is a pool of non-identical instances
  11. // that only one instance with same identity is in the pool at a time.
  12. // In other words, only instances with different identities can be in
  13. // the pool the same time. If another instance with same identity tries
  14. // to get into the pool, it hangs until previous instance left the pool.
  15. //
  16. // This pool is particularly useful for performing tasks on same resource
  17. // on the file system in different goroutines.
  18. type ExclusivePool struct {
  19. lock sync.Mutex
  20. // pool maintains locks for each instance in the pool.
  21. pool map[string]*sync.Mutex
  22. // count maintains the number of times an instance with same identity checks in
  23. // to the pool, and should be reduced to 0 (removed from map) by checking out
  24. // with same number of times.
  25. // The purpose of count is to delete lock when count down to 0 and recycle memory
  26. // from map object.
  27. count map[string]int
  28. }
  29. // NewExclusivePool initializes and returns a new ExclusivePool object.
  30. func NewExclusivePool() *ExclusivePool {
  31. return &ExclusivePool{
  32. pool: make(map[string]*sync.Mutex),
  33. count: make(map[string]int),
  34. }
  35. }
  36. // CheckIn checks in an instance to the pool and hangs while instance
  37. // with same indentity is using the lock.
  38. func (p *ExclusivePool) CheckIn(identity string) {
  39. p.lock.Lock()
  40. lock, has := p.pool[identity]
  41. if !has {
  42. lock = &sync.Mutex{}
  43. p.pool[identity] = lock
  44. }
  45. p.count[identity]++
  46. p.lock.Unlock()
  47. lock.Lock()
  48. }
  49. // CheckOut checks out an instance from the pool and releases the lock
  50. // to let other instances with same identity to grab the lock.
  51. func (p *ExclusivePool) CheckOut(identity string) {
  52. p.lock.Lock()
  53. defer p.lock.Unlock()
  54. p.pool[identity].Unlock()
  55. if p.count[identity] == 1 {
  56. delete(p.pool, identity)
  57. delete(p.count, identity)
  58. } else {
  59. p.count[identity]--
  60. }
  61. }