add some more docs - design notes
This commit is contained in:
parent
db25ded557
commit
a40c1b23bb
|
@ -20,6 +20,38 @@ export threadresults
|
||||||
|
|
||||||
push: {.upraises: [].}
|
push: {.upraises: [].}
|
||||||
|
|
||||||
|
## Design Notes
|
||||||
|
## ============
|
||||||
|
## This is the threaded backend for `threadproxyds.nim`. It requires
|
||||||
|
## a `TResult[T]` to already be allocated, and uses it to "return"
|
||||||
|
## the data. The `taskpools` worker uses `TResult[T]` to signal
|
||||||
|
## Chronos that the associated future is ready. Then the future on the
|
||||||
|
## `threadproxyds` frontend can read the results from `TResult[T]`.
|
||||||
|
##
|
||||||
|
## `TResult[T]` handles the shared memory aspect so each threaded
|
||||||
|
## task here can rely on having the memory until it finishes it's
|
||||||
|
## work. Even if the future exits early, the thread workers won't
|
||||||
|
## need to worry about using free-ed memory.
|
||||||
|
##
|
||||||
|
## The `FlowVar[T]` in `taskpools` isn't really suitable because
|
||||||
|
## we want to use Chronos's `ThreadSignalPtr` notification mechanism.
|
||||||
|
## Likewise the signaling mechanism in `taskpools` isn't suitable
|
||||||
|
## for the same reason. We need to notify Chronos when our work
|
||||||
|
## is done.
|
||||||
|
##
|
||||||
|
##
|
||||||
|
## Potential Issues
|
||||||
|
## ================
|
||||||
|
## One issue still outstanding with this setup and using a
|
||||||
|
## ThreadSignalPtr pool is if `threadproxyds` frontend called
|
||||||
|
## `tresult.release()` early due to a `myFuture.cancel()` scenario.
|
||||||
|
## In this case the task here would then fire `tresult[].signal.fireAsync()`.
|
||||||
|
## If another `threadproxyds` had gotten that same ThreadSignalPtr it'd
|
||||||
|
## potentially get the signal. In this case the `TResult` would still be empty.
|
||||||
|
## It shouldn't corrupt memory, but the `threadproxyds` TResult would return "empty".
|
||||||
|
##
|
||||||
|
##
|
||||||
|
|
||||||
type
|
type
|
||||||
ThreadDatastore* = object
|
ThreadDatastore* = object
|
||||||
tp*: Taskpool
|
tp*: Taskpool
|
||||||
|
|
|
@ -30,9 +30,13 @@ type
|
||||||
## memory allocated until all references to it are gone.
|
## memory allocated until all references to it are gone.
|
||||||
##
|
##
|
||||||
## Important:
|
## Important:
|
||||||
## On `refc` that internal destructors for ThreadResult[T]
|
## On `refc` that "internal" destructors for ThreadResult[T]
|
||||||
## are *not* called. Effectively limiting this to 1 depth
|
## are *not* called. Effectively limiting this to 1 depth
|
||||||
## of destructors. Hence the `threadSafeType` marker below.
|
## of destructors. Hence the `threadSafeType` marker below.
|
||||||
|
##
|
||||||
|
## Edit: not sure this is quire accurate, but some care
|
||||||
|
## needs to be taken to verify the destructor
|
||||||
|
## works with the specific type.
|
||||||
##
|
##
|
||||||
## Since ThreadResult is a plain object, its lifetime can be
|
## Since ThreadResult is a plain object, its lifetime can be
|
||||||
## tied to that of an async proc. In this case it could be
|
## tied to that of an async proc. In this case it could be
|
||||||
|
|
|
@ -39,8 +39,16 @@ proc getThreadSignal*(): Future[ThreadSignalPtr] {.async, raises: [].} =
|
||||||
## processes IO descriptor limit, which results in bad
|
## processes IO descriptor limit, which results in bad
|
||||||
## and unpredictable failure modes.
|
## and unpredictable failure modes.
|
||||||
##
|
##
|
||||||
## This could be put onto its own thread and use it's own set ThreadSignalPtr,
|
## This could be put onto its own thread and use it's own set ThreadSignalPtr
|
||||||
## but the sleepAsync should prove if this is useful for not.
|
## to become a true "resource pool".
|
||||||
|
## For now the sleepAsync should prove if this setup is useful
|
||||||
|
## or not before going into that effort.
|
||||||
|
##
|
||||||
|
## TLDR: if all ThreadSignalPtr's are used up, this will
|
||||||
|
## repetedly call `sleepAsync` deferring whatever request
|
||||||
|
## is until more ThreadSignalPtr's are available. This
|
||||||
|
## design isn't particularly fair, but should let us handle
|
||||||
|
## periods of overloads with lots of requests in flight.
|
||||||
##
|
##
|
||||||
{.cast(gcsafe).}:
|
{.cast(gcsafe).}:
|
||||||
var cnt = SignalPoolRetries
|
var cnt = SignalPoolRetries
|
||||||
|
|
|
@ -16,7 +16,6 @@ import ./querycommontests
|
||||||
|
|
||||||
# import pretty
|
# import pretty
|
||||||
|
|
||||||
|
|
||||||
suite "Test Basic ThreadProxyDatastore":
|
suite "Test Basic ThreadProxyDatastore":
|
||||||
var
|
var
|
||||||
sds: ThreadProxyDatastore
|
sds: ThreadProxyDatastore
|
||||||
|
|
Loading…
Reference in New Issue