mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-11-09 17:06:13 -06:00
committed by
GitHub
parent
1d8c429532
commit
42eb8664be
@@ -6,6 +6,8 @@ export class DiskSmallerBlock extends DiskPassthrough {
|
||||
#blockSize
|
||||
#generatedDiskBlocks = 0
|
||||
#blockCache?: DiskBlock
|
||||
#blockRatio: number
|
||||
#maxBlockIndex: number
|
||||
|
||||
constructor(source: Disk, blockSize: number) {
|
||||
super(source)
|
||||
@@ -17,9 +19,11 @@ export class DiskSmallerBlock extends DiskPassthrough {
|
||||
assert.strictEqual(
|
||||
source.getBlockSize() % blockSize,
|
||||
0,
|
||||
`target block size ${blockSize} must be a multiple of the source block size ${source.getBlockSize()} `
|
||||
`source block size ${blockSize} must be a multiple of the target block size ${source.getBlockSize()} `
|
||||
)
|
||||
this.#blockSize = blockSize
|
||||
this.#blockRatio = source.getBlockSize() / blockSize
|
||||
this.#maxBlockIndex = Math.ceil(this.getVirtualSize() / this.getBlockSize())
|
||||
}
|
||||
|
||||
openSource(): Promise<Disk> {
|
||||
@@ -35,13 +39,19 @@ export class DiskSmallerBlock extends DiskPassthrough {
|
||||
try {
|
||||
const blockRatio = this.source.getBlockSize() / this.#blockSize
|
||||
const sourceGenerator = this.source.diskBlocks()
|
||||
// we don't reuse getBlockIndexes here since we want don't want to force
|
||||
// a use of source.readblock that would limit the use of this class to RandomeAccessDisk
|
||||
// thus we generate block based on the source block generator
|
||||
for await (const { data: sourceData, index: sourceIndex } of sourceGenerator) {
|
||||
for (let i = 0; i < blockRatio; i++) {
|
||||
this.#generatedDiskBlocks++
|
||||
const data = sourceData.subarray(i * this.#blockSize, (i + 1) * this.#blockSize)
|
||||
yield {
|
||||
index: sourceIndex * blockRatio + i,
|
||||
data,
|
||||
const index = sourceIndex * blockRatio + i
|
||||
if (this.#isBlockBeforeEnd(index)) {
|
||||
yield {
|
||||
index,
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,15 +64,22 @@ export class DiskSmallerBlock extends DiskPassthrough {
|
||||
getBlockSize(): number {
|
||||
return this.#blockSize
|
||||
}
|
||||
// changing the block size can lead
|
||||
// to the last block being incomplete
|
||||
// for example going for a block size of 1024 to 512
|
||||
// and a virtual size of 1200 means 2 blocks in source,
|
||||
// but 3 here
|
||||
#isBlockBeforeEnd(blockIndex: number): boolean {
|
||||
return blockIndex < this.#maxBlockIndex
|
||||
}
|
||||
getBlockIndexes(): Array<number> {
|
||||
const blockRatio = this.source.getBlockSize() / this.getBlockSize()
|
||||
const sourceIndexes = this.source.getBlockIndexes()
|
||||
const indexes: Array<number> = []
|
||||
const maxIndex = Math.ceil(this.getVirtualSize() / this.getBlockSize())
|
||||
for (const sourceIndex of sourceIndexes) {
|
||||
for (let i = 0; i < blockRatio; i++) {
|
||||
const index = sourceIndex * blockRatio + i
|
||||
if (index < maxIndex) {
|
||||
if (this.#isBlockBeforeEnd(index)) {
|
||||
indexes.push(index)
|
||||
}
|
||||
}
|
||||
@@ -71,13 +88,28 @@ export class DiskSmallerBlock extends DiskPassthrough {
|
||||
}
|
||||
|
||||
hasBlock(index: number): boolean {
|
||||
// asking for a block after the end of the smaller disk => false
|
||||
if (!this.#isBlockBeforeEnd(index)) {
|
||||
return false
|
||||
}
|
||||
const blockRatio = this.source.getBlockSize() / this.getBlockSize()
|
||||
const sourceIndex = Math.floor(index / blockRatio)
|
||||
return this.source.hasBlock(sourceIndex)
|
||||
}
|
||||
|
||||
/**
|
||||
* handle gracefully readblock if the source is a RandomAccessDisk
|
||||
* @param index
|
||||
* @returns Promise<DiskBlock>
|
||||
*/
|
||||
|
||||
async readBlock(index: number): Promise<DiskBlock> {
|
||||
if (this.source instanceof RandomAccessDisk) {
|
||||
if (!this.#isBlockBeforeEnd(index)) {
|
||||
throw new Error(
|
||||
`Read after the end, asking for ${index}, last block is ${this.#maxBlockIndex - 1}, vitual size is ${this.getVirtualSize()}, blockSize : ${this.getBlockSize()}`
|
||||
)
|
||||
}
|
||||
const blockRatio = this.source.getBlockSize() / this.getBlockSize()
|
||||
const sourceBlockIndex = Math.floor(index / blockRatio)
|
||||
const indexInblock = index % blockRatio
|
||||
|
||||
@@ -160,8 +160,8 @@ test('hasBlock behavior', async () => {
|
||||
|
||||
test('getBlockIndexes', async () => {
|
||||
const source = new MockDisk(512, 2048, [
|
||||
[0, Buffer.alloc(512)],
|
||||
[2, Buffer.alloc(512)],
|
||||
[0, Buffer.alloc(2048)],
|
||||
[2, Buffer.alloc(2048)],
|
||||
])
|
||||
await source.init()
|
||||
|
||||
@@ -182,3 +182,28 @@ test('close propagation', async () => {
|
||||
await disk.close()
|
||||
assert(source.closed)
|
||||
})
|
||||
|
||||
test('unaligned END ', async () => {
|
||||
const source = new MockDisk(1024, 2048 + 256, [
|
||||
[0, Buffer.alloc(1024)],
|
||||
[2, Buffer.alloc(1024)],
|
||||
])
|
||||
await source.init()
|
||||
|
||||
const disk = new DiskSmallerBlock(source, 256)
|
||||
await disk.init()
|
||||
assert.strictEqual(source.getVirtualSize(), disk.getVirtualSize())
|
||||
|
||||
const indexes = disk.getBlockIndexes()
|
||||
const expecteBlockIndex = [0, 1, 2, 3, 8]
|
||||
assert.deepStrictEqual(indexes, expecteBlockIndex)
|
||||
assert.strictEqual(disk.hasBlock(8), true)
|
||||
assert.strictEqual(disk.hasBlock(9), false) //After the end of small block disk
|
||||
assert.strictEqual(disk.hasBlock(12), false) //After the end of source disk
|
||||
|
||||
// ensure disk blocks also handle the unaligned part
|
||||
for await (const { index, data } of disk.diskBlocks()) {
|
||||
assert.ok(expecteBlockIndex.includes(index))
|
||||
assert.equal(data.length, 256)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user