mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-10 22:14:48 -05:00
feat(nbd-client): implement a Disk adapter based on NBD connection
This commit is contained in:
committed by
Florent BEAUCHAMP
parent
6c32155327
commit
f8cb07596b
122
@vates/nbd-client/NbdDisk.mjs
Normal file
122
@vates/nbd-client/NbdDisk.mjs
Normal file
@@ -0,0 +1,122 @@
|
||||
import { RandomAccessDisk } from '@xen-orchestra/disk-transform'
|
||||
import NbdClient from '@vates/nbd-client'
|
||||
|
||||
/**
|
||||
* @typedef {{ offset: number, length: number }} DataRange
|
||||
*/
|
||||
|
||||
/**
|
||||
* @extends {RandomAccessDisk}
|
||||
*/
|
||||
export class NbdDisk extends RandomAccessDisk {
|
||||
#nbdInfos
|
||||
/** @type {NbdClient|undefined} */
|
||||
#nbdClient
|
||||
|
||||
/** @type {Array<DataRange> | undefined} */
|
||||
#dataMap
|
||||
|
||||
/** @type {number} */
|
||||
#blockSize
|
||||
|
||||
constructor(nbdInfos, blockSize, { dataMap } = {}) {
|
||||
super()
|
||||
this.#blockSize = blockSize
|
||||
this.#nbdInfos = nbdInfos
|
||||
this.#dataMap = dataMap && this.#processDatamap(dataMap)
|
||||
}
|
||||
|
||||
#processDatamap(rawDataMap) {
|
||||
return rawDataMap
|
||||
.filter(({ type }) => type === 0)
|
||||
.map(({ offset, length }) => ({ offset, length }))
|
||||
.sort(({ offset: offset1 }, { offset: offset2 }) => offset1 - offset2)
|
||||
}
|
||||
/**
|
||||
* @param {number} index
|
||||
* @returns {Promise<DiskBlock>}
|
||||
*/
|
||||
async readBlock(index) {
|
||||
if (!this.#nbdClient) {
|
||||
throw new Error("can't readBlock before init")
|
||||
}
|
||||
const data = await this.#nbdClient.readBlock(index, this.getBlockSize())
|
||||
return {
|
||||
index,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
getVirtualSize() {
|
||||
if (!this.#nbdClient) {
|
||||
throw new Error("can't get size before init")
|
||||
}
|
||||
return Number(this.#nbdClient.exportSize)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
getBlockSize() {
|
||||
return this.#blockSize
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async init() {
|
||||
this.#nbdClient = new NbdClient(this.#nbdInfos)
|
||||
await this.#nbdClient.connect()
|
||||
if (this.#dataMap === undefined) {
|
||||
this.#dataMap = this.#processDatamap(await this.#nbdClient.getMap())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async close() {
|
||||
await this.#nbdClient?.disconnect()
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDifferencing() {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Array<number>}
|
||||
*/
|
||||
getBlockIndexes() {
|
||||
const indexes = new Set()
|
||||
this.#dataMap?.forEach(({ offset, length }) => {
|
||||
if (length === 0) return
|
||||
|
||||
const firstBlockIndex = Math.floor(offset / this.getBlockSize())
|
||||
const lastBlockIndex = Math.floor((offset + length - 1) / this.getBlockSize())
|
||||
|
||||
for (let blockIndex = firstBlockIndex; blockIndex <= lastBlockIndex; blockIndex++) {
|
||||
indexes.add(blockIndex)
|
||||
}
|
||||
})
|
||||
return [...indexes].sort((a, b) => a - b)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} index
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasBlock(index) {
|
||||
if (!this.#dataMap) {
|
||||
throw new Error("can't hasBlock before init")
|
||||
}
|
||||
const blockStart = index * this.getBlockSize()
|
||||
const blockEnd = (index + 1) * this.getBlockSize()
|
||||
return this.#dataMap.some(({ offset, length }) => offset + length > blockStart && blockEnd >= offset)
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@
|
||||
"@vates/async-each": "^1.0.0",
|
||||
"@vates/read-chunk": "^1.2.0",
|
||||
"@xen-orchestra/async-map": "^0.1.2",
|
||||
"@xen-orchestra/disk-transform": "^1.0.1",
|
||||
"@xen-orchestra/log": "^0.7.1",
|
||||
"promise-toolbox": "^0.21.0",
|
||||
"xen-api": "^4.7.3"
|
||||
|
||||
Reference in New Issue
Block a user