mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-11-09 17:06:13 -06:00
fix(backups): better handling of generator cleanup (#9557)
This commit is contained in:
committed by
GitHub
parent
a78870b473
commit
4e0655dc3d
@@ -48,17 +48,10 @@ export abstract class Disk {
|
||||
abstract buildDiskBlockGenerator(): Promise<AsyncGenerator<DiskBlock>> | AsyncGenerator<DiskBlock>
|
||||
async *diskBlocks(uid?: string): AsyncGenerator<DiskBlock> {
|
||||
try {
|
||||
// compute next block while the destination is consuming the current block
|
||||
const blockGenerator = await this.buildDiskBlockGenerator()
|
||||
let next = blockGenerator.next()
|
||||
while (true) {
|
||||
const res = await next
|
||||
next = blockGenerator.next()
|
||||
if (res.done) {
|
||||
break
|
||||
}
|
||||
for await (const block of blockGenerator) {
|
||||
this.#generatedDiskBlocks++
|
||||
yield res.value
|
||||
yield block
|
||||
}
|
||||
} finally {
|
||||
await this.close()
|
||||
|
||||
@@ -28,7 +28,7 @@ test('Disk class', async t => {
|
||||
disk.blocks[key] = true
|
||||
}
|
||||
const foundKeys = []
|
||||
const generator = disk.diskBlocks()
|
||||
const generator = disk.diskBlocks()
|
||||
for await (const block of generator) {
|
||||
foundKeys.push(block.index)
|
||||
assert.strictEqual(block.data.length, blockSize)
|
||||
@@ -39,4 +39,24 @@ test('Disk class', async t => {
|
||||
foundKeys.sort()
|
||||
assert.deepStrictEqual(keys, foundKeys)
|
||||
})
|
||||
|
||||
await t.test('diskBlocks calls progressHandler.done when consumer exits early', async () => {
|
||||
let doneCalled = false
|
||||
disk.progressHandler = {
|
||||
setProgress: async () => {},
|
||||
done: async () => {
|
||||
doneCalled = true
|
||||
},
|
||||
}
|
||||
disk.blocks[4] = true
|
||||
disk.blocks[5] = true
|
||||
disk.blocks[6] = true
|
||||
|
||||
// break after the first block — the inner generator's finally must still run
|
||||
for await (const _ of disk.diskBlocks()) {
|
||||
break
|
||||
}
|
||||
|
||||
assert.strictEqual(doneCalled, true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -24,12 +24,14 @@ export class ReadAhead extends RandomDiskPassthrough {
|
||||
const PRELOAD_SIZE = Math.max(Math.min(Math.floor((blockIndexes.length * maxPercent) / 100), maxNumber), 1)
|
||||
|
||||
let counter = 0
|
||||
try{
|
||||
try {
|
||||
for (const index of blockIndexes) {
|
||||
counter++
|
||||
await self.progressHandler?.setProgress(counter/ blockIndexes.length)
|
||||
await self.progressHandler?.setProgress(counter / blockIndexes.length)
|
||||
if (preloaded.length < PRELOAD_SIZE) {
|
||||
preloaded.push(self.source.readBlock(index))
|
||||
const p = self.source.readBlock(index)
|
||||
p.catch(() => {}) // suppress unhandled rejection; error still surfaces when awaited via shift()
|
||||
preloaded.push(p)
|
||||
}
|
||||
if (preloaded.length === PRELOAD_SIZE) {
|
||||
const next = (await preloaded.shift())!
|
||||
@@ -40,10 +42,11 @@ export class ReadAhead extends RandomDiskPassthrough {
|
||||
const next = (await preloaded.shift())!
|
||||
yield next
|
||||
}
|
||||
}finally{
|
||||
} finally {
|
||||
await Promise.allSettled(preloaded) // wait for in-flight I/O & release resources
|
||||
preloaded.length = 0
|
||||
await self.progressHandler?.done()
|
||||
}
|
||||
|
||||
}
|
||||
return generator()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user