Batched SFTP reads: no more batches on a connection whose server did not confirm a close
This commit is contained in:
@@ -55,6 +55,13 @@ final class SftpReadStream {
|
|||||||
*/
|
*/
|
||||||
private static ?\WeakMap $chunks = null;
|
private static ?\WeakMap $chunks = null;
|
||||||
private static int $requestId = 0x4e470000;
|
private static int $requestId = 0x4e470000;
|
||||||
|
/**
|
||||||
|
* Connections whose server did not confirm closing a batch's files: readMany() is not used on
|
||||||
|
* them again, so handles cannot pile up.
|
||||||
|
*
|
||||||
|
* @var \WeakMap<object, true>|null
|
||||||
|
*/
|
||||||
|
private static ?\WeakMap $noBatches = null;
|
||||||
/** Streams in a row that failed; at MAX_FAILURES only the storage's own stream is used. */
|
/** Streams in a row that failed; at MAX_FAILURES only the storage's own stream is used. */
|
||||||
private static int $failures = 0;
|
private static int $failures = 0;
|
||||||
public const MAX_FAILURES = 3;
|
public const MAX_FAILURES = 3;
|
||||||
@@ -182,7 +189,7 @@ final class SftpReadStream {
|
|||||||
self::$failures++;
|
self::$failures++;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if ($sftp === null) {
|
if ($sftp === null || self::$noBatches?->offsetExists($sftp) === true) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$result = array_fill_keys($paths, null);
|
$result = array_fill_keys($paths, null);
|
||||||
@@ -200,8 +207,9 @@ final class SftpReadStream {
|
|||||||
$result[$path] = $contents;
|
$result[$path] = $contents;
|
||||||
}
|
}
|
||||||
if (!$closed) {
|
if (!$closed) {
|
||||||
// The server did not confirm closing these files: no more batches, so handles
|
// The server did not confirm closing these files: no more batches on this
|
||||||
// cannot pile up. The rest is read the usual way, one at a time.
|
// connection, so handles cannot pile up. The rest is read the usual way.
|
||||||
|
self::noMoreBatches($sftp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,6 +217,11 @@ final class SftpReadStream {
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function noMoreBatches(object $sftp): void {
|
||||||
|
self::$noBatches ??= new \WeakMap();
|
||||||
|
self::$noBatches[$sftp] = true;
|
||||||
|
}
|
||||||
|
|
||||||
private static function disconnect(object $sftp): void {
|
private static function disconnect(object $sftp): void {
|
||||||
try {
|
try {
|
||||||
if (is_callable([$sftp, 'disconnect'])) {
|
if (is_callable([$sftp, 'disconnect'])) {
|
||||||
@@ -306,6 +319,7 @@ final class SftpReadStream {
|
|||||||
/** Test hook: forget the learned READ sizes and earlier failures. */
|
/** Test hook: forget the learned READ sizes and earlier failures. */
|
||||||
public static function reset(): void {
|
public static function reset(): void {
|
||||||
self::$chunks = null;
|
self::$chunks = null;
|
||||||
|
self::$noBatches = null;
|
||||||
self::$failures = 0;
|
self::$failures = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -286,6 +286,8 @@ class SftpReadStreamTest extends TestCase {
|
|||||||
$this->assertSame('file 31', $got['31']);
|
$this->assertSame('file 31', $got['31']);
|
||||||
$this->assertNull($got['32'], 'no second batch after unconfirmed closes');
|
$this->assertNull($got['32'], 'no second batch after unconfirmed closes');
|
||||||
$this->assertCount(SftpReadStream::BATCH, array_filter($got, fn ($v) => $v !== null));
|
$this->assertCount(SftpReadStream::BATCH, array_filter($got, fn ($v) => $v !== null));
|
||||||
|
// Nor on a later call over the same connection.
|
||||||
|
$this->assertNull(SftpReadStream::readMany(new FakeSftpStorage($sftp), ['0']));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testReadManyLeavesAMalformedAnswerToTheCaller(): void {
|
public function testReadManyLeavesAMalformedAnswerToTheCaller(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user