mirror of
https://github.com/kopia/kopia.git
synced 2026-01-16 10:27:50 -05:00
* test(providers): added capacity limits to blobtesting.mapStorage * refactor(general): added mutex map which dynamically allocates and releases named mutexes * refactor(repository): refactored cache cleanup and limit enforcement * refactor(repository): plumb through cache size limits in the repository * feat(cli): added CLI options to set cache size limits * unified flag setting and field naming * Update cli/command_cache_set.go Co-authored-by: Shikhar Mall <mall.shikhar.in@gmail.com> * pr feedback --------- Co-authored-by: Shikhar Mall <mall.shikhar.in@gmail.com>
96 lines
1.7 KiB
Go
96 lines
1.7 KiB
Go
package cache
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// manages a map of RWMutexes indexed by string keys
|
|
// mutexes are allocated on demand and released when no longer needed.
|
|
type mutexMap struct {
|
|
mu sync.Mutex
|
|
|
|
// +checklocks:mu
|
|
entries map[string]*mutexMapEntry
|
|
}
|
|
|
|
type mutexMapEntry struct {
|
|
mut *sync.RWMutex
|
|
refCount int
|
|
}
|
|
|
|
// +checklocksignore.
|
|
func (m *mutexMap) exclusiveLock(key string) {
|
|
m.getMutexAndAddRef(key).Lock()
|
|
}
|
|
|
|
func (m *mutexMap) tryExclusiveLock(key string) bool {
|
|
if !m.getMutexAndAddRef(key).TryLock() { // +checklocksignore
|
|
m.getMutexAndReleaseRef(key)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *mutexMap) exclusiveUnlock(key string) {
|
|
m.getMutexAndReleaseRef(key).Unlock() // +checklocksignore
|
|
}
|
|
|
|
// +checklocksignore.
|
|
func (m *mutexMap) sharedLock(key string) {
|
|
m.getMutexAndAddRef(key).RLock()
|
|
}
|
|
|
|
func (m *mutexMap) trySharedLock(key string) bool {
|
|
if !m.getMutexAndAddRef(key).TryRLock() { // +checklocksignore
|
|
m.getMutexAndReleaseRef(key)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *mutexMap) sharedUnlock(key string) {
|
|
m.getMutexAndReleaseRef(key).RUnlock() // +checklocksignore
|
|
}
|
|
|
|
func (m *mutexMap) getMutexAndAddRef(key string) *sync.RWMutex {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
ent := m.entries[key]
|
|
if ent == nil {
|
|
if m.entries == nil {
|
|
m.entries = make(map[string]*mutexMapEntry)
|
|
}
|
|
|
|
ent = &mutexMapEntry{
|
|
mut: &sync.RWMutex{},
|
|
}
|
|
|
|
m.entries[key] = ent
|
|
}
|
|
|
|
ent.refCount++
|
|
|
|
return ent.mut
|
|
}
|
|
|
|
func (m *mutexMap) getMutexAndReleaseRef(key string) *sync.RWMutex {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.entries == nil {
|
|
panic("attempted to call unlock without a lock")
|
|
}
|
|
|
|
ent := m.entries[key]
|
|
ent.refCount--
|
|
|
|
if ent.refCount == 0 {
|
|
delete(m.entries, key)
|
|
}
|
|
|
|
return ent.mut
|
|
}
|