From a7ff543a1d78d7de3cdfb95584c3ae383978d1cb Mon Sep 17 00:00:00 2001 From: cgeek <cem.moreau@gmail.com> Date: Sun, 24 Mar 2019 13:33:13 +0100 Subject: [PATCH] [enh] WW: also persist blocks refered by WoT data --- app/lib/common-libs/filter-async.ts | 9 +++ app/lib/dto/BlockDTO.ts | 6 +- .../wotwizard/hooks/wotwizard.block.insert.ts | 69 +++++++++++++++++++ .../dump/wotwizard/wotwizard.copy.mempool.ts | 44 ++++++++---- app/modules/dump/wotwizard/wotwizard.dump.ts | 13 +++- .../dump/wotwizard/wotwizard.legacy.blocks.ts | 4 +- .../dump/wotwizard/wotwizard.new.blocks.ts | 4 +- 7 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 app/lib/common-libs/filter-async.ts create mode 100644 app/modules/dump/wotwizard/hooks/wotwizard.block.insert.ts diff --git a/app/lib/common-libs/filter-async.ts b/app/lib/common-libs/filter-async.ts new file mode 100644 index 000000000..d495d5401 --- /dev/null +++ b/app/lib/common-libs/filter-async.ts @@ -0,0 +1,9 @@ +export async function filterAsync<T>(arr: T[], filter: (t: T) => Promise<boolean>) { + const filtered: T[] = [] + await Promise.all(arr.map(async t => { + if (await filter(t)) { + filtered.push(t) + } + })) + return filtered +} \ No newline at end of file diff --git a/app/lib/dto/BlockDTO.ts b/app/lib/dto/BlockDTO.ts index e9e610ecd..1dc973b9f 100644 --- a/app/lib/dto/BlockDTO.ts +++ b/app/lib/dto/BlockDTO.ts @@ -210,7 +210,7 @@ export class BlockDTO implements Cloneable { } get blockstamp() { - return [this.number, this.getHash()].join('-') + return BlockDTO.blockstamp({ number: this.number, hash: this.getHash() }) } @MonitorExecutionTime() @@ -292,4 +292,8 @@ export class BlockDTO implements Cloneable { static getHash(block:any) { return BlockDTO.fromJSONObject(block).getHash() } + + static blockstamp(b: { number: number, hash: string }) { + return [b.number, b.hash].join('-') + } } diff --git a/app/modules/dump/wotwizard/hooks/wotwizard.block.insert.ts b/app/modules/dump/wotwizard/hooks/wotwizard.block.insert.ts new file mode 100644 index 000000000..32aba57d0 --- /dev/null +++ b/app/modules/dump/wotwizard/hooks/wotwizard.block.insert.ts @@ -0,0 +1,69 @@ +import {Server} from "../../../../../server" +import {WotWizardDAL} from "../wotwizard.init.structure" +import {DBBlock} from "../../../../lib/db/DBBlock" +import {IdentityDTO} from "../../../../lib/dto/IdentityDTO" +import {CertificationDTO} from "../../../../lib/dto/CertificationDTO" +import {MembershipDTO} from "../../../../lib/dto/MembershipDTO" +import {BlockDTO} from "../../../../lib/dto/BlockDTO" +import {wwHasBlock} from "../wotwizard.copy.mempool" +import {filterAsync} from "../../../../lib/common-libs/filter-async" +import {Underscore} from "../../../../lib/common-libs/underscore" +import {NewLogger} from "../../../../lib/logger" + +export interface WWBlockAccumulator { + accumulate(blocks: DBBlock[]): void + persist(): Promise<void> +} + +export function requiredBlocksAccumulator(server: Server, wwDAL: WotWizardDAL): WWBlockAccumulator { + + const logger = NewLogger() + const blockstamps: { [k: string]: boolean } = {} + const blockNumbers: { [k: number]: boolean } = {} + + return { + accumulate(blocks: DBBlock[]) { + blocks.forEach(b => { + b.identities.forEach(i => blockstamps[IdentityDTO.fromInline(i).buid] = true) + b.certifications.forEach(i => blockNumbers[CertificationDTO.fromInline(i).block_number] = true) + b.joiners + .concat(b.actives) + .concat(b.leavers) + .forEach(i => blockstamps[MembershipDTO.fromInline(i).blockstamp] = true) + }) + }, + + /** + * Returns the blocks that are not in WW but that requires to be because of inserted blocks containing + * interesting blockstamps (from identifies, certifications, memberships) + */ + async persist() { + const chunkLen = 250 + const numbers = Object.keys(blockNumbers).map(n => parseInt(n)) + const blocksForCertifications: (DBBlock|null)[] = [] + for (let i = 0; i < numbers.length; i += chunkLen) { + const chunk = numbers.slice(0, chunkLen) + logger.debug('Chunk %s-%s', i, i + chunkLen) + ;(await Promise.all(chunk.map(n => server.dal.getBlock(n)))) + .forEach(b => blocksForCertifications.push(b)) + } + const blocksForBlockstamps: (DBBlock|null)[] = await Promise.all( + Object + .keys(blockstamps) + .map(b => server.dal.getAbsoluteBlockByBlockstamp(b)) + ) + const reducedBlocks: { [k: string]: DBBlock } = blocksForCertifications + .concat(blocksForBlockstamps) + .reduce((acc, b) => { + if (b) { + acc[BlockDTO.blockstamp(b)] = b + } + return acc + }, {} as { [k: string]: DBBlock }) + + const blocksToInsert = await filterAsync(Object.values(reducedBlocks), (b: DBBlock) => wwHasBlock(wwDAL, b).then(b => !b)) + const blocksSorted = Underscore.sortBy(blocksToInsert, b => b.number) + await wwDAL.blockDao.insertBatch(blocksSorted.map(f => { (f as any).legacy = true; return f })) + } + } +} \ No newline at end of file diff --git a/app/modules/dump/wotwizard/wotwizard.copy.mempool.ts b/app/modules/dump/wotwizard/wotwizard.copy.mempool.ts index b8b1d4398..d598820a7 100644 --- a/app/modules/dump/wotwizard/wotwizard.copy.mempool.ts +++ b/app/modules/dump/wotwizard/wotwizard.copy.mempool.ts @@ -3,31 +3,49 @@ import {Server} from "../../../../server" import {DBBlock} from "../../../lib/db/DBBlock" import {Underscore} from "../../../lib/common-libs/underscore" import {NewLogger} from "../../../lib/logger" +import {WWBlockAccumulator} from "./hooks/wotwizard.block.insert" -export async function copyMemPool(server: Server, wwDAL: WotWizardDAL) { +export async function copyMemPool(server: Server, wwDAL: WotWizardDAL, acc: WWBlockAccumulator) { const logger = NewLogger() const identities = await server.dal.idtyDAL.sqlListAll() // Blocks on which are based identities - const blocks = await Promise.all(identities.map(async idty => { - let b = await server.dal.getAbsoluteBlockByBlockstamp(idty.buid) - if (b) { - const b2 = await wwDAL.blockDao.getAbsoluteBlock(b.number, b.hash) - if (!b2) { - return b - } - } - return null - })) - + const blocks = await Promise.all(identities.map(async idty => returnBlockIfPresentInServerButNotInWW(idty.buid, server, wwDAL))) const toPersist: DBBlock[] = Underscore.uniq(blocks.filter(b => b) as DBBlock[], false, b => [b.number, b.hash].join('-')) logger.debug('Persisting %s blocks for identities...', toPersist.length) + acc.accumulate(toPersist) await wwDAL.blockDao.insertBatch(toPersist.map(b => { (b as any).legacy = true; return b })) await wwDAL.idtyDao.insertBatch(identities) await wwDAL.certDao.insertBatch(await server.dal.certDAL.sqlListAll()) await wwDAL.msDao.insertBatch(await server.dal.msDAL.sqlListAll()) -} \ No newline at end of file +} + +/** + * Returns the server's block of given blockstamp if found in server and not found in WW + * @param blockstamp + * @param server + * @param wwDAL + */ +async function returnBlockIfPresentInServerButNotInWW(blockstamp: string, server: Server, wwDAL: WotWizardDAL) { + let b = await server.dal.getAbsoluteBlockByBlockstamp(blockstamp) + if (b) { + if (!(await wwHasBlock(wwDAL, b))) { + return b + } + } + return null +} + +/** + * Tells wether given block is found in WW database or not. + * @param wwDAL + * @param b + */ +export async function wwHasBlock(wwDAL: WotWizardDAL, b: { number: number, hash: string}) { + const wwBlock = await wwDAL.blockDao.getAbsoluteBlock(b.number, b.hash) + return !!wwBlock +} diff --git a/app/modules/dump/wotwizard/wotwizard.dump.ts b/app/modules/dump/wotwizard/wotwizard.dump.ts index 64628788e..b1e52b519 100644 --- a/app/modules/dump/wotwizard/wotwizard.dump.ts +++ b/app/modules/dump/wotwizard/wotwizard.dump.ts @@ -5,21 +5,28 @@ import {addLegacyBlocks} from "./wotwizard.legacy.blocks" import {addNewBlocks} from "./wotwizard.new.blocks" import {deleteNonLegacy} from "./wotwizard.delete" import {copyMemPool} from "./wotwizard.copy.mempool" +import {requiredBlocksAccumulator} from "./hooks/wotwizard.block.insert" export async function dumpWotWizard(server: Server) { // 1. Create dump structure if it does not exist const wwDAL = await createExportStructure(WotWizardConstants.DB_NAME) + // Prepare accumulator for blocks with data refering blocks + const accumulator = requiredBlocksAccumulator(server, wwDAL) + // 2. Integrate legacy blocks (= non-forkable) - await addLegacyBlocks(server, wwDAL) + await addLegacyBlocks(server, wwDAL, accumulator) // 3. Delete non-legacy data await deleteNonLegacy(wwDAL) // 4. Integrate new blocks (= forkable) - await addNewBlocks(server, wwDAL) + await addNewBlocks(server, wwDAL, accumulator) // 5. Copy mempool - await copyMemPool(server, wwDAL) + await copyMemPool(server, wwDAL, accumulator) + + // 6. Persist blocks referenced by a wot data (identities, certifications, memberships) + await accumulator.persist() } diff --git a/app/modules/dump/wotwizard/wotwizard.legacy.blocks.ts b/app/modules/dump/wotwizard/wotwizard.legacy.blocks.ts index 0c960e1b9..09803305a 100644 --- a/app/modules/dump/wotwizard/wotwizard.legacy.blocks.ts +++ b/app/modules/dump/wotwizard/wotwizard.legacy.blocks.ts @@ -3,8 +3,9 @@ import {Server} from "../../../../server" import {CommonConstants} from "../../../lib/common-libs/constants" import {DBBlock} from "../../../lib/db/DBBlock" import {NewLogger} from "../../../lib/logger" +import {WWBlockAccumulator} from "./hooks/wotwizard.block.insert" -export async function addLegacyBlocks(server: Server, wwDAL: WotWizardDAL) { +export async function addLegacyBlocks(server: Server, wwDAL: WotWizardDAL, acc: WWBlockAccumulator) { const logger = NewLogger() @@ -35,6 +36,7 @@ export async function addLegacyBlocks(server: Server, wwDAL: WotWizardDAL) { logger.debug('Saving blocks...') await wwDAL.blockDao.insertBatch(blocksSaved) + acc.accumulate(blocksSaved) await Promise.all(blocksSaved) diff --git a/app/modules/dump/wotwizard/wotwizard.new.blocks.ts b/app/modules/dump/wotwizard/wotwizard.new.blocks.ts index ee49905cd..38e7b7d2a 100644 --- a/app/modules/dump/wotwizard/wotwizard.new.blocks.ts +++ b/app/modules/dump/wotwizard/wotwizard.new.blocks.ts @@ -2,8 +2,9 @@ import {WotWizardDAL} from "./wotwizard.init.structure" import {Server} from "../../../../server" import {CommonConstants} from "../../../lib/common-libs/constants" import {NewLogger} from "../../../lib/logger" +import {WWBlockAccumulator} from "./hooks/wotwizard.block.insert" -export async function addNewBlocks(server: Server, wwDAL: WotWizardDAL) { +export async function addNewBlocks(server: Server, wwDAL: WotWizardDAL, acc: WWBlockAccumulator) { const logger = NewLogger() @@ -25,6 +26,7 @@ export async function addNewBlocks(server: Server, wwDAL: WotWizardDAL) { const all = blocks.concat(forks).map(f => { (f as any).legacy = false; return f }) logger.debug('Saving %s pending blocks...', all.length) blocksSaved.push(wwDAL.blockDao.insertBatch(all)) + acc.accumulate(all) } await Promise.all(blocksSaved) -- GitLab