ccbbf01c54
A restore read one pack at a time over one SFTP connection, which over a long line is bound by the round trip and by what one TCP connection gets: about 2-3 MiB/s from a Hetzner Storage Box to Canada, with PHP mostly waiting. Repository::restore() now first lists the ranges of packs the restore needs, in order (ReadAheadPlan), and the location reads them ahead into unlinked files in a spool folder in the target (IReadsAhead). Over SFTP, SftpRangeFetcher does that on four connections of its own, 16 requests in flight each, taking the answers of whichever connection has one. A range that fails, a damaged copy, or a blob that moved since the plan is read the usual way, which reports what is wrong. Other locations restore as before. On a test line with 120 ms RTT and 0.2% loss, a 1.6 GiB restore went from 5.1 to 17.8 MiB/s, all files identical.
31 lines
1.3 KiB
PHP
31 lines
1.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
// SPDX-FileCopyrightText: 2026 Dillard Blom
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
namespace OCA\NgBackup\Backend;
|
|
|
|
/**
|
|
* A backend that can read many byte ranges ahead of use, several at a time over connections of
|
|
* its own (a full restore, where one connection at a time is bound by the round trip).
|
|
*/
|
|
interface IReadsAhead {
|
|
/** Whether readAhead() is worth planning for: false when it would return null anyway. */
|
|
public function canReadAhead(): bool;
|
|
|
|
/**
|
|
* The ranges in the order given, each as a local stream at offset 0 holding its bytes, read a
|
|
* few ranges ahead of the one the caller is at. A stream is closed when the generator is
|
|
* resumed. Null for a range that could not be read this way (a missing object, a server or
|
|
* connection error): the caller reads it the usual way, which reports why.
|
|
*
|
|
* @param list<array{0:string, 1:int, 2:int}> $ranges [path, offset, length] each
|
|
* @param string $spool an existing local directory for the files that hold the ranges
|
|
* @return \Generator<int, resource|null>|null by position in $ranges; null when this backend
|
|
* cannot read ahead now
|
|
*/
|
|
public function readAhead(array $ranges, string $spool): ?\Generator;
|
|
}
|