mirror of
https://github.com/status-im/nim-codex.git
synced 2025-02-12 18:56:36 +00:00
feat(codex-node): add dataset deletion API to Codex node
This commit is contained in:
parent
54d499be41
commit
c71c8dffed
@ -267,6 +267,59 @@ proc retrieve*(
|
||||
|
||||
await self.streamEntireDataset(manifest, cid)
|
||||
|
||||
proc deleteSingleBlock(self: CodexNodeRef, cid: Cid): Future[?!void] {.async.} =
|
||||
if err =? (await self.networkStore.delBlock(cid)).errorOption:
|
||||
error "Error deleting block", cid, err = err.msg
|
||||
return failure(err)
|
||||
|
||||
trace "Deleted block", cid
|
||||
return success()
|
||||
|
||||
proc deleteEntireDataset(self: CodexNodeRef, cid: Cid): Future[?!void] {.async.} =
|
||||
# Deletion is a strictly local operation
|
||||
var store = self.networkStore.localStore
|
||||
|
||||
if not (await cid in store):
|
||||
return failure("Dataset's manifest is not available locally - nothing to delete")
|
||||
|
||||
without manifestBlock =? await store.getBlock(cid), err:
|
||||
return failure(err)
|
||||
|
||||
without manifest =? Manifest.decode(manifestBlock), err:
|
||||
return failure(err)
|
||||
|
||||
for i in 0 ..< manifest.blocksCount:
|
||||
if err =? (await store.delBlock(manifest.treeCid, i)).errorOption:
|
||||
# The contract for delBlock is fuzzy, but we assume that if the block is
|
||||
# simply missing we won't get an error. This is a best effort operation and
|
||||
# can simply be retried.
|
||||
error "Failed to delete block within dataset", index = i, err = err.msg
|
||||
return failure(err)
|
||||
|
||||
if err =? (await store.delBlock(cid)).errorOption:
|
||||
error "Error deleting manifest block", err = err.msg
|
||||
|
||||
success()
|
||||
|
||||
proc delete*(
|
||||
self: CodexNodeRef, cid: Cid
|
||||
): Future[?!void] {.async: (raises: [CatchableError]).} =
|
||||
## Deletes a whole dataset, if Cid is a Manifest Cid, or a single block, if Cid a block Cid,
|
||||
## from the underlying block store. This is a strictly local operation.
|
||||
##
|
||||
## Missing blocks in dataset deletes are ignored.
|
||||
##
|
||||
|
||||
without isManifest =? cid.isManifest, err:
|
||||
trace "Bad content type for CID:", err = err.msg
|
||||
return failure(err)
|
||||
|
||||
if not isManifest:
|
||||
return await self.deleteSingleBlock(cid)
|
||||
|
||||
echo "dispatch to entire dataset"
|
||||
await self.deleteEntireDataset(cid)
|
||||
|
||||
proc store*(
|
||||
self: CodexNodeRef,
|
||||
stream: LPStream,
|
||||
|
@ -85,30 +85,31 @@ proc makeWantList*(
|
||||
)
|
||||
|
||||
proc storeDataGetManifest*(
|
||||
store: BlockStore, chunker: Chunker
|
||||
store: BlockStore, blocks: seq[Block]
|
||||
): Future[Manifest] {.async.} =
|
||||
var cids = newSeq[Cid]()
|
||||
|
||||
while (let chunk = await chunker.getBytes(); chunk.len > 0):
|
||||
let blk = Block.new(chunk).tryGet()
|
||||
cids.add(blk.cid)
|
||||
for blk in blocks:
|
||||
(await store.putBlock(blk)).tryGet()
|
||||
|
||||
let
|
||||
tree = CodexTree.init(cids).tryGet()
|
||||
(manifest, tree) = makeManifestAndTree(blocks).tryGet()
|
||||
treeCid = tree.rootCid.tryGet()
|
||||
manifest = Manifest.new(
|
||||
treeCid = treeCid,
|
||||
blockSize = NBytes(chunker.chunkSize),
|
||||
datasetSize = NBytes(chunker.offset),
|
||||
)
|
||||
|
||||
for i in 0 ..< tree.leavesCount:
|
||||
let proof = tree.getProof(i).tryGet()
|
||||
(await store.putCidAndProof(treeCid, i, cids[i], proof)).tryGet()
|
||||
(await store.putCidAndProof(treeCid, i, blocks[i].cid, proof)).tryGet()
|
||||
|
||||
return manifest
|
||||
|
||||
proc storeDataGetManifest*(
|
||||
store: BlockStore, chunker: Chunker
|
||||
): Future[Manifest] {.async.} =
|
||||
var blocks = newSeq[Block]()
|
||||
|
||||
while (let chunk = await chunker.getBytes(); chunk.len > 0):
|
||||
blocks.add(Block.new(chunk).tryGet())
|
||||
|
||||
return await storeDataGetManifest(store, blocks)
|
||||
|
||||
proc makeRandomBlocks*(
|
||||
datasetSize: int, blockSize: NBytes
|
||||
): Future[seq[Block]] {.async.} =
|
||||
|
@ -37,6 +37,7 @@ import ../examples
|
||||
import ../helpers
|
||||
import ../helpers/mockmarket
|
||||
import ../helpers/mockclock
|
||||
import ../slots/helpers
|
||||
|
||||
import ./helpers
|
||||
|
||||
@ -166,3 +167,28 @@ asyncchecksuite "Test Node - Basic":
|
||||
(await verifiableBlock.cid in localStore) == true
|
||||
request.content.cid == $verifiableBlock.cid
|
||||
request.content.merkleRoot == builder.verifyRoot.get.toBytes
|
||||
|
||||
test "Should delete a single block":
|
||||
let randomBlock = bt.Block.new("Random block".toBytes).tryGet()
|
||||
(await localStore.putBlock(randomBlock)).tryGet()
|
||||
check (await randomBlock.cid in localStore) == true
|
||||
|
||||
(await node.delete(randomBlock.cid)).tryGet()
|
||||
check (await randomBlock.cid in localStore) == false
|
||||
|
||||
test "Should delete an entire dataset":
|
||||
let
|
||||
blocks = await makeRandomBlocks(datasetSize = 2048, blockSize = 256'nb)
|
||||
manifest = await storeDataGetManifest(localStore, blocks)
|
||||
manifestBlock = (await store.storeManifest(manifest)).tryGet()
|
||||
manifestCid = manifestBlock.cid
|
||||
|
||||
check await manifestCid in localStore
|
||||
for blk in blocks:
|
||||
check await blk.cid in localStore
|
||||
|
||||
(await node.delete(manifestCid)).tryGet()
|
||||
|
||||
check not await manifestCid in localStore
|
||||
for blk in blocks:
|
||||
check not (await blk.cid in localStore)
|
||||
|
Loading…
x
Reference in New Issue
Block a user