mirror of
https://github.com/datarhei/core.git
synced 2025-10-05 16:07:07 +08:00
296 lines
5.5 KiB
Go
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)
|
|
})
|
|
}
|