mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Unix fcntl locks.
This commit is contained in:
8
conn.go
8
conn.go
@@ -40,7 +40,7 @@ func OpenFlags(filename string, flags OpenFlag) (conn *Conn, err error) {
|
||||
c := newConn(module)
|
||||
c.ctx = context.Background()
|
||||
namePtr := c.newString(filename)
|
||||
connPtr := c.new(wordSize)
|
||||
connPtr := c.new(ptrlen)
|
||||
defer c.free(namePtr)
|
||||
defer c.free(connPtr)
|
||||
|
||||
@@ -86,8 +86,8 @@ func (c *Conn) Prepare(sql string) (stmt *Stmt, tail string, err error) {
|
||||
|
||||
func (c *Conn) PrepareFlags(sql string, flags PrepareFlag) (stmt *Stmt, tail string, err error) {
|
||||
sqlPtr := c.newString(sql)
|
||||
stmtPtr := c.new(wordSize)
|
||||
tailPtr := c.new(wordSize)
|
||||
stmtPtr := c.new(ptrlen)
|
||||
tailPtr := c.new(ptrlen)
|
||||
defer c.free(sqlPtr)
|
||||
defer c.free(stmtPtr)
|
||||
defer c.free(tailPtr)
|
||||
@@ -221,5 +221,3 @@ func getString(memory api.Memory, ptr, maxlen uint32) string {
|
||||
return string(mem[:i])
|
||||
}
|
||||
}
|
||||
|
||||
const wordSize = 4
|
||||
|
||||
3
const.go
3
const.go
@@ -8,6 +8,9 @@ const (
|
||||
_UTF8 = 1
|
||||
|
||||
_MAX_PATHNAME = 512
|
||||
|
||||
assert = true
|
||||
ptrlen = 4
|
||||
)
|
||||
|
||||
type ErrorCode uint8
|
||||
|
||||
18
vfs.go
18
vfs.go
@@ -67,15 +67,15 @@ func vfsLocaltime(ctx context.Context, mod api.Module, t uint64, pTm uint32) uin
|
||||
}
|
||||
// https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
|
||||
if mem := mod.Memory(); true &&
|
||||
mem.WriteUint32Le(pTm+0*wordSize, uint32(tm.Second())) &&
|
||||
mem.WriteUint32Le(pTm+1*wordSize, uint32(tm.Minute())) &&
|
||||
mem.WriteUint32Le(pTm+2*wordSize, uint32(tm.Hour())) &&
|
||||
mem.WriteUint32Le(pTm+3*wordSize, uint32(tm.Day())) &&
|
||||
mem.WriteUint32Le(pTm+4*wordSize, uint32(tm.Month()-time.January)) &&
|
||||
mem.WriteUint32Le(pTm+5*wordSize, uint32(tm.Year()-1900)) &&
|
||||
mem.WriteUint32Le(pTm+6*wordSize, uint32(tm.Weekday()-time.Sunday)) &&
|
||||
mem.WriteUint32Le(pTm+7*wordSize, uint32(tm.YearDay()-1)) &&
|
||||
mem.WriteUint32Le(pTm+8*wordSize, uint32(isdst)) {
|
||||
mem.WriteUint32Le(pTm+0*ptrlen, uint32(tm.Second())) &&
|
||||
mem.WriteUint32Le(pTm+1*ptrlen, uint32(tm.Minute())) &&
|
||||
mem.WriteUint32Le(pTm+2*ptrlen, uint32(tm.Hour())) &&
|
||||
mem.WriteUint32Le(pTm+3*ptrlen, uint32(tm.Day())) &&
|
||||
mem.WriteUint32Le(pTm+4*ptrlen, uint32(tm.Month()-time.January)) &&
|
||||
mem.WriteUint32Le(pTm+5*ptrlen, uint32(tm.Year()-1900)) &&
|
||||
mem.WriteUint32Le(pTm+6*ptrlen, uint32(tm.Weekday()-time.Sunday)) &&
|
||||
mem.WriteUint32Le(pTm+7*ptrlen, uint32(tm.YearDay()-1)) &&
|
||||
mem.WriteUint32Le(pTm+8*ptrlen, uint32(isdst)) {
|
||||
return _OK
|
||||
}
|
||||
panic(rangeErr)
|
||||
|
||||
10
vfs_files.go
10
vfs_files.go
@@ -42,7 +42,7 @@ func vfsGetOpenFileID(file *os.File, info os.FileInfo) uint32 {
|
||||
info: info,
|
||||
nref: 1,
|
||||
|
||||
vfsLocker: &vfsNoopLocker{},
|
||||
vfsLocker: &vfsFileLocker{file, _NO_LOCK},
|
||||
}
|
||||
|
||||
// Find an empty slot.
|
||||
@@ -88,7 +88,7 @@ func (p vfsFilePtr) ID() uint32 {
|
||||
if p.ptr == 0 {
|
||||
panic(nilErr)
|
||||
}
|
||||
id, ok := p.Memory().ReadUint32Le(p.ptr + wordSize)
|
||||
id, ok := p.Memory().ReadUint32Le(p.ptr + ptrlen)
|
||||
if !ok {
|
||||
panic(rangeErr)
|
||||
}
|
||||
@@ -99,7 +99,7 @@ func (p vfsFilePtr) Lock() vfsLockState {
|
||||
if p.ptr == 0 {
|
||||
panic(nilErr)
|
||||
}
|
||||
lk, ok := p.Memory().ReadUint32Le(p.ptr + 2*wordSize)
|
||||
lk, ok := p.Memory().ReadUint32Le(p.ptr + 2*ptrlen)
|
||||
if !ok {
|
||||
panic(rangeErr)
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func (p vfsFilePtr) SetID(id uint32) vfsFilePtr {
|
||||
if p.ptr == 0 {
|
||||
panic(nilErr)
|
||||
}
|
||||
if ok := p.Memory().WriteUint32Le(p.ptr+wordSize, id); !ok {
|
||||
if ok := p.Memory().WriteUint32Le(p.ptr+ptrlen, id); !ok {
|
||||
panic(rangeErr)
|
||||
}
|
||||
return p
|
||||
@@ -120,7 +120,7 @@ func (p vfsFilePtr) SetLock(lock vfsLockState) vfsFilePtr {
|
||||
if p.ptr == 0 {
|
||||
panic(nilErr)
|
||||
}
|
||||
if ok := p.Memory().WriteUint32Le(p.ptr+2*wordSize, uint32(lock)); !ok {
|
||||
if ok := p.Memory().WriteUint32Le(p.ptr+2*ptrlen, uint32(lock)); !ok {
|
||||
panic(rangeErr)
|
||||
}
|
||||
return p
|
||||
|
||||
19
vfs_lock.go
19
vfs_lock.go
@@ -52,19 +52,22 @@ const (
|
||||
_SHARED_SIZE = 510
|
||||
)
|
||||
|
||||
type vfsLockState uint32
|
||||
type (
|
||||
vfsLockState uint32
|
||||
xErrorCode = ExtendedErrorCode
|
||||
)
|
||||
|
||||
type vfsLocker interface {
|
||||
LockState() vfsLockState
|
||||
|
||||
LockShared() uint32 // UNLOCKED -> SHARED
|
||||
LockReserved() uint32 // SHARED -> RESERVED
|
||||
LockPending() uint32 // SHARED|RESERVED -> PENDING
|
||||
LockExclusive() uint32 // PENDING -> EXCLUSIVE
|
||||
DowngradeLock() uint32 // SHARED <- EXCLUSIVE|PENDING|RESERVED
|
||||
Unlock() uint32 // UNLOCKED <- EXCLUSIVE|PENDING|RESERVED|SHARED
|
||||
LockShared() xErrorCode // UNLOCKED -> SHARED
|
||||
LockReserved() xErrorCode // SHARED -> RESERVED
|
||||
LockPending() xErrorCode // SHARED|RESERVED -> PENDING
|
||||
LockExclusive() xErrorCode // PENDING -> EXCLUSIVE
|
||||
DowngradeLock() xErrorCode // SHARED <- EXCLUSIVE|PENDING|RESERVED
|
||||
Unlock() xErrorCode // UNLOCKED <- EXCLUSIVE|PENDING|RESERVED|SHARED
|
||||
|
||||
CheckReservedLock() (bool, uint32)
|
||||
CheckReservedLock() (bool, xErrorCode)
|
||||
}
|
||||
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) uint32 {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package sqlite3
|
||||
|
||||
const assert = true
|
||||
|
||||
type vfsNoopLocker struct {
|
||||
state vfsLockState
|
||||
}
|
||||
@@ -12,7 +10,7 @@ func (l *vfsNoopLocker) LockState() vfsLockState {
|
||||
return l.state
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) LockShared() uint32 {
|
||||
func (l *vfsNoopLocker) LockShared() xErrorCode {
|
||||
if assert && !(l.state == _NO_LOCK) {
|
||||
panic(assertErr + " [wz9dcw]")
|
||||
}
|
||||
@@ -20,7 +18,7 @@ func (l *vfsNoopLocker) LockShared() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) LockReserved() uint32 {
|
||||
func (l *vfsNoopLocker) LockReserved() xErrorCode {
|
||||
if assert && !(l.state == _SHARED_LOCK) {
|
||||
panic(assertErr + " [m9hcil]")
|
||||
}
|
||||
@@ -28,7 +26,7 @@ func (l *vfsNoopLocker) LockReserved() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) LockPending() uint32 {
|
||||
func (l *vfsNoopLocker) LockPending() xErrorCode {
|
||||
if assert && !(l.state == _SHARED_LOCK || l.state == _RESERVED_LOCK) {
|
||||
panic(assertErr + " [wx8nk2]")
|
||||
}
|
||||
@@ -36,7 +34,7 @@ func (l *vfsNoopLocker) LockPending() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) LockExclusive() uint32 {
|
||||
func (l *vfsNoopLocker) LockExclusive() xErrorCode {
|
||||
if assert && !(l.state == _PENDING_LOCK) {
|
||||
panic(assertErr + " [84nbax]")
|
||||
}
|
||||
@@ -44,7 +42,7 @@ func (l *vfsNoopLocker) LockExclusive() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) DowngradeLock() uint32 {
|
||||
func (l *vfsNoopLocker) DowngradeLock() xErrorCode {
|
||||
if assert && !(l.state > _SHARED_LOCK) {
|
||||
panic(assertErr + " [je31i3]")
|
||||
}
|
||||
@@ -52,7 +50,7 @@ func (l *vfsNoopLocker) DowngradeLock() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) Unlock() uint32 {
|
||||
func (l *vfsNoopLocker) Unlock() xErrorCode {
|
||||
if assert && !(l.state > _NO_LOCK) {
|
||||
panic(assertErr + " [m6e9w5]")
|
||||
}
|
||||
@@ -60,7 +58,7 @@ func (l *vfsNoopLocker) Unlock() uint32 {
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsNoopLocker) CheckReservedLock() (bool, uint32) {
|
||||
func (l *vfsNoopLocker) CheckReservedLock() (bool, xErrorCode) {
|
||||
if l.state >= _RESERVED_LOCK {
|
||||
return true, _OK
|
||||
}
|
||||
|
||||
140
vfs_unix.go
140
vfs_unix.go
@@ -2,8 +2,146 @@
|
||||
|
||||
package sqlite3
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func deleteOnClose(f *os.File) {
|
||||
_ = os.Remove(f.Name())
|
||||
}
|
||||
|
||||
type vfsFileLocker struct {
|
||||
*os.File
|
||||
state vfsLockState
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) LockState() vfsLockState {
|
||||
return l.state
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) LockShared() xErrorCode {
|
||||
// A PENDING lock is needed before acquiring a SHARED lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 1,
|
||||
}) {
|
||||
return IOERR_LOCK
|
||||
}
|
||||
|
||||
// Acquire the SHARED lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
Start: _SHARED_FIRST,
|
||||
Len: _SHARED_SIZE,
|
||||
}) {
|
||||
return IOERR_LOCK
|
||||
}
|
||||
l.state = _SHARED_LOCK
|
||||
|
||||
// Relese the PENDING lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_UNLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 1,
|
||||
}) {
|
||||
return IOERR_UNLOCK
|
||||
}
|
||||
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) LockReserved() xErrorCode {
|
||||
// Acquire the RESERVED lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _RESERVED_BYTE,
|
||||
Len: 1,
|
||||
}) {
|
||||
return IOERR_LOCK
|
||||
}
|
||||
l.state = _RESERVED_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) LockPending() xErrorCode {
|
||||
// Acquire the PENDING lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 1,
|
||||
}) {
|
||||
return IOERR_LOCK
|
||||
}
|
||||
l.state = _PENDING_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) LockExclusive() xErrorCode {
|
||||
// Acquire the EXCLUSIVE lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_WRLCK,
|
||||
Start: _SHARED_FIRST,
|
||||
Len: _SHARED_SIZE,
|
||||
}) {
|
||||
return IOERR_LOCK
|
||||
}
|
||||
l.state = _EXCLUSIVE_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) DowngradeLock() xErrorCode {
|
||||
// Downgrade to a SHARED lock.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
Start: _SHARED_FIRST,
|
||||
Len: _SHARED_SIZE,
|
||||
}) {
|
||||
return IOERR_RDLOCK
|
||||
}
|
||||
l.state = _SHARED_LOCK
|
||||
|
||||
// Release the PENDING and RESERVED locks.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_UNLCK,
|
||||
Start: _PENDING_BYTE,
|
||||
Len: 2,
|
||||
}) {
|
||||
return IOERR_UNLOCK
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) Unlock() xErrorCode {
|
||||
// Release all locks.
|
||||
if !l.fcntlSetLock(&syscall.Flock_t{
|
||||
Type: syscall.F_UNLCK,
|
||||
}) {
|
||||
return IOERR_UNLOCK
|
||||
}
|
||||
l.state = _NO_LOCK
|
||||
return _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) CheckReservedLock() (bool, xErrorCode) {
|
||||
if l.state >= _RESERVED_LOCK {
|
||||
return true, _OK
|
||||
}
|
||||
// Test all write locks.
|
||||
lock := syscall.Flock_t{
|
||||
Type: syscall.F_RDLCK,
|
||||
}
|
||||
if !l.fcntlGetLock(&lock) {
|
||||
return false, IOERR_CHECKRESERVEDLOCK
|
||||
}
|
||||
return lock.Type == syscall.F_UNLCK, _OK
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) fcntlGetLock(lock *syscall.Flock_t) bool {
|
||||
return syscall.FcntlFlock(l.Fd(), syscall.F_GETLK, lock) == nil
|
||||
}
|
||||
|
||||
func (l *vfsFileLocker) fcntlSetLock(lock *syscall.Flock_t) bool {
|
||||
return syscall.FcntlFlock(l.Fd(), syscall.F_SETLK, lock) == nil
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
package sqlite3
|
||||
|
||||
func deleteOnClose(f *os.File) {}
|
||||
|
||||
type vfsFileLocker = vfsNoopLocker
|
||||
|
||||
Reference in New Issue
Block a user