| Author | Dave Jarvis <email> |
|---|---|
| Date | 2026-02-21 17:50:33 GMT-0800 |
| Commit | 60c9a68c5635aea4b81dddb94d698263fa5fdf90 |
| Parent | 5abd9b1 |
| -<?php | ||
| -require_once __DIR__ . '/BufferedReader.php'; | ||
| -class FileHandlePool { | ||
| - private array $handles; | ||
| - | ||
| - public function __construct() { | ||
| - $this->handles = []; | ||
| - } | ||
| - | ||
| - public function __destruct() { | ||
| - foreach( $this->handles as $handle ) { | ||
| - if( is_resource( $handle ) ) { | ||
| - fclose( $handle ); | ||
| - } | ||
| - } | ||
| - } | ||
| - | ||
| - public function computeInt( | ||
| - string $path, | ||
| - callable $action, | ||
| - int $fallback = 0 | ||
| - ): int { | ||
| - $computed = $this->withHandle( $path, $action ); | ||
| - | ||
| - return is_int( $computed ) ? $computed : $fallback; | ||
| - } | ||
| - | ||
| - public function computeString( | ||
| - string $path, | ||
| - callable $action, | ||
| - string $fallback = '' | ||
| - ): string { | ||
| - $computed = $this->withHandle( $path, $action ); | ||
| - | ||
| - return is_string( $computed ) ? $computed : $fallback; | ||
| - } | ||
| - | ||
| - public function computeVoid( string $path, callable $action ): void { | ||
| - $this->withHandle( $path, $action ); | ||
| - } | ||
| - | ||
| - public function streamGenerator( | ||
| - string $path, | ||
| - callable $action | ||
| - ): Generator { | ||
| - $resultGenerator = $this->withHandle( $path, $action ); | ||
| - | ||
| - if( $resultGenerator instanceof Generator ) { | ||
| - yield from $resultGenerator; | ||
| - } | ||
| - } | ||
| - | ||
| - public function computeStringDedicated( | ||
| - string $path, | ||
| - callable $action, | ||
| - string $fallback = '' | ||
| - ): string { | ||
| - $handle = @fopen( $path, 'rb' ); | ||
| - $computed = false; | ||
| - | ||
| - if( is_resource( $handle ) ) { | ||
| - $computed = $action( BufferedReader::wrap( $handle ) ); | ||
| - | ||
| - fclose( $handle ); | ||
| - } | ||
| - | ||
| - return is_string( $computed ) ? $computed : $fallback; | ||
| - } | ||
| - | ||
| - public function streamGeneratorDedicated( | ||
| - string $path, | ||
| - callable $action | ||
| - ): Generator { | ||
| - $handle = @fopen( $path, 'rb' ); | ||
| - | ||
| - if( is_resource( $handle ) ) { | ||
| - try { | ||
| - $resultGenerator = $action( BufferedReader::wrap( $handle ) ); | ||
| - | ||
| - if( $resultGenerator instanceof Generator ) { | ||
| - yield from $resultGenerator; | ||
| - } | ||
| - } finally { | ||
| - fclose( $handle ); | ||
| - } | ||
| - } | ||
| - } | ||
| - | ||
| - private function withHandle( string $path, callable $action ): mixed { | ||
| - $result = false; | ||
| - | ||
| - if( !array_key_exists( $path, $this->handles ) ) { | ||
| - $handle = @fopen( $path, 'rb' ); | ||
| - | ||
| - if( is_resource( $handle ) ) { | ||
| - $this->handles[$path] = $handle; | ||
| - } | ||
| - } | ||
| - | ||
| - if( array_key_exists( $path, $this->handles ) ) { | ||
| - $result = $action( BufferedReader::wrap( $this->handles[$path] ) ); | ||
| - } | ||
| - | ||
| - return $result; | ||
| - } | ||
| -} | ||
| <?php | ||
| -require_once __DIR__ . '/FileHandlePool.php'; | ||
| +require_once __DIR__ . '/PackStreamManager.php'; | ||
| require_once __DIR__ . '/PackLocator.php'; | ||
| require_once __DIR__ . '/DeltaDecoder.php'; | ||
| require_once __DIR__ . '/PackEntryReader.php'; | ||
| class GitPacks { | ||
| private const MAX_RAM = 1048576; | ||
| - private FileHandlePool $pool; | ||
| - private PackLocator $locator; | ||
| - private PackEntryReader $reader; | ||
| + private PackStreamManager $manager; | ||
| + private PackLocator $locator; | ||
| + private PackEntryReader $reader; | ||
| public function __construct( string $objectsPath ) { | ||
| - $this->pool = new FileHandlePool(); | ||
| + $this->manager = new PackStreamManager(); | ||
| $this->locator = new PackLocator( $objectsPath ); | ||
| $this->reader = new PackEntryReader( new DeltaDecoder() ); | ||
| } | ||
| public function peek( string $sha, int $len = 12 ): string { | ||
| $result = ''; | ||
| $this->locator->locate( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $sha, | ||
| function( string $packFile, int $offset ) use ( &$result, $len ): void { | ||
| $result = $this->reader->read( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $packFile, | ||
| $offset, | ||
| $this->locator->locate( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $sha, | ||
| function( string $packFile, int $offset ) use ( &$result ): void { | ||
| - $size = $this->reader->getSize( $this->pool, $packFile, $offset ); | ||
| + $size = $this->reader->getSize( | ||
| + $this->manager, | ||
| + $packFile, | ||
| + $offset | ||
| + ); | ||
| if( $size <= self::MAX_RAM ) { | ||
| $result = $this->reader->read( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $packFile, | ||
| $offset, | ||
| $this->locator->locate( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $sha, | ||
| function( string $packFile, int $offset ) use ( | ||
| if( $found ) { | ||
| yield from $this->reader->streamRawCompressed( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $file, | ||
| $off | ||
| $this->locator->locate( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $sha, | ||
| function( string $packFile, int $offset ) use ( | ||
| if( $found ) { | ||
| yield from $this->reader->streamEntryGenerator( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $file, | ||
| $off, | ||
| $this->locator->locate( | ||
| - $this->pool, | ||
| + $this->manager, | ||
| $sha, | ||
| function( string $packFile, int $offset ) use ( &$result ): void { | ||
| - $result = $this->reader->getSize( $this->pool, $packFile, $offset ); | ||
| + $result = $this->reader->getSize( | ||
| + $this->manager, | ||
| + $packFile, | ||
| + $offset | ||
| + ); | ||
| } | ||
| ); | ||
| <?php | ||
| -require_once __DIR__ . '/FileHandlePool.php'; | ||
| +require_once __DIR__ . '/PackStreamManager.php'; | ||
| require_once __DIR__ . '/DeltaDecoder.php'; | ||
| require_once __DIR__ . '/CompressionStream.php'; | ||
| public function getSize( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $offset | ||
| ): int { | ||
| - $result = $pool->computeInt( | ||
| + $result = $manager->computeInt( | ||
| $packFile, | ||
| function( StreamReader $stream ) use ( $offset ): int { | ||
| public function read( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $offset, | ||
| int $cap, | ||
| callable $readShaBaseFn | ||
| ): string { | ||
| - $result = $pool->computeStringDedicated( | ||
| + $result = $manager->computeStringDedicated( | ||
| $packFile, | ||
| function( StreamReader $stream ) use ( | ||
| public function streamRawCompressed( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $offset | ||
| ): Generator { | ||
| - yield from $pool->streamGenerator( | ||
| + yield from $manager->streamGenerator( | ||
| $packFile, | ||
| function( StreamReader $stream ) use ( $offset ): Generator { | ||
| public function streamEntryGenerator( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $offset, | ||
| int $depth, | ||
| callable $getSizeShaFn, | ||
| callable $streamShaFn | ||
| ): Generator { | ||
| - yield from $pool->streamGeneratorDedicated( | ||
| + yield from $manager->streamGeneratorDedicated( | ||
| $packFile, | ||
| function( StreamReader $stream ) use ( | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $offset, | ||
| yield from $this->streamDeltaObjectGenerator( | ||
| $stream, | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $offset, | ||
| private function streamDeltaObjectGenerator( | ||
| StreamReader $stream, | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $offset, | ||
| $neg = $this->readOffsetDelta( $stream ); | ||
| $baseSize = $this->getSize( | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $offset - $neg | ||
| ); | ||
| if( $baseSize > self::MAX_BASE_RAM ) { | ||
| $tmpStream = $this->resolveBaseToTempFile( | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $offset - $neg, | ||
| $base = $this->read( | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $offset - $neg, | ||
| private function resolveBaseToTempFile( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $packFile, | ||
| int $baseOffset, | ||
| int $depth, | ||
| callable $getSizeShaFn, | ||
| callable $streamShaFn | ||
| ): StreamReader { | ||
| $result = BufferedReader::createTemp(); | ||
| foreach( $this->streamEntryGenerator( | ||
| - $pool, | ||
| + $manager, | ||
| $packFile, | ||
| $baseOffset, | ||
| <?php | ||
| require_once __DIR__ . '/StreamReader.php'; | ||
| -require_once __DIR__ . '/FileHandlePool.php'; | ||
| +require_once __DIR__ . '/PackStreamManager.php'; | ||
| class PackIndex { | ||
| public function search( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $sha, | ||
| callable $onFound | ||
| ): void { | ||
| - $pool->computeVoid( | ||
| + $manager->computeInt( | ||
| $this->indexFile, | ||
| - function( StreamReader $stream ) use ( $sha, $onFound ): void { | ||
| + function( StreamReader $stream ) use ( $sha, $onFound ): int { | ||
| $this->ensureFanout( $stream ); | ||
| if( !empty( $this->fanoutCache ) ) { | ||
| $this->binarySearch( $stream, $sha, $onFound ); | ||
| } | ||
| - } | ||
| + | ||
| + return 0; | ||
| + }, | ||
| + 0 | ||
| ); | ||
| } | ||
| $offset = $pos - $this->bufferOffset; | ||
| + | ||
| return substr( $this->buffer, $offset, 20 ); | ||
| } | ||
| <?php | ||
| require_once __DIR__ . '/PackIndex.php'; | ||
| -require_once __DIR__ . '/FileHandlePool.php'; | ||
| +require_once __DIR__ . '/PackStreamManager.php'; | ||
| class PackLocator { | ||
| public function locate( | ||
| - FileHandlePool $pool, | ||
| + PackStreamManager $manager, | ||
| string $sha, | ||
| callable $action | ||
| while( !$found && $index < $count ) { | ||
| $this->indexes[$index]->search( | ||
| - $pool, | ||
| + $manager, | ||
| $binarySha, | ||
| function( | ||
| +<?php | ||
| +require_once __DIR__ . '/BufferedReader.php'; | ||
| + | ||
| +class PackStreamManager { | ||
| + private array $readers = []; | ||
| + | ||
| + public function computeInt( | ||
| + string $path, | ||
| + callable $callback, | ||
| + int $default | ||
| + ): int { | ||
| + $result = $default; | ||
| + $reader = $this->acquire( $path ); | ||
| + | ||
| + if( $reader->isOpen() ) { | ||
| + try { | ||
| + $result = $callback( $reader ); | ||
| + } finally { | ||
| + $this->release( $path, $reader ); | ||
| + } | ||
| + } | ||
| + | ||
| + return $result; | ||
| + } | ||
| + | ||
| + public function computeStringDedicated( | ||
| + string $path, | ||
| + callable $callback, | ||
| + string $default | ||
| + ): string { | ||
| + $result = $default; | ||
| + $reader = BufferedReader::open( $path ); | ||
| + | ||
| + if( $reader->isOpen() ) { | ||
| + $result = $callback( $reader ); | ||
| + } | ||
| + | ||
| + return $result; | ||
| + } | ||
| + | ||
| + public function streamGenerator( | ||
| + string $path, | ||
| + callable $callback | ||
| + ): Generator { | ||
| + $reader = $this->acquire( $path ); | ||
| + | ||
| + if( $reader->isOpen() ) { | ||
| + try { | ||
| + yield from $callback( $reader ); | ||
| + } finally { | ||
| + $this->release( $path, $reader ); | ||
| + } | ||
| + } | ||
| + } | ||
| + | ||
| + public function streamGeneratorDedicated( | ||
| + string $path, | ||
| + callable $callback | ||
| + ): Generator { | ||
| + $reader = BufferedReader::open( $path ); | ||
| + | ||
| + if( $reader->isOpen() ) { | ||
| + yield from $callback( $reader ); | ||
| + } | ||
| + } | ||
| + | ||
| + private function acquire( string $path ): BufferedReader { | ||
| + return !empty( $this->readers[$path] ) | ||
| + ? array_pop( $this->readers[$path] ) | ||
| + : BufferedReader::open( $path ); | ||
| + } | ||
| + | ||
| + private function release( string $path, BufferedReader $reader ): void { | ||
| + isset( $this->readers[$path] ) ? null : $this->readers[$path] = []; | ||
| + | ||
| + $this->readers[$path][] = $reader; | ||
| + } | ||
| +} | ||
| Delta | 131 lines added, 147 lines removed, 16-line decrease |
|---|