simplify locking
This commit is contained in:
parent
52d6a857ac
commit
7306a0bfd4
|
@ -10,3 +10,5 @@ datastore.nims
|
||||||
nimcache
|
nimcache
|
||||||
TODO
|
TODO
|
||||||
nim.cfg
|
nim.cfg
|
||||||
|
nimble.develop
|
||||||
|
nimble.paths
|
||||||
|
|
|
@ -10,3 +10,7 @@ when (NimMajor, NimMinor) == (1, 2):
|
||||||
|
|
||||||
when (NimMajor, NimMinor) > (1, 2):
|
when (NimMajor, NimMinor) > (1, 2):
|
||||||
switch("hint", "XCannotRaiseY:off")
|
switch("hint", "XCannotRaiseY:off")
|
||||||
|
# begin Nimble config (version 2)
|
||||||
|
when withDir(thisDir(), system.fileExists("nimble.paths")):
|
||||||
|
include "nimble.paths"
|
||||||
|
# end Nimble config
|
||||||
|
|
|
@ -46,13 +46,10 @@ type
|
||||||
ds: Datastore
|
ds: Datastore
|
||||||
semaphore: AsyncSemaphore # semaphore is used for backpressure \
|
semaphore: AsyncSemaphore # semaphore is used for backpressure \
|
||||||
# to avoid exhausting file descriptors
|
# to avoid exhausting file descriptors
|
||||||
case withLocks: bool
|
withLocks: bool
|
||||||
of true:
|
|
||||||
tasks: Table[Key, Future[void]]
|
tasks: Table[Key, Future[void]]
|
||||||
queryLock: AsyncLock # global query lock, this is only really \
|
queryLock: AsyncLock # global query lock, this is only really \
|
||||||
# needed for the fsds, but it is expensive!
|
# needed for the fsds, but it is expensive!
|
||||||
else:
|
|
||||||
futs: seq[Future[void]] # keep a list of the futures to the signals around
|
|
||||||
|
|
||||||
template withLocks(
|
template withLocks(
|
||||||
self: ThreadDatastore,
|
self: ThreadDatastore,
|
||||||
|
@ -61,27 +58,21 @@ template withLocks(
|
||||||
fut: Future[void],
|
fut: Future[void],
|
||||||
body: untyped) =
|
body: untyped) =
|
||||||
try:
|
try:
|
||||||
case self.withLocks:
|
if key.isSome and key.get in self.tasks:
|
||||||
of true:
|
if self.withLocks:
|
||||||
if key.isSome and
|
|
||||||
key.get in self.tasks:
|
|
||||||
await self.tasks[key.get]
|
await self.tasks[key.get]
|
||||||
await self.queryLock.acquire() # lock query or wait to finish
|
self.tasks[key.get] = fut # we alway want to store the future, but only await if we're using locks
|
||||||
|
|
||||||
self.tasks[key.get] = fut
|
if self.withLocks:
|
||||||
else:
|
await self.queryLock.acquire() # only lock if it's required (fsds)
|
||||||
self.futs.add(fut)
|
|
||||||
|
|
||||||
body
|
body
|
||||||
finally:
|
finally:
|
||||||
case self.withLocks:
|
if self.withLocks:
|
||||||
of true:
|
if key.isSome and key.get in self.tasks:
|
||||||
if key.isSome:
|
|
||||||
self.tasks.del(key.get)
|
self.tasks.del(key.get)
|
||||||
if self.queryLock.locked:
|
if self.queryLock.locked:
|
||||||
self.queryLock.release()
|
self.queryLock.release()
|
||||||
else:
|
|
||||||
self.futs.keepItIf(it != fut)
|
|
||||||
|
|
||||||
template dispatchTask(
|
template dispatchTask(
|
||||||
self: ThreadDatastore,
|
self: ThreadDatastore,
|
||||||
|
@ -359,13 +350,8 @@ method get*(
|
||||||
return success(@(res.get()))
|
return success(@(res.get()))
|
||||||
|
|
||||||
method close*(self: ThreadDatastore): Future[?!void] {.async.} =
|
method close*(self: ThreadDatastore): Future[?!void] {.async.} =
|
||||||
var futs = if self.withLocks:
|
for fut in self.tasks.values.toSeq:
|
||||||
self.tasks.values.toSeq # toSeq(...) doesn't work here???
|
await fut.cancelAndWait() # probably want to store the signal, instead of the future (or both?)
|
||||||
else:
|
|
||||||
self.futs
|
|
||||||
|
|
||||||
for fut in futs:
|
|
||||||
await fut.cancelAndWait()
|
|
||||||
|
|
||||||
await self.ds.close()
|
await self.ds.close()
|
||||||
|
|
||||||
|
@ -418,18 +404,9 @@ method query*(
|
||||||
defer:
|
defer:
|
||||||
locked = false
|
locked = false
|
||||||
self.semaphore.release()
|
self.semaphore.release()
|
||||||
case self.withLocks:
|
|
||||||
of true:
|
|
||||||
if self.queryLock.locked:
|
|
||||||
self.queryLock.release()
|
|
||||||
else:
|
|
||||||
discard
|
|
||||||
|
|
||||||
trace "About to query"
|
trace "About to query"
|
||||||
await self.semaphore.acquire()
|
await self.semaphore.acquire()
|
||||||
if self.withLocks:
|
|
||||||
await self.queryLock.acquire()
|
|
||||||
|
|
||||||
if locked:
|
if locked:
|
||||||
return failure (ref DatastoreError)(msg: "Should always await query features")
|
return failure (ref DatastoreError)(msg: "Should always await query features")
|
||||||
|
|
||||||
|
|
|
@ -21,47 +21,49 @@ import pkg/datastore/threads/threadproxyds {.all.}
|
||||||
import ./dscommontests
|
import ./dscommontests
|
||||||
import ./querycommontests
|
import ./querycommontests
|
||||||
|
|
||||||
suite "Test Basic ThreadDatastore with SQLite":
|
const NumThreads = 200 # IO threads aren't attached to CPU count
|
||||||
|
|
||||||
var
|
# suite "Test Basic ThreadDatastore with SQLite":
|
||||||
sqlStore: Datastore
|
|
||||||
ds: ThreadDatastore
|
|
||||||
taskPool: Taskpool
|
|
||||||
key = Key.init("/a/b").tryGet()
|
|
||||||
bytes = "some bytes".toBytes
|
|
||||||
otherBytes = "some other bytes".toBytes
|
|
||||||
|
|
||||||
setupAll:
|
# var
|
||||||
sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
# sqlStore: Datastore
|
||||||
taskPool = Taskpool.new(countProcessors() * 2)
|
# ds: ThreadDatastore
|
||||||
ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
# taskPool: Taskpool
|
||||||
|
# key = Key.init("/a/b").tryGet()
|
||||||
|
# bytes = "some bytes".toBytes
|
||||||
|
# otherBytes = "some other bytes".toBytes
|
||||||
|
|
||||||
teardownAll:
|
# setupAll:
|
||||||
(await ds.close()).tryGet()
|
# sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
||||||
taskPool.shutdown()
|
# taskPool = Taskpool.new(NumThreads)
|
||||||
|
# ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
||||||
|
|
||||||
basicStoreTests(ds, key, bytes, otherBytes)
|
# teardownAll:
|
||||||
|
# (await ds.close()).tryGet()
|
||||||
|
# taskPool.shutdown()
|
||||||
|
|
||||||
suite "Test Query ThreadDatastore with SQLite":
|
# basicStoreTests(ds, key, bytes, otherBytes)
|
||||||
|
|
||||||
var
|
# suite "Test Query ThreadDatastore with SQLite":
|
||||||
sqlStore: Datastore
|
|
||||||
ds: ThreadDatastore
|
|
||||||
taskPool: Taskpool
|
|
||||||
key = Key.init("/a/b").tryGet()
|
|
||||||
bytes = "some bytes".toBytes
|
|
||||||
otherBytes = "some other bytes".toBytes
|
|
||||||
|
|
||||||
setup:
|
# var
|
||||||
sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
# sqlStore: Datastore
|
||||||
taskPool = Taskpool.new(countProcessors() * 2)
|
# ds: ThreadDatastore
|
||||||
ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
# taskPool: Taskpool
|
||||||
|
# key = Key.init("/a/b").tryGet()
|
||||||
|
# bytes = "some bytes".toBytes
|
||||||
|
# otherBytes = "some other bytes".toBytes
|
||||||
|
|
||||||
teardown:
|
# setup:
|
||||||
(await ds.close()).tryGet()
|
# sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
||||||
taskPool.shutdown()
|
# taskPool = Taskpool.new(NumThreads)
|
||||||
|
# ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
||||||
|
|
||||||
queryTests(ds, true)
|
# teardown:
|
||||||
|
# (await ds.close()).tryGet()
|
||||||
|
# taskPool.shutdown()
|
||||||
|
|
||||||
|
# queryTests(ds, true)
|
||||||
|
|
||||||
suite "Test Basic ThreadDatastore with fsds":
|
suite "Test Basic ThreadDatastore with fsds":
|
||||||
let
|
let
|
||||||
|
@ -83,7 +85,7 @@ suite "Test Basic ThreadDatastore with fsds":
|
||||||
createDir(basePathAbs)
|
createDir(basePathAbs)
|
||||||
|
|
||||||
fsStore = FSDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
fsStore = FSDatastore.new(root = basePathAbs, depth = 3).tryGet()
|
||||||
taskPool = Taskpool.new(countProcessors() * 2)
|
taskPool = Taskpool.new(NumThreads)
|
||||||
ds = ThreadDatastore.new(fsStore, withLocks = true, tp = taskPool).tryGet()
|
ds = ThreadDatastore.new(fsStore, withLocks = true, tp = taskPool).tryGet()
|
||||||
|
|
||||||
teardownAll:
|
teardownAll:
|
||||||
|
@ -112,7 +114,7 @@ suite "Test Query ThreadDatastore with fsds":
|
||||||
createDir(basePathAbs)
|
createDir(basePathAbs)
|
||||||
|
|
||||||
fsStore = FSDatastore.new(root = basePathAbs, depth = 5).tryGet()
|
fsStore = FSDatastore.new(root = basePathAbs, depth = 5).tryGet()
|
||||||
taskPool = Taskpool.new(countProcessors() * 2)
|
taskPool = Taskpool.new(NumThreads)
|
||||||
ds = ThreadDatastore.new(fsStore, withLocks = true, tp = taskPool).tryGet()
|
ds = ThreadDatastore.new(fsStore, withLocks = true, tp = taskPool).tryGet()
|
||||||
|
|
||||||
teardown:
|
teardown:
|
||||||
|
@ -138,7 +140,7 @@ suite "Test ThreadDatastore cancelations":
|
||||||
|
|
||||||
setupAll:
|
setupAll:
|
||||||
sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
sqlStore = SQLiteDatastore.new(Memory).tryGet()
|
||||||
taskPool = Taskpool.new(countProcessors() * 2)
|
taskPool = Taskpool.new(NumThreads)
|
||||||
ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
ds = ThreadDatastore.new(sqlStore, tp = taskPool).tryGet()
|
||||||
|
|
||||||
test "Should monitor signal and cancel":
|
test "Should monitor signal and cancel":
|
||||||
|
|
Loading…
Reference in New Issue