Skip to content

Commit

Permalink
feat(vhd-lib): merge resume can resume when rename fails (#6530)
Browse files Browse the repository at this point in the history
  • Loading branch information
fbeauchamp committed Nov 25, 2022
1 parent 9d5bc8a commit f6c227e
Show file tree
Hide file tree
Showing 2 changed files with 243 additions and 107 deletions.
95 changes: 79 additions & 16 deletions packages/vhd-lib/merge.integ.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ const fs = require('fs-extra')
const rimraf = require('rimraf')
const tmp = require('tmp')
const { getSyncedHandler } = require('@xen-orchestra/fs')
const { pFromCallback } = require('promise-toolbox')
const { pFromCallback, Disposable } = require('promise-toolbox')

const { VhdFile, chainVhd } = require('./index')
const { VhdFile, chainVhd, openVhd } = require('./index')
const { _cleanupVhds: cleanupVhds, mergeVhdChain } = require('./merge')

const { checkFile, createRandomFile, convertFromRawToVhd } = require('./tests/utils')
Expand Down Expand Up @@ -163,6 +163,78 @@ test('it can resume a simple merge ', async () => {
}
})

test('it can resume a failed renaming ', async () => {
const mbOfFather = 8
const mbOfChildren = 4
const parentRandomFileName = `${tempDir}/randomfile`

await createRandomFile(`${tempDir}/randomfile`, mbOfFather)
await convertFromRawToVhd(`${tempDir}/randomfile`, `${tempDir}/parent.vhd`)
const parentVhd = new VhdFile(handler, 'parent.vhd')
await parentVhd.readHeaderAndFooter()

await createRandomFile(`${tempDir}/small_randomfile`, mbOfChildren)
await convertFromRawToVhd(`${tempDir}/small_randomfile`, `${tempDir}/child1.vhd`)
await chainVhd(handler, 'parent.vhd', handler, 'child1.vhd', true)


const childVhd = new VhdFile(handler, 'child1.vhd')
await childVhd.readHeaderAndFooter()

await handler.writeFile(
'.parent.vhd.merge.json',
JSON.stringify({
parent: {
header: parentVhd.header.checksum,
},
child: {
header: childVhd.header.checksum,
},
step: 'cleanupVhds',
})
)
// expect merge to succed
await mergeVhdChain(handler, ['parent.vhd', 'child1.vhd'])
// parent have been renamed
expect(await fs.exists(`${tempDir}/parent.vhd`)).toBeFalsy()
expect(await fs.exists(`${tempDir}/.parent.vhd.merge.json`)).toBeFalsy()

Disposable.use(openVhd(handler, 'child1.vhd'), async mergedVhd => {
await mergedVhd.readBlockAllocationTable()
// the resume is at the step 'cleanupVhds' it should not have merged blocks and should still contians parent data

let offset = 0
const fd = await fs.open(parentRandomFileName, 'r')
for await (const block of mergedVhd.blocks()) {
const blockContent = block.data
const buffer = Buffer.alloc(blockContent.length)
await fs.read(fd, buffer, 0, buffer.length, offset)

expect(buffer.equals(blockContent)).toEqual(true)
offset += childVhd.header.blockSize
}
})

// merge succeed if renaming was already done

await handler.writeFile(
'.parent.vhd.merge.json',
JSON.stringify({
parent: {
header: parentVhd.header.checksum,
},
child: {
header: childVhd.header.checksum,
},
step: 'cleanupVhds',
})
)
await mergeVhdChain(handler, ['parent.vhd', 'child1.vhd'])
expect(await fs.exists(`${tempDir}/parent.vhd`)).toBeFalsy()
expect(await fs.exists(`${tempDir}/child1.vhd`)).toBeTruthy()
expect(await fs.exists(`${tempDir}/.parent.vhd.merge.json`)).toBeFalsy()
})

test('it can resume a multiple merge ', async () => {
const mbOfFather = 8
const mbOfChildren = 6
Expand Down Expand Up @@ -226,7 +298,11 @@ test('it can resume a multiple merge ', async () => {
})
)
// it should succeed
await mergeVhdChain(handler, ['parent.vhd', 'child.vhd', 'grandchild.vhd'])
await mergeVhdChain(handler, ['parent.vhd', 'child.vhd', 'grandchild.vhd'],{removeUnused: true})
expect(await fs.exists(`${tempDir}/parent.vhd`)).toBeFalsy()
expect(await fs.exists(`${tempDir}/child.vhd`)).toBeFalsy()
expect(await fs.exists(`${tempDir}/grandchild.vhd`)).toBeTruthy()
expect(await fs.exists(`${tempDir}/.parent.vhd.merge.json`)).toBeFalsy()
})

test('it merge multiple child in one pass ', async () => {
Expand Down Expand Up @@ -279,17 +355,4 @@ test('it merge multiple child in one pass ', async () => {
}
})

test('it cleans vhd mergedfiles', async () => {
await handler.writeFile('parent', 'parentData')
await handler.writeFile('child1', 'child1Data')
await handler.writeFile('child2', 'child2Data')
await handler.writeFile('child3', 'child3Data')

await cleanupVhds(handler, ['parent', 'child1', 'child2', 'child3'], { merge: true, removeUnused: true })

// only child3 should stay, with the data of parent
const [child3, ...other] = await handler.list('.')
expect(other.length).toEqual(0)
expect(child3).toEqual('child3')
expect((await handler.readFile('child3')).toString('utf8')).toEqual('parentData')
})
Loading

0 comments on commit f6c227e

Please sign in to comment.