Mercurial > games > semicongine
changeset 989:3e0116b5d2ed
did: undo complicated background storage API, sync is good enough for now
author | sam <sam@basx.dev> |
---|---|
date | Sun, 07 Apr 2024 21:56:43 +0700 |
parents | 46778940c1d7 |
children | 1705e005cdee |
files | semicongine/storage.nim tests/test_storage.nim |
diffstat | 2 files changed, 12 insertions(+), 161 deletions(-) [+] |
line wrap: on
line diff
--- a/semicongine/storage.nim Sun Apr 07 20:12:52 2024 +0700 +++ b/semicongine/storage.nim Sun Apr 07 21:56:43 2024 +0700 @@ -19,7 +19,6 @@ var db: Table[StorageType, DbConn] - proc path(storageType: StorageType): Path = case storageType: of SystemStorage: @@ -37,115 +36,20 @@ value TEXT NOT NULL )""")) -proc storeInDb[T](db: DbConn, key: string, value: T) = +proc store*[T](storageType: StorageType, key: string, value: T) = + storageType.setup() const KEY_VALUE_TABLE_NAME = "shelf" - db.exec(sql(&"""INSERT INTO {KEY_VALUE_TABLE_NAME} VALUES(?, ?) + db[storageType].exec(sql(&"""INSERT INTO {KEY_VALUE_TABLE_NAME} VALUES(?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value """), key, $$value) -proc loadFromDb[T](db: DbConn, key: string, default = default(T)): T = +proc load*[T](storageType: StorageType, key: string, default = default(T)): T = + storageType.setup() const KEY_VALUE_TABLE_NAME = "shelf" - let dbResult = db.getValue(sql(&"""SELECT value FROM {KEY_VALUE_TABLE_NAME} WHERE key = ? """), key) + let dbResult = db[storageType].getValue(sql(&"""SELECT value FROM {KEY_VALUE_TABLE_NAME} WHERE key = ? """), key) if dbResult == "": return default return to[T](dbResult) proc purge*(storageType: StorageType) = storageType.path().string.removeFile() - -# mini async API -# -# LOADING ######################################3333 -# -# -type - LoadFuture*[T] = object - thread: Thread[(DbConn, string, ptr Channel[T])] - channel: ptr Channel[T] - result: T - -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](p: var LoadFuture[T]): T = - if p.channel == nil: - return p.result - result = p.channel[].recv() - p.result = result - p.cleanup() - -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](p: LoadFuture[T]): T = - assert p.channel == nil, "Result is not available yet" - return p.result - -proc loadWorker[T](params: (DbConn, string, ptr Channel[T])) {.thread.} = - let ret = loadFromDb[T](params[0], params[1]) - params[2][].send(ret) - -proc load*[T](storageType: StorageType, key: string): LoadFuture[T] = - storageType.setup() - result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) - result.channel[].open() - createThread(result.thread, loadWorker[T], (db[storageType], key, result.channel)) - -# STORING ######################################3333 -# -type - StoreFuture*[T] = object - # thread: Thread[(DbConn, string, ptr Channel[T], ptr Channel[bool])] - thread: Thread[void] - channel: ptr Channel[T] - doneChannel: ptr Channel[bool] - -proc cleanup*[T](p: var StoreFuture[T]) = - if p.channel != nil: - p.thread.joinThread() - p.channel[].close() - p.doneChannel[].close() - deallocShared(p.channel) - deallocShared(p.doneChannel) - p.channel = nil - p.doneChannel = nil - -proc awaitStored*[T](p: var StoreFuture[T]) = - discard p.doneChannel[].recv() - p.cleanup() - -proc isStored*[T](p: var StoreFuture[T]): bool = - let ret = p.doneChannel[].tryRecv() - result = ret.dataAvailable - if ret.dataAvailable: - p.cleanup() - -# proc storeWorker[T](params: (DbConn, string, ptr Channel[T], ptr Channel[bool])) {.thread.} = - # storeInDb(params[0], params[1], params[2][].recv()) - # params[3][].send(true) - - -# proc store*[T](storageType: StorageType, key: string, value: T): StoreFuture[T] = - # storageType.setup() - # result.channel = cast[ptr Channel[T]](allocShared0(sizeof(Channel[T]))) - # result.channel[].open() - # result.doneChannel = cast[ptr Channel[bool]](allocShared0(sizeof(Channel[bool]))) - # result.doneChannel[].open() - # createThread(result.thread, storeWorker[T], (db[storageType], key, result.channel, result.doneChannel)) - # createThread(result.thread, storeWorker) - # result.channel[].send(value) - -proc storeWorker() {.thread.} = - echo "storeWorker" - -proc store*() = - var thread: Thread[void] - createThread(thread, storeWorker)
--- a/tests/test_storage.nim Sun Apr 07 20:12:52 2024 +0700 +++ b/tests/test_storage.nim Sun Apr 07 21:56:43 2024 +0700 @@ -3,78 +3,31 @@ import semicongine -#[ proc testSimple(storage: StorageType) = const TEST_VALUE = 42 const KEY = "test" # get default - var future1 = load[int](storage, KEY) - assert future1.awaitResult() == default(type(TEST_VALUE)) + assert load[int](storage, KEY) == default(type(TEST_VALUE)) # save and load custom - 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 future1 = load[string](storage, KEY) - while not future1.hasResult(): - sleep(1) - assert future1.getResult() == default(type(TEST_VALUE)) - - # save and load custom - var future2 = store(storage, KEY, TEST_VALUE) - while not future2.isStored(): - sleep(1) - future1 = load[string](storage, KEY) - while not future1.hasResult(): - sleep(1) - assert future1.awaitResult() == TEST_VALUE + store(storage, KEY, TEST_VALUE) + assert load[int](storage, KEY) == 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]] + store(storage, key, i) + assert load[int](storage, key) == i - for i in 1 .. 10000: - let key = &"key-{i}" - echo key - store() - # 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" - SystemStorage.testBusyWait() UserStorage.purge() echo "UserStorage: Testing simple store/load" UserStorage.testSimple() - echo "UserStorage: Testing store/load with busy wait" - UserStorage.testBusyWait() echo "Stress test with 10'000 saves/loads" SystemStorage.stressTest() @@ -82,12 +35,6 @@ 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: - echo "Stress test with 10'000 saves/loads and a little concurrency" - SystemStorage.concurrentStressTest() - # main() + main()