mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Refactor.
This commit is contained in:
@@ -19,7 +19,7 @@ embeds a build of SQLite into your application.
|
||||
### Caveats
|
||||
|
||||
This module replaces the SQLite [OS Interface](https://www.sqlite.org/vfs.html) (aka VFS)
|
||||
with a pure Go implementation.
|
||||
with a [pure Go](internal/vfs/) implementation.
|
||||
This has numerous benefits, but also comes with some drawbacks.
|
||||
|
||||
#### Write-Ahead Logging
|
||||
|
||||
3
const.go
3
const.go
@@ -9,8 +9,7 @@ const (
|
||||
|
||||
_UTF8 = 1
|
||||
|
||||
_MAX_STRING = 512 // Used for short strings: names, error messages…
|
||||
_MAX_PATHNAME = 512
|
||||
_MAX_STRING = 512 // Used for short strings: names, error messages…
|
||||
|
||||
_MAX_ALLOCATION_SIZE = 0x7ffffeff
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package vfs
|
||||
|
||||
const (
|
||||
_MAX_PATHNAME = 512
|
||||
|
||||
ptrlen = 4
|
||||
)
|
||||
const _MAX_PATHNAME = 512
|
||||
|
||||
// https://www.sqlite.org/rescode.html
|
||||
type _ErrorCode uint32
|
||||
|
||||
const (
|
||||
@@ -55,9 +52,10 @@ const (
|
||||
_CANTOPEN_CONVPATH = _CANTOPEN | (4 << 8)
|
||||
_CANTOPEN_DIRTYWAL = _CANTOPEN | (5 << 8) /* Not Used */
|
||||
_CANTOPEN_SYMLINK = _CANTOPEN | (6 << 8)
|
||||
_OK_SYMLINK = (_OK | (2 << 8)) /* internal use only */
|
||||
_OK_SYMLINK = _OK | (2 << 8) /* internal use only */
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_open_autoproxy.html
|
||||
type _OpenFlag uint32
|
||||
|
||||
const (
|
||||
@@ -85,6 +83,7 @@ const (
|
||||
_OPEN_EXRESCODE _OpenFlag = 0x02000000 /* Extended result codes */
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_access_exists.html
|
||||
type _AccessFlag uint32
|
||||
|
||||
const (
|
||||
@@ -93,6 +92,7 @@ const (
|
||||
_ACCESS_READ _AccessFlag = 2 /* Unused */
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_sync_dataonly.html
|
||||
type _SyncFlag uint32
|
||||
|
||||
const (
|
||||
@@ -101,6 +101,51 @@ const (
|
||||
_SYNC_DATAONLY _SyncFlag = 0x00010
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_lock_exclusive.html
|
||||
type _LockLevel uint32
|
||||
|
||||
const (
|
||||
// No locks are held on the database.
|
||||
// The database may be neither read nor written.
|
||||
// Any internally cached data is considered suspect and subject to
|
||||
// verification against the database file before being used.
|
||||
// Other processes can read or write the database as their own locking
|
||||
// states permit.
|
||||
// This is the default state.
|
||||
_LOCK_NONE _LockLevel = 0 /* xUnlock() only */
|
||||
|
||||
// The database may be read but not written.
|
||||
// Any number of processes can hold SHARED locks at the same time,
|
||||
// hence there can be many simultaneous readers.
|
||||
// But no other thread or process is allowed to write to the database file
|
||||
// while one or more SHARED locks are active.
|
||||
_LOCK_SHARED _LockLevel = 1 /* xLock() or xUnlock() */
|
||||
|
||||
// A RESERVED lock means that the process is planning on writing to the
|
||||
// database file at some point in the future but that it is currently just
|
||||
// reading from the file.
|
||||
// Only a single RESERVED lock may be active at one time,
|
||||
// though multiple SHARED locks can coexist with a single RESERVED lock.
|
||||
// RESERVED differs from PENDING in that new SHARED locks can be acquired
|
||||
// while there is a RESERVED lock.
|
||||
_LOCK_RESERVED _LockLevel = 2 /* xLock() only */
|
||||
|
||||
// A PENDING lock means that the process holding the lock wants to write to
|
||||
// the database as soon as possible and is just waiting on all current
|
||||
// SHARED locks to clear so that it can get an EXCLUSIVE lock.
|
||||
// No new SHARED locks are permitted against the database if a PENDING lock
|
||||
// is active, though existing SHARED locks are allowed to continue.
|
||||
_LOCK_PENDING _LockLevel = 3 /* internal use only */
|
||||
|
||||
// An EXCLUSIVE lock is needed in order to write to the database file.
|
||||
// Only one EXCLUSIVE lock is allowed on the file and no other locks of any
|
||||
// kind are allowed to coexist with an EXCLUSIVE lock.
|
||||
// In order to maximize concurrency, SQLite works to minimize the amount of
|
||||
// time that EXCLUSIVE locks are held.
|
||||
_LOCK_EXCLUSIVE _LockLevel = 4 /* xLock() only */
|
||||
)
|
||||
|
||||
// https://www.sqlite.org/c3ref/c_fcntl_begin_atomic_write.html
|
||||
type _FcntlOpcode uint32
|
||||
|
||||
const (
|
||||
|
||||
@@ -16,13 +16,10 @@ import (
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
|
||||
_ "github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/vfs"
|
||||
)
|
||||
|
||||
@@ -13,12 +13,10 @@ import (
|
||||
"testing"
|
||||
|
||||
_ "embed"
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/tetratelabs/wazero"
|
||||
"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
|
||||
|
||||
_ "github.com/ncruces/go-sqlite3"
|
||||
"github.com/ncruces/go-sqlite3/internal/vfs"
|
||||
)
|
||||
|
||||
@@ -76,16 +76,17 @@ func vfsLocaltime(ctx context.Context, mod api.Module, pTm uint32, t int64) _Err
|
||||
isdst = 1
|
||||
}
|
||||
|
||||
const size = 32 / 8
|
||||
// https://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
|
||||
util.WriteUint32(mod, pTm+0*ptrlen, uint32(tm.Second()))
|
||||
util.WriteUint32(mod, pTm+1*ptrlen, uint32(tm.Minute()))
|
||||
util.WriteUint32(mod, pTm+2*ptrlen, uint32(tm.Hour()))
|
||||
util.WriteUint32(mod, pTm+3*ptrlen, uint32(tm.Day()))
|
||||
util.WriteUint32(mod, pTm+4*ptrlen, uint32(tm.Month()-time.January))
|
||||
util.WriteUint32(mod, pTm+5*ptrlen, uint32(tm.Year()-1900))
|
||||
util.WriteUint32(mod, pTm+6*ptrlen, uint32(tm.Weekday()-time.Sunday))
|
||||
util.WriteUint32(mod, pTm+7*ptrlen, uint32(tm.YearDay()-1))
|
||||
util.WriteUint32(mod, pTm+8*ptrlen, uint32(isdst))
|
||||
util.WriteUint32(mod, pTm+0*size, uint32(tm.Second()))
|
||||
util.WriteUint32(mod, pTm+1*size, uint32(tm.Minute()))
|
||||
util.WriteUint32(mod, pTm+2*size, uint32(tm.Hour()))
|
||||
util.WriteUint32(mod, pTm+3*size, uint32(tm.Day()))
|
||||
util.WriteUint32(mod, pTm+4*size, uint32(tm.Month()-time.January))
|
||||
util.WriteUint32(mod, pTm+5*size, uint32(tm.Year()-1900))
|
||||
util.WriteUint32(mod, pTm+6*size, uint32(tm.Weekday()-time.Sunday))
|
||||
util.WriteUint32(mod, pTm+7*size, uint32(tm.YearDay()-1))
|
||||
util.WriteUint32(mod, pTm+8*size, uint32(isdst))
|
||||
return _OK
|
||||
}
|
||||
|
||||
|
||||
@@ -53,11 +53,11 @@ func getOSFile(ctx context.Context, mod api.Module, pFile uint32) *os.File {
|
||||
return vfs.files[id]
|
||||
}
|
||||
|
||||
func getFileLock(ctx context.Context, mod api.Module, pFile uint32) vfsLockState {
|
||||
return vfsLockState(util.ReadUint8(mod, pFile+vfsFileLockOffset))
|
||||
func getFileLock(ctx context.Context, mod api.Module, pFile uint32) _LockLevel {
|
||||
return _LockLevel(util.ReadUint8(mod, pFile+vfsFileLockOffset))
|
||||
}
|
||||
|
||||
func setFileLock(ctx context.Context, mod api.Module, pFile uint32, lock vfsLockState) {
|
||||
func setFileLock(ctx context.Context, mod api.Module, pFile uint32, lock _LockLevel) {
|
||||
util.WriteUint8(mod, pFile+vfsFileLockOffset, uint8(lock))
|
||||
}
|
||||
|
||||
|
||||
@@ -10,56 +10,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// No locks are held on the database.
|
||||
// The database may be neither read nor written.
|
||||
// Any internally cached data is considered suspect and subject to
|
||||
// verification against the database file before being used.
|
||||
// Other processes can read or write the database as their own locking
|
||||
// states permit.
|
||||
// This is the default state.
|
||||
_NO_LOCK = 0
|
||||
|
||||
// The database may be read but not written.
|
||||
// Any number of processes can hold SHARED locks at the same time,
|
||||
// hence there can be many simultaneous readers.
|
||||
// But no other thread or process is allowed to write to the database file
|
||||
// while one or more SHARED locks are active.
|
||||
_SHARED_LOCK = 1
|
||||
|
||||
// A RESERVED lock means that the process is planning on writing to the
|
||||
// database file at some point in the future but that it is currently just
|
||||
// reading from the file.
|
||||
// Only a single RESERVED lock may be active at one time,
|
||||
// though multiple SHARED locks can coexist with a single RESERVED lock.
|
||||
// RESERVED differs from PENDING in that new SHARED locks can be acquired
|
||||
// while there is a RESERVED lock.
|
||||
_RESERVED_LOCK = 2
|
||||
|
||||
// A PENDING lock means that the process holding the lock wants to write to
|
||||
// the database as soon as possible and is just waiting on all current
|
||||
// SHARED locks to clear so that it can get an EXCLUSIVE lock.
|
||||
// No new SHARED locks are permitted against the database if a PENDING lock
|
||||
// is active, though existing SHARED locks are allowed to continue.
|
||||
_PENDING_LOCK = 3
|
||||
|
||||
// An EXCLUSIVE lock is needed in order to write to the database file.
|
||||
// Only one EXCLUSIVE lock is allowed on the file and no other locks of any
|
||||
// kind are allowed to coexist with an EXCLUSIVE lock.
|
||||
// In order to maximize concurrency, SQLite works to minimize the amount of
|
||||
// time that EXCLUSIVE locks are held.
|
||||
_EXCLUSIVE_LOCK = 4
|
||||
|
||||
_PENDING_BYTE = 0x40000000
|
||||
_RESERVED_BYTE = (_PENDING_BYTE + 1)
|
||||
_SHARED_FIRST = (_PENDING_BYTE + 2)
|
||||
_SHARED_SIZE = 510
|
||||
)
|
||||
|
||||
type vfsLockState uint32
|
||||
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) _ErrorCode {
|
||||
func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel) _ErrorCode {
|
||||
// Argument check. SQLite never explicitly requests a pending lock.
|
||||
if eLock != _SHARED_LOCK && eLock != _RESERVED_LOCK && eLock != _EXCLUSIVE_LOCK {
|
||||
if eLock != _LOCK_SHARED && eLock != _LOCK_RESERVED && eLock != _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
@@ -69,13 +28,13 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
readOnly := getFileReadOnly(ctx, mod, pFile)
|
||||
|
||||
switch {
|
||||
case cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK:
|
||||
case cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE:
|
||||
// Connection state check.
|
||||
panic(util.AssertErr())
|
||||
case cLock == _NO_LOCK && eLock > _SHARED_LOCK:
|
||||
case cLock == _LOCK_NONE && eLock > _LOCK_SHARED:
|
||||
// We never move from unlocked to anything higher than a shared lock.
|
||||
panic(util.AssertErr())
|
||||
case cLock != _SHARED_LOCK && eLock == _RESERVED_LOCK:
|
||||
case cLock != _LOCK_SHARED && eLock == _LOCK_RESERVED:
|
||||
// A shared lock is always held when a reserved lock is requested.
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
@@ -86,49 +45,49 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
}
|
||||
|
||||
// Do not allow any kind of write-lock on a read-only database.
|
||||
if readOnly && eLock > _RESERVED_LOCK {
|
||||
if readOnly && eLock > _LOCK_RESERVED {
|
||||
return _IOERR_LOCK
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _SHARED_LOCK:
|
||||
case _LOCK_SHARED:
|
||||
// Must be unlocked to get SHARED.
|
||||
if cLock != _NO_LOCK {
|
||||
if cLock != _LOCK_NONE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetSharedLock(file, timeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _SHARED_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_SHARED)
|
||||
return _OK
|
||||
|
||||
case _RESERVED_LOCK:
|
||||
case _LOCK_RESERVED:
|
||||
// Must be SHARED to get RESERVED.
|
||||
if cLock != _SHARED_LOCK {
|
||||
if cLock != _LOCK_SHARED {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
if rc := osGetReservedLock(file, timeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _RESERVED_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_RESERVED)
|
||||
return _OK
|
||||
|
||||
case _EXCLUSIVE_LOCK:
|
||||
case _LOCK_EXCLUSIVE:
|
||||
// Must be SHARED, RESERVED or PENDING to get EXCLUSIVE.
|
||||
if cLock <= _NO_LOCK || cLock >= _EXCLUSIVE_LOCK {
|
||||
if cLock <= _LOCK_NONE || cLock >= _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
// A PENDING lock is needed before acquiring an EXCLUSIVE lock.
|
||||
if cLock < _PENDING_LOCK {
|
||||
if cLock < _LOCK_PENDING {
|
||||
if rc := osGetPendingLock(file); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _PENDING_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_PENDING)
|
||||
}
|
||||
if rc := osGetExclusiveLock(file, timeout); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _EXCLUSIVE_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_EXCLUSIVE)
|
||||
return _OK
|
||||
|
||||
default:
|
||||
@@ -136,9 +95,9 @@ func vfsLock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockSta
|
||||
}
|
||||
}
|
||||
|
||||
func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockState) _ErrorCode {
|
||||
func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock _LockLevel) _ErrorCode {
|
||||
// Argument check.
|
||||
if eLock != _NO_LOCK && eLock != _SHARED_LOCK {
|
||||
if eLock != _LOCK_NONE && eLock != _LOCK_SHARED {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
@@ -146,7 +105,7 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
cLock := getFileLock(ctx, mod, pFile)
|
||||
|
||||
// Connection state check.
|
||||
if cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK {
|
||||
if cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
@@ -156,16 +115,16 @@ func vfsUnlock(ctx context.Context, mod api.Module, pFile uint32, eLock vfsLockS
|
||||
}
|
||||
|
||||
switch eLock {
|
||||
case _SHARED_LOCK:
|
||||
case _LOCK_SHARED:
|
||||
if rc := osDowngradeLock(file, cLock); rc != _OK {
|
||||
return rc
|
||||
}
|
||||
setFileLock(ctx, mod, pFile, _SHARED_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_SHARED)
|
||||
return _OK
|
||||
|
||||
case _NO_LOCK:
|
||||
case _LOCK_NONE:
|
||||
rc := osReleaseLock(file, cLock)
|
||||
setFileLock(ctx, mod, pFile, _NO_LOCK)
|
||||
setFileLock(ctx, mod, pFile, _LOCK_NONE)
|
||||
return rc
|
||||
|
||||
default:
|
||||
@@ -178,13 +137,13 @@ func vfsCheckReservedLock(ctx context.Context, mod api.Module, pFile, pResOut ui
|
||||
cLock := getFileLock(ctx, mod, pFile)
|
||||
|
||||
// Connection state check.
|
||||
if cLock < _NO_LOCK || cLock > _EXCLUSIVE_LOCK {
|
||||
if cLock < _LOCK_NONE || cLock > _LOCK_EXCLUSIVE {
|
||||
panic(util.AssertErr())
|
||||
}
|
||||
|
||||
var locked bool
|
||||
var rc _ErrorCode
|
||||
if cLock >= _RESERVED_LOCK {
|
||||
if cLock >= _LOCK_RESERVED {
|
||||
locked = true
|
||||
} else {
|
||||
locked, rc = osCheckReservedLock(file)
|
||||
|
||||
@@ -61,7 +61,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -81,11 +81,11 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _RESERVED_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_RESERVED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
rc = vfsLock(ctx, mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile2, _EXCLUSIVE_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile2, _LOCK_EXCLUSIVE)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -125,7 +125,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile1, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile1, _LOCK_SHARED)
|
||||
if rc == _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -145,7 +145,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file wasn't locked")
|
||||
}
|
||||
|
||||
rc = vfsUnlock(ctx, mod, pFile2, _SHARED_LOCK)
|
||||
rc = vfsUnlock(ctx, mod, pFile2, _LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
@@ -165,7 +165,7 @@ func Test_vfsLock(t *testing.T) {
|
||||
t.Error("file was locked")
|
||||
}
|
||||
|
||||
rc = vfsLock(ctx, mod, pFile1, _SHARED_LOCK)
|
||||
rc = vfsLock(ctx, mod, pFile1, _LOCK_SHARED)
|
||||
if rc != _OK {
|
||||
t.Fatal("returned", rc)
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ func osGetExclusiveLock(file *os.File, timeout time.Duration) _ErrorCode {
|
||||
return osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, timeout)
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state vfsLockState) _ErrorCode {
|
||||
if state >= _EXCLUSIVE_LOCK {
|
||||
func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
if state >= _LOCK_EXCLUSIVE {
|
||||
// Downgrade to a SHARED lock.
|
||||
if rc := osReadLock(file, _SHARED_FIRST, _SHARED_SIZE, 0); rc != _OK {
|
||||
// In theory, the downgrade to a SHARED cannot fail because another
|
||||
@@ -59,7 +59,7 @@ func osDowngradeLock(file *os.File, state vfsLockState) _ErrorCode {
|
||||
return osUnlock(file, _PENDING_BYTE, 2)
|
||||
}
|
||||
|
||||
func osReleaseLock(file *os.File, _ vfsLockState) _ErrorCode {
|
||||
func osReleaseLock(file *os.File, _ _LockLevel) _ErrorCode {
|
||||
// Release all locks.
|
||||
return osUnlock(file, 0, 0)
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ func osGetExclusiveLock(file *os.File, timeout time.Duration) _ErrorCode {
|
||||
return rc
|
||||
}
|
||||
|
||||
func osDowngradeLock(file *os.File, state vfsLockState) _ErrorCode {
|
||||
if state >= _EXCLUSIVE_LOCK {
|
||||
func osDowngradeLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
if state >= _LOCK_EXCLUSIVE {
|
||||
// Release the SHARED lock.
|
||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
|
||||
@@ -93,24 +93,24 @@ func osDowngradeLock(file *os.File, state vfsLockState) _ErrorCode {
|
||||
}
|
||||
|
||||
// Release the PENDING and RESERVED locks.
|
||||
if state >= _RESERVED_LOCK {
|
||||
if state >= _LOCK_RESERVED {
|
||||
osUnlock(file, _RESERVED_BYTE, 1)
|
||||
}
|
||||
if state >= _PENDING_LOCK {
|
||||
if state >= _LOCK_PENDING {
|
||||
osUnlock(file, _PENDING_BYTE, 1)
|
||||
}
|
||||
return _OK
|
||||
}
|
||||
|
||||
func osReleaseLock(file *os.File, state vfsLockState) _ErrorCode {
|
||||
func osReleaseLock(file *os.File, state _LockLevel) _ErrorCode {
|
||||
// Release all locks.
|
||||
if state >= _RESERVED_LOCK {
|
||||
if state >= _LOCK_RESERVED {
|
||||
osUnlock(file, _RESERVED_BYTE, 1)
|
||||
}
|
||||
if state >= _SHARED_LOCK {
|
||||
if state >= _LOCK_SHARED {
|
||||
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
|
||||
}
|
||||
if state >= _PENDING_LOCK {
|
||||
if state >= _LOCK_PENDING {
|
||||
osUnlock(file, _PENDING_BYTE, 1)
|
||||
}
|
||||
return _OK
|
||||
|
||||
Reference in New Issue
Block a user