Files
core/io/fs/mem_storage.go
2024-10-14 10:51:35 +02:00

296 lines
5.5 KiB
Go

package fs
import (
"sync"
"github.com/datarhei/core/v16/mem"
"github.com/dolthub/swiss"
"github.com/puzpuzpuz/xsync/v3"
)
type memStorage interface {
// Delete deletes a file from the storage.
Delete(key string) (file *memFile, ok bool)
// Store stores a file to the storage. If there's already a file with
// the same key, that value will be returned and replaced with the
// new file.
Store(key string, file *memFile) (oldfile *memFile, ok bool)
// Load loads a file from the storage. This is a references to the file,
// i.e. all changes to the file will be reflected on the storage.
Load(key string) (file *memFile, ok bool)
// LoadAndCopy loads a file from the storage. This is a copy of file
// metadata and content.
LoadAndCopy(key string) (file *memFile, ok bool)
// Has checks whether a file exists at path.
Has(key string) bool
// Range ranges over all files on the storage. The callback needs to return
// false in order to stop the iteration.
Range(f func(key string, file *memFile) bool)
}
type mapOfStorage struct {
lock *xsync.RBMutex
files *xsync.MapOf[string, *memFile]
}
func newMapOfStorage() memStorage {
m := &mapOfStorage{
lock: xsync.NewRBMutex(),
files: xsync.NewMapOf[string, *memFile](),
}
return m
}
func (m *mapOfStorage) Delete(key string) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
return m.files.LoadAndDelete(key)
}
func (m *mapOfStorage) Store(key string, value *memFile) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
return m.files.LoadAndStore(key, value)
}
func (m *mapOfStorage) Load(key string) (*memFile, bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
return m.files.Load(key)
}
func (m *mapOfStorage) LoadAndCopy(key string) (*memFile, bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
file, ok := m.files.Load(key)
if !ok {
return nil, false
}
newFile := &memFile{
memFileInfo: memFileInfo{
name: file.name,
size: file.size,
dir: file.dir,
lastMod: file.lastMod,
linkTo: file.linkTo,
},
data: nil,
r: nil,
}
if file.data != nil {
newFile.data = mem.Get()
file.data.WriteTo(newFile.data)
}
return newFile, true
}
func (m *mapOfStorage) Has(key string) bool {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
_, ok := m.files.Load(key)
return ok
}
func (m *mapOfStorage) Range(f func(key string, value *memFile) bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
m.files.Range(f)
}
type mapStorage struct {
lock sync.RWMutex
files map[string]*memFile
}
func newMapStorage() memStorage {
m := &mapStorage{
files: map[string]*memFile{},
}
return m
}
func (m *mapStorage) Delete(key string) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
v, ok := m.files[key]
delete(m.files, key)
return v, ok
}
func (m *mapStorage) Store(key string, value *memFile) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
v, ok := m.files[key]
m.files[key] = value
return v, ok
}
func (m *mapStorage) Load(key string) (*memFile, bool) {
m.lock.RLock()
defer m.lock.RUnlock()
v, ok := m.files[key]
return v, ok
}
func (m *mapStorage) LoadAndCopy(key string) (*memFile, bool) {
m.lock.RLock()
defer m.lock.RUnlock()
v, ok := m.files[key]
if !ok {
return nil, false
}
newFile := &memFile{
memFileInfo: memFileInfo{
name: v.name,
size: v.size,
dir: v.dir,
lastMod: v.lastMod,
linkTo: v.linkTo,
},
data: nil,
r: nil,
}
if v.data != nil {
newFile.data = mem.Get()
v.data.WriteTo(newFile.data)
}
return newFile, true
}
func (m *mapStorage) Has(key string) bool {
m.lock.RLock()
defer m.lock.RUnlock()
_, ok := m.files[key]
return ok
}
func (m *mapStorage) Range(f func(key string, value *memFile) bool) {
m.lock.RLock()
defer m.lock.RUnlock()
for k, v := range m.files {
if !f(k, v) {
break
}
}
}
type swissMapStorage struct {
lock *xsync.RBMutex
files *swiss.Map[string, *memFile]
}
func newSwissMapStorage() memStorage {
m := &swissMapStorage{
lock: xsync.NewRBMutex(),
files: swiss.NewMap[string, *memFile](128),
}
return m
}
func (m *swissMapStorage) Delete(key string) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
file, hasFile := m.files.Get(key)
if !hasFile {
return nil, false
}
m.files.Delete(key)
return file, true
}
func (m *swissMapStorage) Store(key string, value *memFile) (*memFile, bool) {
m.lock.Lock()
defer m.lock.Unlock()
file, hasFile := m.files.Get(key)
m.files.Put(key, value)
return file, hasFile
}
func (m *swissMapStorage) Load(key string) (*memFile, bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
return m.files.Get(key)
}
func (m *swissMapStorage) LoadAndCopy(key string) (*memFile, bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
file, ok := m.files.Get(key)
if !ok {
return nil, false
}
newFile := &memFile{
memFileInfo: memFileInfo{
name: file.name,
size: file.size,
dir: file.dir,
lastMod: file.lastMod,
linkTo: file.linkTo,
},
data: nil,
r: nil,
}
if file.data != nil {
newFile.data = mem.Get()
file.data.WriteTo(newFile.data)
}
return newFile, true
}
func (m *swissMapStorage) Has(key string) bool {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
return m.files.Has(key)
}
func (m *swissMapStorage) Range(f func(key string, value *memFile) bool) {
token := m.lock.RLock()
defer m.lock.RUnlock(token)
m.files.Iter(func(key string, value *memFile) bool {
return !f(key, value)
})
}