mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
VFS API refactor.
This commit is contained in:
@@ -6,12 +6,58 @@ import (
|
||||
"github.com/ncruces/go-sqlite3/vfs"
|
||||
)
|
||||
|
||||
// WrapSharedMemory helps wrap [vfs.FileSharedMemory].
|
||||
func WrapSharedMemory(f vfs.File) vfs.SharedMemory {
|
||||
if f, ok := f.(vfs.FileSharedMemory); ok {
|
||||
return f.SharedMemory()
|
||||
// UnwrapFile unwraps a [vfs.File],
|
||||
// possibly implementing [vfs.FileUnwrap],
|
||||
// to a concrete type.
|
||||
func UnwrapFile[T vfs.File](f vfs.File) (_ T, _ bool) {
|
||||
for {
|
||||
switch t := f.(type) {
|
||||
default:
|
||||
return
|
||||
case T:
|
||||
return t, true
|
||||
case vfs.FileUnwrap:
|
||||
f = t.Unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WrapLockState helps wrap [vfs.FileLockState].
|
||||
func WrapLockState(f vfs.File) vfs.LockLevel {
|
||||
if f, ok := f.(vfs.FileLockState); ok {
|
||||
return f.LockState()
|
||||
}
|
||||
return vfs.LOCK_EXCLUSIVE + 1 // UNKNOWN_LOCK
|
||||
}
|
||||
|
||||
// WrapPersistentWAL helps wrap [vfs.FilePersistentWAL].
|
||||
func WrapPersistentWAL(f vfs.File) bool {
|
||||
if f, ok := f.(vfs.FilePersistentWAL); ok {
|
||||
return f.PersistentWAL()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WrapSetPersistentWAL helps wrap [vfs.FilePersistentWAL].
|
||||
func WrapSetPersistentWAL(f vfs.File, keepWAL bool) {
|
||||
if f, ok := f.(vfs.FilePersistentWAL); ok {
|
||||
f.SetPersistentWAL(keepWAL)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapPowersafeOverwrite helps wrap [vfs.FilePowersafeOverwrite].
|
||||
func WrapPowersafeOverwrite(f vfs.File) bool {
|
||||
if f, ok := f.(vfs.FilePowersafeOverwrite); ok {
|
||||
return f.PowersafeOverwrite()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WrapSetPowersafeOverwrite helps wrap [vfs.FilePowersafeOverwrite].
|
||||
func WrapSetPowersafeOverwrite(f vfs.File, psow bool) {
|
||||
if f, ok := f.(vfs.FilePowersafeOverwrite); ok {
|
||||
f.SetPowersafeOverwrite(psow)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WrapChunkSize helps wrap [vfs.FileChunkSize].
|
||||
@@ -45,36 +91,6 @@ func WrapOverwrite(f vfs.File) error {
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
// WrapPersistentWAL helps wrap [vfs.FilePersistentWAL].
|
||||
func WrapPersistentWAL(f vfs.File) bool {
|
||||
if f, ok := f.(vfs.FilePersistentWAL); ok {
|
||||
return f.PersistentWAL()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WrapSetPersistentWAL helps wrap [vfs.FilePersistentWAL].
|
||||
func WrapSetPersistentWAL(f vfs.File, keepWAL bool) {
|
||||
if f, ok := f.(vfs.FilePersistentWAL); ok {
|
||||
f.SetPersistentWAL(keepWAL)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapPowersafeOverwrite helps wrap [vfs.FilePowersafeOverwrite].
|
||||
func WrapPowersafeOverwrite(f vfs.File) bool {
|
||||
if f, ok := f.(vfs.FilePowersafeOverwrite); ok {
|
||||
return f.PowersafeOverwrite()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WrapSetPowersafeOverwrite helps wrap [vfs.FilePowersafeOverwrite].
|
||||
func WrapSetPowersafeOverwrite(f vfs.File, psow bool) {
|
||||
if f, ok := f.(vfs.FilePowersafeOverwrite); ok {
|
||||
f.SetPowersafeOverwrite(psow)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCommitPhaseTwo helps wrap [vfs.FileCommitPhaseTwo].
|
||||
func WrapCommitPhaseTwo(f vfs.File) error {
|
||||
if f, ok := f.(vfs.FileCommitPhaseTwo); ok {
|
||||
@@ -107,20 +123,18 @@ func WrapRollbackAtomicWrite(f vfs.File) error {
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
// WrapCheckpointDone helps wrap [vfs.FileCheckpoint].
|
||||
func WrapCheckpointDone(f vfs.File) error {
|
||||
// WrapCheckpointStart helps wrap [vfs.FileCheckpoint].
|
||||
func WrapCheckpointStart(f vfs.File) {
|
||||
if f, ok := f.(vfs.FileCheckpoint); ok {
|
||||
return f.CheckpointDone()
|
||||
f.CheckpointStart()
|
||||
}
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
// WrapCheckpointStart helps wrap [vfs.FileCheckpoint].
|
||||
func WrapCheckpointStart(f vfs.File) error {
|
||||
// WrapCheckpointDone helps wrap [vfs.FileCheckpoint].
|
||||
func WrapCheckpointDone(f vfs.File) {
|
||||
if f, ok := f.(vfs.FileCheckpoint); ok {
|
||||
return f.CheckpointStart()
|
||||
f.CheckpointDone()
|
||||
}
|
||||
return sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
// WrapPragma helps wrap [vfs.FilePragma].
|
||||
@@ -130,3 +144,11 @@ func WrapPragma(f vfs.File, name, value string) (string, error) {
|
||||
}
|
||||
return "", sqlite3.NOTFOUND
|
||||
}
|
||||
|
||||
// WrapSharedMemory helps wrap [vfs.FileSharedMemory].
|
||||
func WrapSharedMemory(f vfs.File) vfs.SharedMemory {
|
||||
if f, ok := f.(vfs.FileSharedMemory); ok {
|
||||
return f.SharedMemory()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ func (h *hbshVFS) OpenFilename(name *vfs.Filename, flags vfs.OpenFlag) (file vfs
|
||||
}
|
||||
|
||||
var hbsh *hbsh.HBSH
|
||||
if f, ok := name.DatabaseFile().(*hbshFile); ok {
|
||||
if f, ok := vfsutil.UnwrapFile[*hbshFile](name.DatabaseFile()); ok {
|
||||
hbsh = f.hbsh
|
||||
} else {
|
||||
var key []byte
|
||||
@@ -71,6 +71,17 @@ const (
|
||||
blockSize = 4096
|
||||
)
|
||||
|
||||
// Ensure blockSize is a power of two.
|
||||
var _ [0]struct{} = [blockSize & (blockSize - 1)]struct{}{}
|
||||
|
||||
func roundDown(i int64) int64 {
|
||||
return i &^ (blockSize - 1)
|
||||
}
|
||||
|
||||
func roundUp[T int | int64](i T) T {
|
||||
return (i + (blockSize - 1)) &^ (blockSize - 1)
|
||||
}
|
||||
|
||||
type hbshFile struct {
|
||||
vfs.File
|
||||
init HBSHCreator
|
||||
@@ -111,8 +122,8 @@ func (h *hbshFile) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, sqlite3.CANTOPEN
|
||||
}
|
||||
|
||||
min := (off) &^ (blockSize - 1) // round down
|
||||
max := (off + int64(len(p)) + (blockSize - 1)) &^ (blockSize - 1) // round up
|
||||
min := roundDown(off)
|
||||
max := roundUp(off + int64(len(p)))
|
||||
|
||||
// Read one block at a time.
|
||||
for ; min < max; min += blockSize {
|
||||
@@ -141,8 +152,8 @@ func (h *hbshFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, sqlite3.READONLY
|
||||
}
|
||||
|
||||
min := (off) &^ (blockSize - 1) // round down
|
||||
max := (off + int64(len(p)) + (blockSize - 1)) &^ (blockSize - 1) // round up
|
||||
min := roundDown(off)
|
||||
max := roundUp(off + int64(len(p)))
|
||||
|
||||
// Write one block at a time.
|
||||
for ; min < max; min += blockSize {
|
||||
@@ -187,45 +198,44 @@ func (h *hbshFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (h *hbshFile) Truncate(size int64) error {
|
||||
size = (size + (blockSize - 1)) &^ (blockSize - 1) // round up
|
||||
return h.File.Truncate(size)
|
||||
func (h *hbshFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
|
||||
var _ [0]struct{} = [blockSize - 4096]struct{}{} // Ensure blockSize is 4K.
|
||||
return h.File.DeviceCharacteristics() & (0 |
|
||||
// The only safe flags are these:
|
||||
vfs.IOCAP_ATOMIC4K |
|
||||
vfs.IOCAP_UNDELETABLE_WHEN_OPEN |
|
||||
vfs.IOCAP_IMMUTABLE |
|
||||
vfs.IOCAP_BATCH_ATOMIC)
|
||||
}
|
||||
|
||||
func (h *hbshFile) SectorSize() int {
|
||||
return util.LCM(h.File.SectorSize(), blockSize)
|
||||
}
|
||||
|
||||
func (h *hbshFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
|
||||
return h.File.DeviceCharacteristics() & (0 |
|
||||
// The only safe flags are these:
|
||||
vfs.IOCAP_UNDELETABLE_WHEN_OPEN |
|
||||
vfs.IOCAP_IMMUTABLE |
|
||||
vfs.IOCAP_BATCH_ATOMIC)
|
||||
func (h *hbshFile) Truncate(size int64) error {
|
||||
return h.File.Truncate(roundUp(size))
|
||||
}
|
||||
|
||||
// Wrap optional methods.
|
||||
func (h *hbshFile) ChunkSize(size int) {
|
||||
vfsutil.WrapChunkSize(h.File, roundUp(size))
|
||||
}
|
||||
|
||||
func (h *hbshFile) SizeHint(size int64) error {
|
||||
return vfsutil.WrapSizeHint(h.File, roundUp(size))
|
||||
}
|
||||
|
||||
func (h *hbshFile) Unwrap() vfs.File {
|
||||
return h.File
|
||||
}
|
||||
|
||||
func (h *hbshFile) SharedMemory() vfs.SharedMemory {
|
||||
return vfsutil.WrapSharedMemory(h.File)
|
||||
}
|
||||
|
||||
func (h *hbshFile) ChunkSize(size int) {
|
||||
size = (size + (blockSize - 1)) &^ (blockSize - 1) // round up
|
||||
vfsutil.WrapChunkSize(h.File, size)
|
||||
}
|
||||
// Wrap optional methods.
|
||||
|
||||
func (h *hbshFile) SizeHint(size int64) error {
|
||||
size = (size + (blockSize - 1)) &^ (blockSize - 1) // round up
|
||||
return vfsutil.WrapSizeHint(h.File, size)
|
||||
}
|
||||
|
||||
func (h *hbshFile) HasMoved() (bool, error) {
|
||||
return vfsutil.WrapHasMoved(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) Overwrite() error {
|
||||
return vfsutil.WrapOverwrite(h.File) // notest
|
||||
func (h *hbshFile) LockState() vfs.LockLevel {
|
||||
return vfsutil.WrapLockState(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) PersistentWAL() bool {
|
||||
@@ -236,6 +246,14 @@ func (h *hbshFile) SetPersistentWAL(keepWAL bool) {
|
||||
vfsutil.WrapSetPersistentWAL(h.File, keepWAL) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) HasMoved() (bool, error) {
|
||||
return vfsutil.WrapHasMoved(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) Overwrite() error {
|
||||
return vfsutil.WrapOverwrite(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) CommitPhaseTwo() error {
|
||||
return vfsutil.WrapCommitPhaseTwo(h.File) // notest
|
||||
}
|
||||
@@ -252,10 +270,10 @@ func (h *hbshFile) RollbackAtomicWrite() error {
|
||||
return vfsutil.WrapRollbackAtomicWrite(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) CheckpointDone() error {
|
||||
return vfsutil.WrapCheckpointDone(h.File) // notest
|
||||
func (h *hbshFile) CheckpointStart() {
|
||||
vfsutil.WrapCheckpointStart(h.File) // notest
|
||||
}
|
||||
|
||||
func (h *hbshFile) CheckpointStart() error {
|
||||
return vfsutil.WrapCheckpointStart(h.File) // notest
|
||||
func (h *hbshFile) CheckpointDone() {
|
||||
vfsutil.WrapCheckpointDone(h.File) // notest
|
||||
}
|
||||
|
||||
69
vfs/api.go
69
vfs/api.go
@@ -49,6 +49,13 @@ type File interface {
|
||||
DeviceCharacteristics() DeviceCharacteristic
|
||||
}
|
||||
|
||||
// FileUnwrap should be implemented by a File
|
||||
// that wraps another File implementation.
|
||||
type FileUnwrap interface {
|
||||
File
|
||||
Unwrap() File
|
||||
}
|
||||
|
||||
// FileLockState extends File to implement the
|
||||
// SQLITE_FCNTL_LOCKSTATE file control opcode.
|
||||
//
|
||||
@@ -58,6 +65,26 @@ type FileLockState interface {
|
||||
LockState() LockLevel
|
||||
}
|
||||
|
||||
// FilePersistentWAL extends File to implement the
|
||||
// SQLITE_FCNTL_PERSIST_WAL file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpersistwal
|
||||
type FilePersistentWAL interface {
|
||||
File
|
||||
PersistentWAL() bool
|
||||
SetPersistentWAL(bool)
|
||||
}
|
||||
|
||||
// FilePowersafeOverwrite extends File to implement the
|
||||
// SQLITE_FCNTL_POWERSAFE_OVERWRITE file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpowersafeoverwrite
|
||||
type FilePowersafeOverwrite interface {
|
||||
File
|
||||
PowersafeOverwrite() bool
|
||||
SetPowersafeOverwrite(bool)
|
||||
}
|
||||
|
||||
// FileChunkSize extends File to implement the
|
||||
// SQLITE_FCNTL_CHUNK_SIZE file control opcode.
|
||||
//
|
||||
@@ -94,26 +121,6 @@ type FileOverwrite interface {
|
||||
Overwrite() error
|
||||
}
|
||||
|
||||
// FilePersistentWAL extends File to implement the
|
||||
// SQLITE_FCNTL_PERSIST_WAL file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpersistwal
|
||||
type FilePersistentWAL interface {
|
||||
File
|
||||
PersistentWAL() bool
|
||||
SetPersistentWAL(bool)
|
||||
}
|
||||
|
||||
// FilePowersafeOverwrite extends File to implement the
|
||||
// SQLITE_FCNTL_POWERSAFE_OVERWRITE file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpowersafeoverwrite
|
||||
type FilePowersafeOverwrite interface {
|
||||
File
|
||||
PowersafeOverwrite() bool
|
||||
SetPowersafeOverwrite(bool)
|
||||
}
|
||||
|
||||
// FileCommitPhaseTwo extends File to implement the
|
||||
// SQLITE_FCNTL_COMMIT_PHASETWO file control opcode.
|
||||
//
|
||||
@@ -135,15 +142,6 @@ type FileBatchAtomicWrite interface {
|
||||
RollbackAtomicWrite() error
|
||||
}
|
||||
|
||||
// FilePragma extends File to implement the
|
||||
// SQLITE_FCNTL_PRAGMA file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpragma
|
||||
type FilePragma interface {
|
||||
File
|
||||
Pragma(name, value string) (string, error)
|
||||
}
|
||||
|
||||
// FileCheckpoint extends File to implement the
|
||||
// SQLITE_FCNTL_CKPT_START and SQLITE_FCNTL_CKPT_DONE
|
||||
// file control opcodes.
|
||||
@@ -151,8 +149,17 @@ type FilePragma interface {
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlckptstart
|
||||
type FileCheckpoint interface {
|
||||
File
|
||||
CheckpointDone() error
|
||||
CheckpointStart() error
|
||||
CheckpointStart()
|
||||
CheckpointDone()
|
||||
}
|
||||
|
||||
// FilePragma extends File to implement the
|
||||
// SQLITE_FCNTL_PRAGMA file control opcode.
|
||||
//
|
||||
// https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html#sqlitefcntlpragma
|
||||
type FilePragma interface {
|
||||
File
|
||||
Pragma(name, value string) (string, error)
|
||||
}
|
||||
|
||||
// FileSharedMemory extends File to possibly implement
|
||||
|
||||
32
vfs/vfs.go
32
vfs/vfs.go
@@ -239,14 +239,8 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
switch op {
|
||||
case _FCNTL_LOCKSTATE:
|
||||
if file, ok := file.(FileLockState); ok {
|
||||
util.WriteUint32(mod, pArg, uint32(file.LockState()))
|
||||
return _OK
|
||||
}
|
||||
|
||||
case _FCNTL_LOCK_TIMEOUT:
|
||||
if file, ok := file.(FileSharedMemory); ok {
|
||||
if shm, ok := file.SharedMemory().(blockingSharedMemory); ok {
|
||||
shm.shmEnableBlocking(util.ReadUint32(mod, pArg) != 0)
|
||||
if lk := file.LockState(); lk <= LOCK_EXCLUSIVE {
|
||||
util.WriteUint32(mod, pArg, uint32(lk))
|
||||
return _OK
|
||||
}
|
||||
}
|
||||
@@ -328,15 +322,15 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
return vfsErrorCode(err, _IOERR_ROLLBACK_ATOMIC)
|
||||
}
|
||||
|
||||
case _FCNTL_CKPT_DONE:
|
||||
if file, ok := file.(FileCheckpoint); ok {
|
||||
err := file.CheckpointDone()
|
||||
return vfsErrorCode(err, _IOERR)
|
||||
}
|
||||
case _FCNTL_CKPT_START:
|
||||
if file, ok := file.(FileCheckpoint); ok {
|
||||
err := file.CheckpointStart()
|
||||
return vfsErrorCode(err, _IOERR)
|
||||
file.CheckpointStart()
|
||||
return _OK
|
||||
}
|
||||
case _FCNTL_CKPT_DONE:
|
||||
if file, ok := file.(FileCheckpoint); ok {
|
||||
file.CheckpointDone()
|
||||
return _OK
|
||||
}
|
||||
|
||||
case _FCNTL_PRAGMA:
|
||||
@@ -365,6 +359,14 @@ func vfsFileControl(ctx context.Context, mod api.Module, pFile uint32, op _Fcntl
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
case _FCNTL_LOCK_TIMEOUT:
|
||||
if file, ok := file.(FileSharedMemory); ok {
|
||||
if shm, ok := file.SharedMemory().(blockingSharedMemory); ok {
|
||||
shm.shmEnableBlocking(util.ReadUint32(mod, pArg) != 0)
|
||||
return _OK
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consider also implementing these opcodes (in use by SQLite):
|
||||
|
||||
@@ -35,7 +35,7 @@ func (x *xtsVFS) OpenFilename(name *vfs.Filename, flags vfs.OpenFlag) (file vfs.
|
||||
}
|
||||
|
||||
var cipher *xts.Cipher
|
||||
if f, ok := name.DatabaseFile().(*xtsFile); ok {
|
||||
if f, ok := vfsutil.UnwrapFile[*xtsFile](name.DatabaseFile()); ok {
|
||||
cipher = f.cipher
|
||||
} else {
|
||||
var key []byte
|
||||
@@ -67,6 +67,17 @@ func (x *xtsVFS) OpenFilename(name *vfs.Filename, flags vfs.OpenFlag) (file vfs.
|
||||
// https://sqlite.org/fileformat.html#pages
|
||||
const sectorSize = 512
|
||||
|
||||
// Ensure sectorSize is a power of two.
|
||||
var _ [0]struct{} = [sectorSize & (sectorSize - 1)]struct{}{}
|
||||
|
||||
func roundDown(i int64) int64 {
|
||||
return i &^ (sectorSize - 1)
|
||||
}
|
||||
|
||||
func roundUp[T int | int64](i T) T {
|
||||
return (i + (sectorSize - 1)) &^ (sectorSize - 1)
|
||||
}
|
||||
|
||||
type xtsFile struct {
|
||||
vfs.File
|
||||
init XTSCreator
|
||||
@@ -106,8 +117,8 @@ func (x *xtsFile) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, sqlite3.CANTOPEN
|
||||
}
|
||||
|
||||
min := (off) &^ (sectorSize - 1) // round down
|
||||
max := (off + int64(len(p)) + (sectorSize - 1)) &^ (sectorSize - 1) // round up
|
||||
min := roundDown(off)
|
||||
max := roundUp(off + int64(len(p)))
|
||||
|
||||
// Read one block at a time.
|
||||
for ; min < max; min += sectorSize {
|
||||
@@ -137,8 +148,8 @@ func (x *xtsFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return 0, sqlite3.READONLY
|
||||
}
|
||||
|
||||
min := (off) &^ (sectorSize - 1) // round down
|
||||
max := (off + int64(len(p)) + (sectorSize - 1)) &^ (sectorSize - 1) // round up
|
||||
min := roundDown(off)
|
||||
max := roundUp(off + int64(len(p)))
|
||||
|
||||
// Write one block at a time.
|
||||
for ; min < max; min += sectorSize {
|
||||
@@ -183,45 +194,44 @@ func (x *xtsFile) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (x *xtsFile) Truncate(size int64) error {
|
||||
size = (size + (sectorSize - 1)) &^ (sectorSize - 1) // round up
|
||||
return x.File.Truncate(size)
|
||||
func (x *xtsFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
|
||||
var _ [0]struct{} = [sectorSize - 512]struct{}{} // Ensure sectorSize is 512.
|
||||
return x.File.DeviceCharacteristics() & (0 |
|
||||
// The only safe flags are these:
|
||||
vfs.IOCAP_ATOMIC512 |
|
||||
vfs.IOCAP_UNDELETABLE_WHEN_OPEN |
|
||||
vfs.IOCAP_IMMUTABLE |
|
||||
vfs.IOCAP_BATCH_ATOMIC)
|
||||
}
|
||||
|
||||
func (x *xtsFile) SectorSize() int {
|
||||
return util.LCM(x.File.SectorSize(), sectorSize)
|
||||
}
|
||||
|
||||
func (x *xtsFile) DeviceCharacteristics() vfs.DeviceCharacteristic {
|
||||
return x.File.DeviceCharacteristics() & (0 |
|
||||
// The only safe flags are these:
|
||||
vfs.IOCAP_UNDELETABLE_WHEN_OPEN |
|
||||
vfs.IOCAP_IMMUTABLE |
|
||||
vfs.IOCAP_BATCH_ATOMIC)
|
||||
func (x *xtsFile) Truncate(size int64) error {
|
||||
return x.File.Truncate(roundUp(size))
|
||||
}
|
||||
|
||||
// Wrap optional methods.
|
||||
func (x *xtsFile) ChunkSize(size int) {
|
||||
vfsutil.WrapChunkSize(x.File, roundUp(size))
|
||||
}
|
||||
|
||||
func (x *xtsFile) SizeHint(size int64) error {
|
||||
return vfsutil.WrapSizeHint(x.File, roundUp(size))
|
||||
}
|
||||
|
||||
func (x *xtsFile) Unwrap() vfs.File {
|
||||
return x.File
|
||||
}
|
||||
|
||||
func (x *xtsFile) SharedMemory() vfs.SharedMemory {
|
||||
return vfsutil.WrapSharedMemory(x.File)
|
||||
}
|
||||
|
||||
func (x *xtsFile) ChunkSize(size int) {
|
||||
size = (size + (sectorSize - 1)) &^ (sectorSize - 1) // round up
|
||||
vfsutil.WrapChunkSize(x.File, size)
|
||||
}
|
||||
// Wrap optional methods.
|
||||
|
||||
func (x *xtsFile) SizeHint(size int64) error {
|
||||
size = (size + (sectorSize - 1)) &^ (sectorSize - 1) // round up
|
||||
return vfsutil.WrapSizeHint(x.File, size)
|
||||
}
|
||||
|
||||
func (x *xtsFile) HasMoved() (bool, error) {
|
||||
return vfsutil.WrapHasMoved(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) Overwrite() error {
|
||||
return vfsutil.WrapOverwrite(x.File) // notest
|
||||
func (x *xtsFile) LockState() vfs.LockLevel {
|
||||
return vfsutil.WrapLockState(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) PersistentWAL() bool {
|
||||
@@ -232,6 +242,14 @@ func (x *xtsFile) SetPersistentWAL(keepWAL bool) {
|
||||
vfsutil.WrapSetPersistentWAL(x.File, keepWAL) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) HasMoved() (bool, error) {
|
||||
return vfsutil.WrapHasMoved(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) Overwrite() error {
|
||||
return vfsutil.WrapOverwrite(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) CommitPhaseTwo() error {
|
||||
return vfsutil.WrapCommitPhaseTwo(x.File) // notest
|
||||
}
|
||||
@@ -248,10 +266,10 @@ func (x *xtsFile) RollbackAtomicWrite() error {
|
||||
return vfsutil.WrapRollbackAtomicWrite(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) CheckpointDone() error {
|
||||
return vfsutil.WrapCheckpointDone(x.File) // notest
|
||||
func (x *xtsFile) CheckpointStart() {
|
||||
vfsutil.WrapCheckpointStart(x.File) // notest
|
||||
}
|
||||
|
||||
func (x *xtsFile) CheckpointStart() error {
|
||||
return vfsutil.WrapCheckpointStart(x.File) // notest
|
||||
func (x *xtsFile) CheckpointDone() {
|
||||
vfsutil.WrapCheckpointDone(x.File) // notest
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user