exper with custom sharedptr -- are we keeping a sig ref somewhere?

This commit is contained in:
Jaremy Creechley 2023-09-12 15:32:01 -07:00
parent 18b0d33ac7
commit 08c4a936ad
No known key found for this signature in database
GPG Key ID: 4E66FB67B21D3300
4 changed files with 97 additions and 78 deletions

View File

@ -32,7 +32,7 @@ method has*(
try:
has(ret, sig, self.tds, key)
await wait(sig)
wait(sig)
finally:
discard # ret.release()()
@ -47,7 +47,7 @@ method delete*(
try:
delete(ret, sig, self.tds, key)
await wait(sig)
wait(sig)
finally:
discard # ret.release()()
@ -78,7 +78,7 @@ method get*(
try:
get(ret, sig, self.tds, key)
await wait(sig)
wait(sig)
finally:
discard # ret.release()()
@ -90,13 +90,16 @@ method put*(
data: seq[byte]
): Future[?!void] {.async.} =
let (ret, sig) = await newThreadResult(void)
var ret: TResult[void]
block:
let (rets, sig) = await newThreadResult(void)
ret = rets
try:
put(ret, sig, self.tds, key, data)
await wait(sig)
finally:
discard # ret.release()()
try:
put(ret, sig, self.tds, key, data)
wait(sig)
finally:
discard # ret.release()()
return ret.convert(void)
@ -145,7 +148,7 @@ method query*(
if not iter[].it.finished:
iterWrapper.readyForNext = false
query(ret, sig, self.tds, iter)
await wait(sig)
wait(sig)
iterWrapper.readyForNext = true
# echo ""
# print "query:post: ", ret[].results

View File

@ -30,15 +30,6 @@ type
## SharedPtr that allocates a shared buffer and keeps the
## memory allocated until all references to it are gone.
##
## Important:
## On `refc` that "internal" destructors for ThreadResult[T]
## are *not* called. Effectively limiting this to 1 depth
## 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
## tied to that of an async proc. In this case it could be
## freed before the other background thread is finished.

View File

@ -77,22 +77,52 @@ proc release*(sig: ThreadSignalPtr) {.raises: [].} =
signalPoolFree.incl(sig)
# echo "free:signalPoolUsed:size: ", signalPoolUsed.len()
type
SignalObj* = object
val*: ThreadSignalPtr
SharedSignalPtr* = object
cnt: ptr int
buf*: ThreadSignalPtr
SharedSignalPtr* = SharedPtr[SignalObj] ##\
proc `=destroy`*(sig: var SignalObj) =
echo "FREE SIG! ", sig.val.pointer.repr
sig.val.release()
proc `$`*(data: SharedSignalPtr): string =
if data.buf.isNil:
result = "nil"
else:
result = data.buf.pointer.repr
proc `=destroy`*(x: var SharedSignalPtr) =
if x.buf != nil and x.cnt != nil:
let res = atomicSubFetch(x.cnt, 1, ATOMIC_ACQUIRE)
if res == 0:
# for i in 0..<x.len: `=destroy`(x.data[i])
echo "SIGNAL: FREE: ", repr x.buf.pointer, " ", x.cnt[]
deallocShared(x.buf)
deallocShared(x.cnt)
else:
echo "SIGNAL: decr: ", repr x.buf.pointer, " ", x.cnt[]
proc `=copy`*(a: var SharedSignalPtr; b: SharedSignalPtr) =
# do nothing for self-assignments:
if a.buf == b.buf: return
`=destroy`(a)
discard atomicAddFetch(b.cnt, 1, ATOMIC_RELAXED)
a.buf = b.buf
a.cnt = b.cnt
echo "SIGNAL: Copy: repr: ", b.cnt[],
" ", repr a.buf.pointer,
" ", repr b.buf.pointer
proc `incr`*(a: SharedSignalPtr) =
echo "SIGNAL: incr: ", atomicAddFetch(a.cnt, 1, ATOMIC_RELAXED)
proc newSharedSignalPtr*(): Future[SharedSignalPtr] {.async, raises: [].} =
let ts = await getThreadSignal()
return newSharedPtr(SignalObj(val: ts))
result.cnt = cast[ptr int](allocShared0(sizeof(result.cnt)))
result.buf = await getThreadSignal()
proc fireSync*(sig: SharedSignalPtr): Result[bool, string] =
sig[].val.fireSync()
template fireSync*(sig: SharedSignalPtr): untyped =
let ts: ThreadSignalPtr = sig.buf
ts.fireSync()
proc wait*(sig: SharedSignalPtr): Future[void] =
sig[].val.wait()
template wait*(sig: SharedSignalPtr): untyped =
let ts: ThreadSignalPtr = sig.buf
await ts.wait()

View File

@ -35,64 +35,59 @@ suite "Test Basic ThreadProxyDatastore":
check res1.isOk
# print "res1: ", res1
test "check get":
# echo "\n\n=== get ==="
let res2 = await sds.get(key1)
check res2.get() == data
var val = ""
for c in res2.get():
val &= char(c)
# print "get res2: ", $val
# test "check get":
# # echo "\n\n=== get ==="
# let res2 = await sds.get(key1)
# check res2.get() == data
# var val = ""
# for c in res2.get():
# val &= char(c)
# # print "get res2: ", $val
# echo "\n\n=== put cancel ==="
# # let res1 = await sds.put(key1, "value for 1".toBytes())
# let res3 = sds.put(key1, "value for 1".toBytes())
# res3.cancel()
# # print "res3: ", res3
# suite "Test Basic ThreadProxyDatastore":
suite "Test Basic ThreadProxyDatastore":
# var
# memStore: MemoryDatastore
# ds: ThreadProxyDatastore
# key = Key.init("/a/b").tryGet()
# bytes = "some bytes".toBytes
# otherBytes = "some other bytes".toBytes
var
memStore: MemoryDatastore
ds: ThreadProxyDatastore
key = Key.init("/a/b").tryGet()
bytes = "some bytes".toBytes
otherBytes = "some other bytes".toBytes
# setupAll:
# memStore = MemoryDatastore.new()
# ds = newThreadProxyDatastore(memStore).expect("should work")
setupAll:
memStore = MemoryDatastore.new()
ds = newThreadProxyDatastore(memStore).expect("should work")
# teardownAll:
# (await memStore.close()).get()
teardownAll:
(await memStore.close()).get()
# basicStoreTests(ds, key, bytes, otherBytes)
basicStoreTests(ds, key, bytes, otherBytes)
# suite "Test Query":
# var
# mem: MemoryDatastore
# sds: ThreadProxyDatastore
suite "Test Query":
var
mem: MemoryDatastore
sds: ThreadProxyDatastore
# setup:
# mem = MemoryDatastore.new()
# sds = newThreadProxyDatastore(mem).expect("should work")
setup:
mem = MemoryDatastore.new()
sds = newThreadProxyDatastore(mem).expect("should work")
# queryTests(sds, false)
queryTests(sds, false)
# test "query iter fails":
test "query iter fails":
# expect FutureDefect:
# let q = Query.init(key1)
expect FutureDefect:
let q = Query.init(key1)
# (await sds.put(key1, val1)).tryGet
# (await sds.put(key2, val2)).tryGet
# (await sds.put(key3, val3)).tryGet
(await sds.put(key1, val1)).tryGet
(await sds.put(key2, val2)).tryGet
(await sds.put(key3, val3)).tryGet
let
iter = (await sds.query(q)).tryGet
res = (await allFinished(toSeq(iter)))
.mapIt( it.read.tryGet )
.filterIt( it.key.isSome )
# let
# iter = (await sds.query(q)).tryGet
# res = (await allFinished(toSeq(iter)))
# .mapIt( it.read.tryGet )
# .filterIt( it.key.isSome )
check res.len() > 0
# check res.len() > 0