Dmitrii Stepanov
7456c8556a
All checks were successful
DCO action / DCO (pull_request) Successful in 1m33s
Vulncheck / Vulncheck (pull_request) Successful in 2m43s
Build / Build Components (1.20) (pull_request) Successful in 3m40s
Tests and linters / Staticcheck (pull_request) Successful in 3m59s
Tests and linters / Tests (1.20) (pull_request) Successful in 5m44s
Tests and linters / Tests (1.21) (pull_request) Successful in 6m3s
Tests and linters / Tests with -race (pull_request) Successful in 6m28s
Build / Build Components (1.21) (pull_request) Successful in 12m34s
Tests and linters / Lint (pull_request) Successful in 12m51s
Signed-off-by: Dmitrii Stepanov <d.stepanov@yadro.com>
103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
package blobovniczatree
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
|
|
utilSync "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/sync"
|
|
"github.com/hashicorp/golang-lru/v2/simplelru"
|
|
)
|
|
|
|
// dbCache caches sharedDB instances that are NOT open for Put.
|
|
//
|
|
// Uses dbManager for opening/closing sharedDB instances.
|
|
// Stores a reference to an cached sharedDB, so dbManager does not close it.
|
|
type dbCache struct {
|
|
cacheGuard *sync.RWMutex
|
|
cache simplelru.LRUCache[string, *sharedDB]
|
|
pathLock *utilSync.KeyLocker[string]
|
|
closed bool
|
|
|
|
dbManager *dbManager
|
|
}
|
|
|
|
func newDBCache(size int, dbManager *dbManager) *dbCache {
|
|
cache, err := simplelru.NewLRU[string, *sharedDB](size, func(_ string, evictedDB *sharedDB) {
|
|
evictedDB.Close()
|
|
})
|
|
if err != nil {
|
|
// occurs only if the size is not positive
|
|
panic(fmt.Errorf("could not create LRU cache of size %d: %w", size, err))
|
|
}
|
|
return &dbCache{
|
|
cacheGuard: &sync.RWMutex{},
|
|
cache: cache,
|
|
dbManager: dbManager,
|
|
pathLock: utilSync.NewKeyLocker[string](),
|
|
}
|
|
}
|
|
|
|
func (c *dbCache) Open() {
|
|
c.cacheGuard.Lock()
|
|
defer c.cacheGuard.Unlock()
|
|
|
|
c.closed = false
|
|
}
|
|
|
|
func (c *dbCache) Close() {
|
|
c.cacheGuard.Lock()
|
|
defer c.cacheGuard.Unlock()
|
|
c.cache.Purge()
|
|
c.closed = true
|
|
}
|
|
|
|
func (c *dbCache) GetOrCreate(path string) *sharedDB {
|
|
value := c.getExisted(path)
|
|
if value != nil {
|
|
return value
|
|
}
|
|
return c.create(path)
|
|
}
|
|
|
|
func (c *dbCache) getExisted(path string) *sharedDB {
|
|
c.cacheGuard.Lock()
|
|
defer c.cacheGuard.Unlock()
|
|
|
|
if value, ok := c.cache.Get(path); ok {
|
|
return value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *dbCache) create(path string) *sharedDB {
|
|
c.pathLock.Lock(path)
|
|
defer c.pathLock.Unlock(path)
|
|
|
|
value := c.getExisted(path)
|
|
if value != nil {
|
|
return value
|
|
}
|
|
|
|
value = c.dbManager.GetByPath(path)
|
|
|
|
_, err := value.Open() //open db to hold reference, closed by evictedDB.Close() or if cache closed
|
|
if err != nil {
|
|
return value
|
|
}
|
|
if added := c.put(path, value); !added {
|
|
value.Close()
|
|
}
|
|
return value
|
|
}
|
|
|
|
func (c *dbCache) put(path string, db *sharedDB) bool {
|
|
c.cacheGuard.Lock()
|
|
defer c.cacheGuard.Unlock()
|
|
|
|
if !c.closed {
|
|
c.cache.Add(path, db)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|