mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-05 23:12:42 +00:00
115 lines
2.5 KiB
TypeScript
115 lines
2.5 KiB
TypeScript
import {
|
|
toWorkspaceString,
|
|
type Doc,
|
|
type DocInfo,
|
|
type Domain,
|
|
type LowLevelStorage,
|
|
type MeasureContext,
|
|
type Ref,
|
|
type StorageIterator,
|
|
type WorkspaceId
|
|
} from '@hcengineering/core'
|
|
import { estimateDocSize } from './utils'
|
|
|
|
export * from '@hcengineering/storage'
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export function getBucketId (workspaceId: WorkspaceId): string {
|
|
return toWorkspaceString(workspaceId)
|
|
}
|
|
|
|
const chunkSize = 512 * 1024
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export interface ChunkInfo {
|
|
idx: number
|
|
index: 0
|
|
finished: boolean
|
|
iterator: StorageIterator
|
|
}
|
|
|
|
/**
|
|
* @public
|
|
*/
|
|
export class BackupClientOps {
|
|
constructor (protected readonly storage: LowLevelStorage) {}
|
|
|
|
idIndex = 0
|
|
chunkInfo = new Map<number, ChunkInfo>()
|
|
|
|
loadChunk (
|
|
ctx: MeasureContext,
|
|
domain: Domain,
|
|
idx?: number,
|
|
recheck?: boolean
|
|
): Promise<{
|
|
idx: number
|
|
docs: DocInfo[]
|
|
finished: boolean
|
|
}> {
|
|
return ctx.with('load-chunk', {}, async (ctx) => {
|
|
idx = idx ?? this.idIndex++
|
|
let chunk: ChunkInfo | undefined = this.chunkInfo.get(idx)
|
|
if (chunk !== undefined) {
|
|
chunk.index++
|
|
if (chunk.finished === undefined || chunk.finished) {
|
|
return {
|
|
idx,
|
|
docs: [],
|
|
finished: true
|
|
}
|
|
}
|
|
} else {
|
|
chunk = { idx, iterator: this.storage.find(ctx, domain, recheck), finished: false, index: 0 }
|
|
this.chunkInfo.set(idx, chunk)
|
|
}
|
|
let size = 0
|
|
const docs: DocInfo[] = []
|
|
|
|
while (size < chunkSize) {
|
|
const _docs = await chunk.iterator.next(ctx)
|
|
if (_docs.length === 0) {
|
|
chunk.finished = true
|
|
break
|
|
}
|
|
for (const doc of _docs) {
|
|
size += estimateDocSize(doc)
|
|
docs.push(doc)
|
|
}
|
|
}
|
|
|
|
return {
|
|
idx,
|
|
docs,
|
|
finished: chunk.finished
|
|
}
|
|
})
|
|
}
|
|
|
|
closeChunk (ctx: MeasureContext, idx: number): Promise<void> {
|
|
return ctx.with('close-chunk', {}, async () => {
|
|
const chunk = this.chunkInfo.get(idx)
|
|
this.chunkInfo.delete(idx)
|
|
if (chunk != null) {
|
|
await chunk.iterator.close(ctx)
|
|
}
|
|
})
|
|
}
|
|
|
|
loadDocs (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<Doc[]> {
|
|
return this.storage.load(ctx, domain, docs)
|
|
}
|
|
|
|
upload (ctx: MeasureContext, domain: Domain, docs: Doc[]): Promise<void> {
|
|
return this.storage.upload(ctx, domain, docs)
|
|
}
|
|
|
|
clean (ctx: MeasureContext, domain: Domain, docs: Ref<Doc>[]): Promise<void> {
|
|
return this.storage.clean(ctx, domain, docs)
|
|
}
|
|
}
|