feat(xo-server/file restore): dedupe mount/unmount (#4961)
This commit is contained in:
parent
6555e2c440
commit
48ce7df43a
45
packages/xo-server/src/_dedupeUnmount.js
Normal file
45
packages/xo-server/src/_dedupeUnmount.js
Normal file
@ -0,0 +1,45 @@
|
||||
import assert from 'assert'
|
||||
|
||||
import ensureArray from './_ensureArray'
|
||||
import MultiKeyMap from './_MultiKeyMap'
|
||||
|
||||
function State() {
|
||||
this.i = 0
|
||||
this.value = undefined
|
||||
}
|
||||
|
||||
export const dedupeUnmount = (fn, keyFn) => {
|
||||
const states = new MultiKeyMap()
|
||||
|
||||
return function() {
|
||||
const keys = ensureArray(keyFn.apply(this, arguments))
|
||||
let state = states.get(keys)
|
||||
if (state === undefined) {
|
||||
state = new State()
|
||||
states.set(keys, state)
|
||||
|
||||
const mount = async () => {
|
||||
try {
|
||||
const value = await fn.apply(this, arguments)
|
||||
return {
|
||||
__proto__: value,
|
||||
async unmount() {
|
||||
assert(state.i > 0)
|
||||
if (--state.i === 0) {
|
||||
states.delete(keys)
|
||||
await value.unmount()
|
||||
}
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
states.delete(keys)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
state.value = mount()
|
||||
}
|
||||
++state.i
|
||||
return state.value
|
||||
}
|
||||
}
|
@ -6,9 +6,15 @@ import { normalize } from 'path'
|
||||
import { readdir, rmdir, stat } from 'fs-extra'
|
||||
import { ZipFile } from 'yazl'
|
||||
|
||||
import { decorateWith } from '../_decorateWith'
|
||||
import { dedupeUnmount } from '../_dedupeUnmount'
|
||||
import { lvs, pvs } from '../lvm'
|
||||
import { resolveSubpath, tmpDir } from '../utils'
|
||||
|
||||
const compose = (...fns) => value => fns.reduce((value, fn) => fn(value), value)
|
||||
|
||||
const dedupeUnmountWithArgs = fn => dedupeUnmount(fn, (...args) => args)
|
||||
|
||||
const IGNORED_PARTITION_TYPES = {
|
||||
// https://github.com/jhermsmeier/node-mbr/blob/master/lib/partition.js#L38
|
||||
0x05: true,
|
||||
@ -60,8 +66,10 @@ const parsePartxLine = createPairsParser({
|
||||
: value,
|
||||
})
|
||||
|
||||
const listLvmLogicalVolumes = defer(
|
||||
async ($defer, devicePath, partition, results = []) => {
|
||||
const listLvmLogicalVolumes = compose(
|
||||
defer,
|
||||
dedupeUnmountWithArgs
|
||||
)(async ($defer, devicePath, partition, results = []) => {
|
||||
const pv = await mountLvmPhysicalVolume(devicePath, partition)
|
||||
$defer(pv.unmount)
|
||||
|
||||
@ -78,10 +86,10 @@ const listLvmLogicalVolumes = defer(
|
||||
}
|
||||
})
|
||||
return results
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
async function mountLvmPhysicalVolume(devicePath, partition) {
|
||||
const mountLvmPhysicalVolume = dedupeUnmountWithArgs(
|
||||
async (devicePath, partition) => {
|
||||
const args = []
|
||||
if (partition !== undefined) {
|
||||
args.push('-o', partition.start * 512)
|
||||
@ -101,9 +109,13 @@ async function mountLvmPhysicalVolume(devicePath, partition) {
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const mountPartition = defer(async ($defer, devicePath, partition) => {
|
||||
const mountPartition = compose(
|
||||
defer,
|
||||
dedupeUnmountWithArgs
|
||||
)(async ($defer, devicePath, partition) => {
|
||||
const options = ['loop', 'ro']
|
||||
|
||||
if (partition !== undefined) {
|
||||
@ -280,6 +292,7 @@ export default class BackupNgFileRestore {
|
||||
return partitions
|
||||
}
|
||||
|
||||
@decorateWith(dedupeUnmountWithArgs)
|
||||
@defer
|
||||
async _mountDisk($defer, remoteId, diskId) {
|
||||
const handler = await this._app.getRemoteHandler(remoteId)
|
||||
@ -321,6 +334,7 @@ export default class BackupNgFileRestore {
|
||||
}
|
||||
}
|
||||
|
||||
@decorateWith(dedupeUnmountWithArgs)
|
||||
@defer
|
||||
async _mountPartition($defer, devicePath, partitionId) {
|
||||
if (partitionId === undefined) {
|
||||
|
Loading…
Reference in New Issue
Block a user