From 65c78aa49f2ae5855bb9df0177428a239cc3aa6f Mon Sep 17 00:00:00 2001 From: Fuxing Loh <4266087+fuxingloh@users.noreply.github.com> Date: Mon, 31 Jan 2022 19:39:58 +0800 Subject: [PATCH] chore(database): check index is modified before deleting for better performance (#733) --- .../provider.level/level.database.ts | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/src/module.database/provider.level/level.database.ts b/src/module.database/provider.level/level.database.ts index 674ef09ad..d3858c795 100644 --- a/src/module.database/provider.level/level.database.ts +++ b/src/module.database/provider.level/level.database.ts @@ -110,14 +110,24 @@ export abstract class LevelUpDatabase extends Database { } async put (mapping: ModelMapping, model: M): Promise { - // TODO(fuxingloh): check before deleting for better performance - // TODO(fuxingloh): block writing race condition - await this.delete(mapping, model.id) + const indexes = Object.values(mapping.index) + const persisted = await this.get(mapping, model.id) as M + + if (persisted !== undefined) { + // Check before deleting for better performance, only delete secondary indexes that won't be present anymore + for (const index of indexes) { + if (isIndexModified(index, persisted, model)) { + const subIndex = this.subIndex(index, index.partition.key(persisted)) + const key = index.sort !== undefined ? index.sort.key(persisted) : index.partition.key(persisted) + await subIndex.del(key) + } + } + } const subRoot = this.subRoot(mapping) await subRoot.put(model.id, model) - for (const index of Object.values(mapping.index)) { + for (const index of indexes) { const subIndex = this.subIndex(index, index.partition.key(model)) const key = index.sort !== undefined ? index.sort.key(model) : index.partition.key(model) await subIndex.put(key, model) @@ -141,6 +151,34 @@ export abstract class LevelUpDatabase extends Database { } } +/** + * Given the current persisted and soon to be overridden data, is the index we are writing to modified? + * + * If it's modified, we need to delete the previously indexed data. (delete and put) + * If it's not modified, we can just replace it via a simple put. (put) + * + * @param {ModelIndex} index to write data into + * @param {M} persisted currently persisted + * @param {M} override to be overridden with + */ +function isIndexModified (index: ModelIndex, persisted: M, override: M): boolean { + const persistedPartitionKey = index.partition.key(persisted) + const overridePartitionKey = index.partition.key(override) + + if (persistedPartitionKey !== overridePartitionKey) { + return true + } + + if (index.sort === undefined) { + return false + } + + const persistedSortKey = index.sort.key(persisted) + const overrideSortKey = index.sort.key(override) + + return persistedSortKey !== overrideSortKey +} + /** * LevelDatabase uses [Level/level](https://github.com/Level/level) with a LevelDB instances under the hood. * [Level/subleveldown](https://github.com/Level/subleveldown) is used to divide key spaces into