Files
sqlite3/sqlite3vfs/memory.go

278 lines
5.4 KiB
Go
Raw Normal View History

2023-05-26 04:59:54 +01:00
package sqlite3vfs
import (
"io"
2023-05-26 11:04:48 +01:00
"runtime"
2023-05-26 04:59:54 +01:00
"sync"
2023-05-26 11:04:48 +01:00
"time"
2023-05-26 04:59:54 +01:00
)
// A MemoryVFS is a [VFS] for memory databases.
type MemoryVFS map[string]*MemoryDB
var _ VFS = MemoryVFS{}
// Open implements the [VFS] interface.
func (vfs MemoryVFS) Open(name string, flags OpenFlag) (File, OpenFlag, error) {
if flags&OPEN_MAIN_DB == 0 {
return nil, flags, _CANTOPEN
}
if db, ok := vfs[name]; ok {
return &memoryFile{
MemoryDB: db,
readOnly: flags&OPEN_READONLY != 0,
}, flags, nil
}
return nil, flags, _CANTOPEN
}
// Delete implements the [VFS] interface.
func (vfs MemoryVFS) Delete(name string, dirSync bool) error {
return _IOERR_DELETE
}
// Access implements the [VFS] interface.
func (vfs MemoryVFS) Access(name string, flag AccessFlag) (bool, error) {
return false, nil
}
// FullPathname implements the [VFS] interface.
func (vfs MemoryVFS) FullPathname(name string) (string, error) {
return name, nil
}
const memSectorSize = 65536
2023-05-29 16:50:48 +01:00
// A MemoryDB is a [MemoryVFS] database.
//
// A MemoryDB is safe to access concurrently from multiple SQLite connections.
2023-05-26 04:59:54 +01:00
type MemoryDB struct {
2023-05-26 11:04:48 +01:00
mtx sync.RWMutex
2023-05-26 04:59:54 +01:00
size int64
data []*[memSectorSize]byte
2023-05-26 11:04:48 +01:00
locker sync.Mutex
pending *memoryFile
reserved *memoryFile
shared int
2023-05-26 04:59:54 +01:00
}
type memoryFile struct {
*MemoryDB
2023-05-26 11:04:48 +01:00
lock LockLevel
2023-05-26 04:59:54 +01:00
readOnly bool
}
2023-05-29 16:50:48 +01:00
// Close implements the [File] and [io.Closer] interfaces.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) Close() error {
return m.Unlock(LOCK_NONE)
}
2023-05-29 16:50:48 +01:00
// ReadAt implements the [File] and [io.ReaderAt] interfaces.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) ReadAt(b []byte, off int64) (n int, err error) {
2023-05-26 11:04:48 +01:00
m.mtx.RLock()
defer m.mtx.RUnlock()
2023-05-26 04:59:54 +01:00
if off >= m.size {
return 0, io.EOF
}
2023-05-29 16:50:48 +01:00
2023-05-26 04:59:54 +01:00
base := off / memSectorSize
rest := off % memSectorSize
have := int64(memSectorSize)
if base == int64(len(m.data))-1 {
2023-05-29 16:50:48 +01:00
have = modRoundUp(m.size, memSectorSize)
}
n = copy(b, (*m.data[base])[rest:have])
if n < len(b) {
// Assume reads are page aligned.
return 0, io.ErrNoProgress
2023-05-26 04:59:54 +01:00
}
2023-05-29 16:50:48 +01:00
return n, nil
2023-05-26 04:59:54 +01:00
}
2023-05-29 16:50:48 +01:00
// WriteAt implements the [File] and [io.WriterAt] interfaces.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) WriteAt(b []byte, off int64) (n int, err error) {
2023-05-26 11:04:48 +01:00
m.mtx.Lock()
defer m.mtx.Unlock()
2023-05-26 04:59:54 +01:00
base := off / memSectorSize
rest := off % memSectorSize
2023-05-29 16:50:48 +01:00
for base >= int64(len(m.data)) {
2023-05-26 04:59:54 +01:00
m.data = append(m.data, new([memSectorSize]byte))
}
n = copy((*m.data[base])[rest:], b)
2023-05-29 16:50:48 +01:00
if n < len(b) {
// Assume writes are page aligned.
return 0, io.ErrShortWrite
2023-05-26 04:59:54 +01:00
}
return n, nil
}
2023-05-29 16:50:48 +01:00
// Truncate implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) Truncate(size int64) error {
2023-05-26 11:04:48 +01:00
m.mtx.Lock()
defer m.mtx.Unlock()
return m.truncate(size)
}
func (m *memoryFile) truncate(size int64) error {
2023-05-26 04:59:54 +01:00
if size < m.size {
base := size / memSectorSize
rest := size % memSectorSize
2023-05-29 16:50:48 +01:00
if rest != 0 {
clear((*m.data[base])[rest:])
}
2023-05-26 04:59:54 +01:00
}
2023-05-29 16:50:48 +01:00
sectors := divRoundUp(size, memSectorSize)
2023-05-26 04:59:54 +01:00
for sectors > int64(len(m.data)) {
m.data = append(m.data, new([memSectorSize]byte))
}
2023-05-29 16:50:48 +01:00
clear(m.data[sectors:])
m.data = m.data[:sectors]
2023-05-26 04:59:54 +01:00
m.size = size
return nil
}
2023-05-29 16:50:48 +01:00
// Sync implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (*memoryFile) Sync(flag SyncFlag) error {
return nil
}
2023-05-29 16:50:48 +01:00
// Size implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) Size() (int64, error) {
2023-05-26 11:04:48 +01:00
m.mtx.RLock()
defer m.mtx.RUnlock()
2023-05-26 04:59:54 +01:00
return m.size, nil
}
2023-05-29 16:50:48 +01:00
// Lock implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) Lock(lock LockLevel) error {
2023-05-26 11:04:48 +01:00
if m.lock >= lock {
return nil
}
2023-05-26 04:59:54 +01:00
if m.readOnly && lock >= LOCK_RESERVED {
return _IOERR_LOCK
}
2023-05-26 11:04:48 +01:00
m.locker.Lock()
defer m.locker.Unlock()
deadline := time.Now().Add(time.Millisecond)
switch lock {
case LOCK_SHARED:
for m.pending != nil {
if time.Now().After(deadline) {
return _BUSY
}
m.locker.Unlock()
runtime.Gosched()
m.locker.Lock()
}
m.shared++
case LOCK_RESERVED:
if m.reserved != nil {
return _BUSY
}
m.reserved = m
case LOCK_EXCLUSIVE:
if m.lock < LOCK_PENDING {
if m.pending != nil {
return _BUSY
}
m.lock = LOCK_PENDING
m.pending = m
}
for m.shared > 1 {
if time.Now().After(deadline) {
return _BUSY
}
m.locker.Unlock()
runtime.Gosched()
m.locker.Lock()
}
}
m.lock = lock
return nil
2023-05-26 04:59:54 +01:00
}
2023-05-29 16:50:48 +01:00
// Unlock implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) Unlock(lock LockLevel) error {
2023-05-26 11:04:48 +01:00
if m.lock <= lock {
return nil
}
m.locker.Lock()
defer m.locker.Unlock()
if m.pending == m {
m.pending = nil
}
if m.reserved == m {
m.reserved = nil
}
if lock < LOCK_SHARED {
m.shared--
2023-05-26 04:59:54 +01:00
}
2023-05-26 11:04:48 +01:00
m.lock = lock
2023-05-26 04:59:54 +01:00
return nil
}
2023-05-29 16:50:48 +01:00
// CheckReservedLock implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) CheckReservedLock() (bool, error) {
2023-05-26 11:04:48 +01:00
if m.lock >= LOCK_RESERVED {
2023-05-26 04:59:54 +01:00
return true, nil
}
2023-05-26 11:04:48 +01:00
m.locker.Lock()
defer m.locker.Unlock()
return m.reserved != nil, nil
2023-05-26 04:59:54 +01:00
}
2023-05-29 16:50:48 +01:00
// SectorSize implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (*memoryFile) SectorSize() int {
return memSectorSize
}
2023-05-29 16:50:48 +01:00
// DeviceCharacteristics implements the [File] interface.
2023-05-26 04:59:54 +01:00
func (*memoryFile) DeviceCharacteristics() DeviceCharacteristic {
return IOCAP_ATOMIC |
IOCAP_SEQUENTIAL |
IOCAP_SAFE_APPEND |
IOCAP_POWERSAFE_OVERWRITE
}
2023-05-29 16:50:48 +01:00
// SizeHint implements the [FileSizeHint] interface.
2023-05-26 04:59:54 +01:00
func (m *memoryFile) SizeHint(size int64) error {
2023-05-26 11:04:48 +01:00
m.mtx.Lock()
defer m.mtx.Unlock()
2023-05-26 04:59:54 +01:00
if size > m.size {
2023-05-26 11:04:48 +01:00
return m.truncate(size)
2023-05-26 04:59:54 +01:00
}
return nil
}
2023-05-29 16:50:48 +01:00
// LockState implements the [FileLockState] interface.
2023-05-26 11:04:48 +01:00
func (m *memoryFile) LockState() LockLevel {
return m.lock
}
2023-05-29 16:50:48 +01:00
func divRoundUp(a, b int64) int64 {
return (a + b - 1) / b
}
func modRoundUp(a, b int64) int64 {
return b - (b-a%b)%b
}
func clear[T any](b []T) {
var zero T
2023-05-26 04:59:54 +01:00
for i := range b {
2023-05-29 16:50:48 +01:00
b[i] = zero
2023-05-26 04:59:54 +01:00
}
}