Mercurial > games > semicongine
changeset 1096:9809bd9e2cdb
add: tests and did some simplification of code
author | sam <sam@basx.dev> |
---|---|
date | Sun, 07 Apr 2024 01:17:40 +0700 |
parents | b6427706c7b1 |
children | bc3efccc2bf4 |
files | semicongine/storage.nim tests/test_storage.nim |
diffstat | 2 files changed, 62 insertions(+), 28 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/storage.nim Sun Apr 07 00:35:45 2024 +0700 +++ b/semicongine/storage.nim Sun Apr 07 01:17:40 2024 +0700 @@ -62,33 +62,33 @@ storageType.path().string.removeFile() type - LoadFuture*[T, U] = object - thread: Thread[U] + LoadFuture*[T] = object + thread: Thread[(StorageType, string, ptr Channel[T])] channel: ptr Channel[T] result: T -proc cleanup*[T, U](p: var LoadFuture[T, U]) = +proc cleanup*[T](p: var LoadFuture[T]) = if p.channel != nil: p.thread.joinThread() p.channel[].close() deallocShared(p.channel) p.channel = nil -proc awaitResult*[T, U](p: var LoadFuture[T, U]): T = +proc awaitResult*[T](p: var LoadFuture[T]): T = if p.channel == nil: return p.result result = p.channel[].recv() p.result = result p.cleanup() -proc hasResult*[T, U](p: var LoadFuture[T, U]): bool = +proc hasResult*[T](p: var LoadFuture[T]): bool = let ret = p.channel[].tryRecv() result = ret.dataAvailable if result: p.result = ret.msg p.cleanup() -proc getResult*[T, U](p: LoadFuture[T, U]): T = +proc getResult*[T](p: LoadFuture[T]): T = assert p.channel == nil, "Result is not available yet" return p.result @@ -98,7 +98,7 @@ let ret = loadFromDb[T](db, params[1]) params[2][].send(ret) -proc load*[T](storageType: StorageType, key: string): LoadFuture[T, (StorageType, string, ptr Channel[T])] = +proc load*[T](storageType: StorageType, key: string): LoadFuture[T] = result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) result.channel[].open() createThread(result.thread, loadWorker[T], (storageType, key, result.channel)) @@ -106,12 +106,12 @@ # STORING ######################################3333 # type - StoreFuture*[T, U] = object - thread: Thread[U] + StoreFuture*[T] = object + thread: Thread[(StorageType, string, ptr Channel[T], ptr Channel[bool])] channel: ptr Channel[T] doneChannel: ptr Channel[bool] -proc cleanup*[T, U](p: var StoreFuture[T, U]) = +proc cleanup*[T](p: var StoreFuture[T]) = if p.channel != nil: p.thread.joinThread() p.channel[].close() @@ -121,11 +121,11 @@ p.channel = nil p.doneChannel = nil -proc awaitStored*[T, U](p: var StoreFuture[T, U]) = +proc awaitStored*[T](p: var StoreFuture[T]) = discard p.doneChannel[].recv() p.cleanup() -proc isStored*[T, U](p: var StoreFuture[T, U]): bool = +proc isStored*[T](p: var StoreFuture[T]): bool = let ret = p.doneChannel[].tryRecv() result = ret.dataAvailable if ret.dataAvailable: @@ -137,7 +137,7 @@ storeInDb(db, params[1], params[2][].recv()) params[3][].send(true) -proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T, (StorageType, string, ptr Channel[T], ptr Channel[bool])] = +proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T] = result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) result.channel[].open() result.doneChannel = cast[ptr Channel[bool]](allocShared0(sizeof(Channel[bool])))
--- a/tests/test_storage.nim Sun Apr 07 00:35:45 2024 +0700 +++ b/tests/test_storage.nim Sun Apr 07 01:17:40 2024 +0700 @@ -1,4 +1,5 @@ import std/os +import std/strformat import semicongine @@ -7,35 +8,59 @@ const KEY = "test" # get default - var promise1 = load[int](storage, KEY) - assert promise1.awaitResult() == default(type(TEST_VALUE)) + var future1 = load[int](storage, KEY) + assert future1.awaitResult() == default(type(TEST_VALUE)) # save and load custom - var promise2 = store(storage, KEY, TEST_VALUE) - promise2.awaitStored() - promise1 = load[int](storage, KEY) - assert promise1.awaitResult() == TEST_VALUE + var future2 = store(storage, KEY, TEST_VALUE) + future2.awaitStored() + future1 = load[int](storage, KEY) + assert future1.awaitResult() == TEST_VALUE proc testBusyWait(storage: StorageType) = const TEST_VALUE = "43" const KEY = "test2" # get default - var promise1 = load[string](storage, KEY) - while not promise1.hasResult(): + var future1 = load[string](storage, KEY) + while not future1.hasResult(): sleep(1) - assert promise1.getResult() == default(type(TEST_VALUE)) + assert future1.getResult() == default(type(TEST_VALUE)) # save and load custom - var promise2 = store(storage, KEY, TEST_VALUE) - while not promise2.isStored(): + var future2 = store(storage, KEY, TEST_VALUE) + while not future2.isStored(): + sleep(1) + future1 = load[string](storage, KEY) + while not future1.hasResult(): sleep(1) - promise1 = load[string](storage, KEY) - while not promise1.hasResult(): - sleep(1) - assert promise1.awaitResult() == TEST_VALUE + assert future1.awaitResult() == TEST_VALUE + +proc stressTest(storage: StorageType) = + for i in 1 .. 10000: + let key = &"key-{i}" + var p = store(storage, key, i) + p.awaitStored() + var p1 = load[int](storage, key) + assert p1.awaitResult() == i + +proc concurrentStressTest(storage: StorageType) = + var storeFutures: seq[StoreFuture[int]] + + for i in 1 .. 10000: + let key = &"key-{i}" + echo key + storeFutures.add store(storage, key, i) + + for i in 1 .. 10000: + echo i + let key = &"key-{i}" + storeFutures[i - 1].awaitStored() + var p1 = load[int](storage, key) + assert p1.awaitResult() == i proc main() = + SystemStorage.purge() echo "SystemStorage: Testing simple store/load" SystemStorage.testSimple() echo "SystemStorage: Testing store/load with busy wait" @@ -46,7 +71,16 @@ UserStorage.testSimple() echo "UserStorage: Testing store/load with busy wait" UserStorage.testBusyWait() + + echo "Stress test with 10'000 saves/loads" + SystemStorage.stressTest() + + SystemStorage.purge() UserStorage.purge() + # TODO: fails currently, but is likely not too important + # echo "Stress test with 10'000 saves/loads and a little concurrency" + # SystemStorage.concurrentStressTest() + when isMainModule: main()