logos-storage-nim/tests/codex/stores/testrepostore.nim
Dmitriy Ryajov 0beeefd760
Repo limits (#319)
* initial implementation of repo store

* allow isManifest on multicodec

* rework with new blockstore

* add raw codec

* rework listBlocks

* remove fsstore

* reworking with repostore

* bump datastore

* fix listBlocks iterator

* adding store's common tests

* run common store tests

* remove fsstore backend tests

* bump datastore

* add `listBlocks` tests

* listBlocks filter based on block type

* disabling tests in need of rewriting

* allow passing block type

* move BlockNotFoundError definition

* fix tests

* increase default advertise loop sleep to 10 mins

* use `self`

* add cache quota functionality

* pass meta store and start repo

* add `CacheQuotaNamespace`

* pass meta store

* bump datastore to latest master

* don't use os `/` as key separator

* Added quota limits support

* tests for quota limits

* add block expiration key

* remove unnesesary space

* use idleAsync in listBlocks

* proper test name

* re-add contrlC try/except

* add storage quota and block ttl config options

* clarify comments

* change expires key format

* check for block presence before storing

* bump datastore

* use dht with fixed datastore `has`

* bump datastore to latest master

* bump dht to latest master
2022-12-02 18:00:55 -06:00

171 lines
4.3 KiB
Nim

import std/os
import std/options
import std/strutils
import pkg/questionable
import pkg/questionable/results
import pkg/chronos
import pkg/asynctest
import pkg/libp2p
import pkg/stew/byteutils
import pkg/stew/endians2
import pkg/datastore
import pkg/codex/stores/cachestore
import pkg/codex/chunker
import pkg/codex/stores
import pkg/codex/blocktype as bt
import ../helpers
import ./commonstoretests
suite "Test RepoStore Quota":
var
repoDs: Datastore
metaDs: Datastore
setup:
repoDs = SQLiteDatastore.new(Memory).tryGet()
metaDs = SQLiteDatastore.new(Memory).tryGet()
teardown:
(await repoDs.close()).tryGet
(await metaDs.close()).tryGet
test "Should update current used bytes on block put":
let
blk = bt.Block.new('a'.repeat(100).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 100)
check repo.quotaUsedBytes == 0
(await repo.putBlock(blk)).tryGet
check:
repo.quotaUsedBytes == 100
uint64.fromBytesBE((await metaDs.get(QuotaUsedKey)).tryGet) == 100'u
test "Should update current used bytes on block delete":
let
blk = bt.Block.new('a'.repeat(100).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 100)
check repo.quotaUsedBytes == 0
(await repo.putBlock(blk)).tryGet
check repo.quotaUsedBytes == 100
(await repo.delBlock(blk.cid)).tryGet
check:
repo.quotaUsedBytes == 0
uint64.fromBytesBE((await metaDs.get(QuotaUsedKey)).tryGet) == 0'u
test "Should fail storing passed the quota":
let
blk = bt.Block.new('a'.repeat(200).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 100)
check repo.totalUsed == 0
expect QuotaUsedError:
(await repo.putBlock(blk)).tryGet
test "Should reserve bytes":
let
blk = bt.Block.new('a'.repeat(100).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 200)
check repo.totalUsed == 0
(await repo.putBlock(blk)).tryGet
check repo.totalUsed == 100
(await repo.reserve(100)).tryGet
check:
repo.totalUsed == 200
repo.quotaUsedBytes == 100
repo.quotaReservedBytes == 100
uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 100'u
test "Should not reserve bytes over max quota":
let
blk = bt.Block.new('a'.repeat(100).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 200)
check repo.totalUsed == 0
(await repo.putBlock(blk)).tryGet
check repo.totalUsed == 100
expect QuotaNotEnoughError:
(await repo.reserve(101)).tryGet
check:
repo.totalUsed == 100
repo.quotaUsedBytes == 100
repo.quotaReservedBytes == 0
expect DatastoreKeyNotFound:
discard (await metaDs.get(QuotaReservedKey)).tryGet
test "Should release bytes":
let
blk = bt.Block.new('a'.repeat(100).toBytes).tryGet()
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 200)
check repo.totalUsed == 0
(await repo.reserve(100)).tryGet
check repo.totalUsed == 100
(await repo.release(100)).tryGet
check:
repo.totalUsed == 0
repo.quotaUsedBytes == 0
repo.quotaReservedBytes == 0
uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 0'u
test "Should not release bytes less than quota":
let
repo = RepoStore.new(repoDs, metaDs, quotaMaxBytes = 200)
check repo.totalUsed == 0
(await repo.reserve(100)).tryGet
check repo.totalUsed == 100
expect CatchableError:
(await repo.release(101)).tryGet
check:
repo.totalUsed == 100
repo.quotaUsedBytes == 0
repo.quotaReservedBytes == 100
uint64.fromBytesBE((await metaDs.get(QuotaReservedKey)).tryGet) == 100'u
commonBlockStoreTests(
"RepoStore Sql backend", proc: BlockStore =
BlockStore(
RepoStore.new(
SQLiteDatastore.new(Memory).tryGet(),
SQLiteDatastore.new(Memory).tryGet())))
const
path = currentSourcePath().parentDir / "test"
proc before() {.async.} =
createDir(path)
proc after() {.async.} =
removeDir(path)
let
depth = path.split(DirSep).len
commonBlockStoreTests(
"RepoStore FS backend", proc: BlockStore =
BlockStore(
RepoStore.new(
FSDatastore.new(path, depth).tryGet(),
SQLiteDatastore.new(Memory).tryGet())),
before = before,
after = after)