code.gitea.io/gitea@v1.19.3/modules/sync/exclusive_pool.go (about) 1 // Copyright 2016 The Gogs Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package sync 5 6 import ( 7 "sync" 8 ) 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 21 // pool maintains locks for each instance in the pool. 22 pool map[string]*sync.Mutex 23 24 // count maintains the number of times an instance with same identity checks in 25 // to the pool, and should be reduced to 0 (removed from map) by checking out 26 // with same number of times. 27 // The purpose of count is to delete lock when count down to 0 and recycle memory 28 // from map object. 29 count map[string]int 30 } 31 32 // NewExclusivePool initializes and returns a new ExclusivePool object. 33 func NewExclusivePool() *ExclusivePool { 34 return &ExclusivePool{ 35 pool: make(map[string]*sync.Mutex), 36 count: make(map[string]int), 37 } 38 } 39 40 // CheckIn checks in an instance to the pool and hangs while instance 41 // with same identity is using the lock. 42 func (p *ExclusivePool) CheckIn(identity string) { 43 p.lock.Lock() 44 45 lock, has := p.pool[identity] 46 if !has { 47 lock = &sync.Mutex{} 48 p.pool[identity] = lock 49 } 50 p.count[identity]++ 51 52 p.lock.Unlock() 53 lock.Lock() 54 } 55 56 // CheckOut checks out an instance from the pool and releases the lock 57 // to let other instances with same identity to grab the lock. 58 func (p *ExclusivePool) CheckOut(identity string) { 59 p.lock.Lock() 60 defer p.lock.Unlock() 61 62 p.pool[identity].Unlock() 63 if p.count[identity] == 1 { 64 delete(p.pool, identity) 65 delete(p.count, identity) 66 } else { 67 p.count[identity]-- 68 } 69 }