Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Adds pack stream manager

AuthorDave Jarvis <email>
Date2026-02-21 17:50:33 GMT-0800
Commit60c9a68c5635aea4b81dddb94d698263fa5fdf90
Parent5abd9b1
git/FileHandlePool.php
-<?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;
- }
-}
git/GitPacks.php
<?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
+ );
}
);
git/PackEntryReader.php
<?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,
git/PackIndex.php
<?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 );
}
git/PackLocator.php
<?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(
git/PackStreamManager.php
+<?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;
+ }
+}
Delta131 lines added, 147 lines removed, 16-line decrease