fix(3393): Ensure channel deletions are honored - #3401
Conversation
| @@ -87,17 +93,23 @@ const Index = | |||
| for await (const entry of log.traverse(null, shoudStopTraverse)) { | |||
| const { hash, payload } = entry | |||
| // If an entry is not yet indexed, process it | |||
| if (await isNotIndexed(hash)) { | |||
| const isHashNotIndexed = await isNotIndexed(hash) | |||
| if (isHashNotIndexed) { | |||
| const { op, key } = payload | |||
| const isValid = validateFn ? await validateFn(entry) : true | |||
| if (op === 'PUT' && !keys.has(key) && isValid) { | |||
| keys.add(key) | |||
| await index.put(key as string, encodeEntry(entry)) | |||
| if (op === OrbitDbOp.PUT && isValid) { | |||
| const isKeyDeleted = await isDeleted(key!) | |||
| if (!keys.has(key) && !isKeyDeleted) { | |||
| keys.add(key) | |||
| await index.put(key as string, encodeEntry(entry)) | |||
| await indexedKeysWithOp.put(key as string, OrbitDbOp.PUT) | |||
| } | |||
| await indexedEntries.put(hash, true) | |||
| } else if (op === 'DEL' && !keys.has(key) && isValid) { | |||
| } else if (op === OrbitDbOp.DEL && isValid) { | |||
| keys.add(key) | |||
| await index.del(key as string) | |||
| await indexedEntries.put(hash, true) | |||
| await indexedKeysWithOp.put(key as string, OrbitDbOp.DEL) | |||
There was a problem hiding this comment.
This is the fix. Basically when the deletions were processed we would skip over marking the put hashes as indexed and that resulted in future reindexing treating them as fresh puts since the check for an entry being indexed is based on the hash.
There was a problem hiding this comment.
I think there may be an issue with this though that will cause PUT("key", "old value") -> DEL ("key") -> PUT("key", "new value") to result in the key to still be indexed as deleted because we are storing the deletion of key persistently and skipping processing the new PUT because it was previously deleted. You can add
it('allows a newer PUT to recreate a deleted key', async () => {
orbitDbService = await module.resolve(OrbitDbService)
await orbitDbService.create(ipfsService.ipfsInstance!)
const store = await orbitDbService.open<KeyValueIndexedValidatedType<string>>(
`recreated-key-test-store-${Date.now()}`,
{
Database: KeyValueIndexedValidated(),
AccessController: IPFSAccessController({ write: ['*'] }),
sync: false,
}
)
await store.put('key', 'old value')
await store.del('key')
await store.put('key', 'new value')
await expect(store.get('key')).resolves.toBe('new value')
})
to the orbitdb service tests to prove this.
| @@ -87,17 +93,23 @@ const Index = | |||
| for await (const entry of log.traverse(null, shoudStopTraverse)) { | |||
| const { hash, payload } = entry | |||
| // If an entry is not yet indexed, process it | |||
| if (await isNotIndexed(hash)) { | |||
| const isHashNotIndexed = await isNotIndexed(hash) | |||
| if (isHashNotIndexed) { | |||
| const { op, key } = payload | |||
| const isValid = validateFn ? await validateFn(entry) : true | |||
| if (op === 'PUT' && !keys.has(key) && isValid) { | |||
| keys.add(key) | |||
| await index.put(key as string, encodeEntry(entry)) | |||
| if (op === OrbitDbOp.PUT && isValid) { | |||
| const isKeyDeleted = await isDeleted(key!) | |||
| if (!keys.has(key) && !isKeyDeleted) { | |||
| keys.add(key) | |||
| await index.put(key as string, encodeEntry(entry)) | |||
| await indexedKeysWithOp.put(key as string, OrbitDbOp.PUT) | |||
| } | |||
| await indexedEntries.put(hash, true) | |||
| } else if (op === 'DEL' && !keys.has(key) && isValid) { | |||
| } else if (op === OrbitDbOp.DEL && isValid) { | |||
| keys.add(key) | |||
| await index.del(key as string) | |||
| await indexedEntries.put(hash, true) | |||
| await indexedKeysWithOp.put(key as string, OrbitDbOp.DEL) | |||
There was a problem hiding this comment.
I think there may be an issue with this though that will cause PUT("key", "old value") -> DEL ("key") -> PUT("key", "new value") to result in the key to still be indexed as deleted because we are storing the deletion of key persistently and skipping processing the new PUT because it was previously deleted. You can add
it('allows a newer PUT to recreate a deleted key', async () => {
orbitDbService = await module.resolve(OrbitDbService)
await orbitDbService.create(ipfsService.ipfsInstance!)
const store = await orbitDbService.open<KeyValueIndexedValidatedType<string>>(
`recreated-key-test-store-${Date.now()}`,
{
Database: KeyValueIndexedValidated(),
AccessController: IPFSAccessController({ write: ['*'] }),
sync: false,
}
)
await store.put('key', 'old value')
await store.del('key')
await store.put('key', 'new value')
await expect(store.get('key')).resolves.toBe('new value')
})
to the orbitdb service tests to prove this.
Pull Request Checklist
(Optional) Mobile checklist
Please ensure you completed the following checks if you did any changes to the mobile package: