UBERF-8069: Rework loadModel to make it faster (#6523)

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2024-09-11 15:03:54 +07:00 committed by GitHub
parent 581e00353c
commit 74c27d6dd7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 36 additions and 19 deletions

View File

@ -351,10 +351,8 @@ async function tryLoadModel (
} }
const lastTxTime = getLastTxTime(current.transactions) const lastTxTime = getLastTxTime(current.transactions)
const result = await ctx.with( const result = await ctx.with('connection-load-model', { hash: current.hash !== '' }, (ctx) =>
'connection-load-model', conn.loadModel(lastTxTime, current.hash)
{ hash: current.hash !== '' },
async (ctx) => await conn.loadModel(lastTxTime, current.hash)
) )
if (Array.isArray(result)) { if (Array.isArray(result)) {

View File

@ -29,7 +29,9 @@ import crypto from 'node:crypto'
* @public * @public
*/ */
export class ModelMiddleware extends BaseMiddleware implements Middleware { export class ModelMiddleware extends BaseMiddleware implements Middleware {
hashes!: string[] hashes!: Map<string, number> // Hash to position
lastHash: string = ''
lastHashResponse!: Promise<LoadModelResponse>
model!: Tx[] model!: Tx[]
static async create (ctx: MeasureContext, context: PipelineContext, next?: Middleware): Promise<Middleware> { static async create (ctx: MeasureContext, context: PipelineContext, next?: Middleware): Promise<Middleware> {
@ -63,35 +65,52 @@ export class ModelMiddleware extends BaseMiddleware implements Middleware {
private addModelTx (tx: Tx): void { private addModelTx (tx: Tx): void {
this.model.push(tx) this.model.push(tx)
const h = crypto.createHash('sha1') const h = crypto.createHash('sha1')
h.update(this.hashes[this.hashes.length - 1]) h.update(this.lastHash)
h.update(JSON.stringify(tx)) h.update(JSON.stringify(tx))
this.hashes.push(h.digest('hex')) const hash = h.digest('hex')
this.hashes.set(hash, this.model.length - 1)
this.setLastHash(hash)
}
private setLastHash (hash: string): void {
this.lastHash = hash
this.lastHashResponse = Promise.resolve({
full: false,
hash,
transactions: []
})
} }
private setModel (model: Tx[]): void { private setModel (model: Tx[]): void {
let prev = '' let last = ''
this.hashes = model.map((it) => { this.hashes = new Map(
model.map((it, index) => {
const h = crypto.createHash('sha1') const h = crypto.createHash('sha1')
h.update(prev) h.update(last)
h.update(JSON.stringify(it)) h.update(JSON.stringify(it))
prev = h.digest('hex') last = h.digest('hex')
return prev return [last, index]
}) })
)
this.setLastHash(last)
} }
loadModel (ctx: MeasureContext, lastModelTx: Timestamp, hash?: string): Promise<Tx[] | LoadModelResponse> { loadModel (ctx: MeasureContext, lastModelTx: Timestamp, hash?: string): Promise<Tx[] | LoadModelResponse> {
if (hash !== undefined) { if (hash !== undefined) {
const pos = this.hashes.indexOf(hash) if (hash === this.lastHash) {
if (pos >= 0) { return this.lastHashResponse
}
const pos = this.hashes.get(hash)
if (pos != null && pos >= 0) {
return Promise.resolve({ return Promise.resolve({
full: false, full: false,
hash: this.hashes[this.hashes.length - 1], hash: this.lastHash,
transactions: this.model.slice(pos + 1) transactions: this.model.slice(pos + 1)
}) })
} }
return Promise.resolve({ return Promise.resolve({
full: true, full: true,
hash: this.hashes[this.hashes.length - 1], hash: this.lastHash,
transactions: [...this.model] transactions: [...this.model]
}) })
} }