add files lock

This commit is contained in:
Jaremy Creechley 2023-09-28 19:00:22 -07:00
parent 2a4d96e109
commit ebc93e8924
No known key found for this signature in database
GPG Key ID: 4E66FB67B21D3300

View File

@ -1,6 +1,7 @@
import std/os
import std/options
import std/strutils
import std/tempfiles
import pkg/questionable
import pkg/questionable/results
@ -13,6 +14,15 @@ export backend
push: {.upraises: [].}
import std/sharedtables
var keyTable: SharedTable[KeyId, int]
template withReadLock(key: KeyId, blk: untyped) =
`blk`
template withWriteLock(key: KeyId, blk: untyped) =
`blk`
type
FSBackend*[K, V] = object
root*: DataBuffer
@ -67,7 +77,8 @@ proc findPath*[K,V](self: FSBackend[K,V], key: K): ?!string =
proc has*[K,V](self: FSBackend[K,V], key: K): ?!bool =
without path =? self.findPath(key), error:
return failure error
success path.fileExists()
withReadLock(key):
success path.fileExists()
proc contains*[K](self: FSBackend, key: K): bool =
return self.has(key).get()
@ -80,7 +91,8 @@ proc delete*[K,V](self: FSBackend[K,V], key: K): ?!void =
return success()
try:
removeFile(path)
withWriteLock(key):
removeFile(path)
except OSError as e:
return failure e
@ -100,34 +112,35 @@ proc readFile[V](self: FSBackend, path: string): ?!V =
defer:
file.close
if not file.open(path):
return failure "unable to open file! path: " & path
withReadLock(key):
if not file.open(path):
return failure "unable to open file! path: " & path
try:
let
size = file.getFileSize().int
try:
let
size = file.getFileSize().int
when V is seq[byte]:
var bytes = newSeq[byte](size)
elif V is V:
var bytes = V.new(size=size)
else:
{.error: "unhandled result type".}
var
read = 0
when V is seq[byte]:
var bytes = newSeq[byte](size)
elif V is V:
var bytes = V.new(size=size)
else:
{.error: "unhandled result type".}
var
read = 0
# echo "BYTES: ", bytes.repr
while read < size:
read += file.readBytes(bytes.toOpenArray(0, size-1), read, size)
# echo "BYTES: ", bytes.repr
while read < size:
read += file.readBytes(bytes.toOpenArray(0, size-1), read, size)
if read < size:
return failure $read & " bytes were read from " & path &
" but " & $size & " bytes were expected"
if read < size:
return failure $read & " bytes were read from " & path &
" but " & $size & " bytes were expected"
return success bytes
return success bytes
except CatchableError as e:
return failure e
except CatchableError as e:
return failure e
proc get*[K,V](self: FSBackend[K,V], key: K): ?!V =
without path =? self.findPath(key), error:
@ -149,8 +162,14 @@ proc put*[K,V](self: FSBackend[K,V],
try:
var data = data
createDir(parentDir(path))
writeFile(path, data.toOpenArray(0, data.len()-1))
withWriteLock(KeyId.new path):
createDir(parentDir(path))
let tmpPath = genTempPath("temp", "", path.splitPath.tail)
writeFile(tmpPath, data.toOpenArray(0, data.len()-1))
withWriteLock(key):
moveFile(tmpPath, path)
except CatchableError as e:
return failure e