Release v0.3.0 LivePSR-16 & PSR-6

Zero-Fragmentation Cache
For Long-Running PHP Workers

Built for FrankenPHP, Swoole, RoadRunner, and Octane. Flat 53 µs prefix invalidation, in-C batch eviction, and zero-copy shared memory.

composer require orieg/judy-cache
Interactive Guide → Measured Benchmarks Underlying PHP Judy
Core Architecture

Designed from the ground up to prevent Zend MM heap fragmentation in long-running persistent runtimes.

Flat O(range) Prefix Invalidation

Drop whole tenant namespaces or resource trees in 53 µs flat regardless of array size — 1,500x faster than APCu regex sweeps and 17,000x faster than Symfony ArrayAdapter.

🧩

Single-Trie STRING_TO_ENTRY

Stores values with uint32 expiry timestamps and 16-bit metadata flags directly packed into C struct entries. Zero userland payload envelopes (\x00JE\x01) and 50% lower key index RAM.

🧹

Single-Pass In-C TTL Eviction

$cache->prune() invokes native in-C pruneExpired() directly. Evicts 100,000 expired entries in 12.9 ms with 0 PHP heap allocations.

💾

SlabArena & SharedMemoryPool

Pre-allocated bitmap-managed chunk allocator and zero-copy shmop shared memory pool across worker processes, eliminating memory leaks.

🔗

Raw Binary XXH3 Interning

Content-addressable payload deduplication using 8-byte uint64 XXH3 digests, yielding -93% net cache RAM on repeated document payloads.

🪜

Adaptive Compression

Transparent multi-codec compression (Zstandard, LZ4, Gzip, Deflate) with 16-bit flag metadata encoding and automatic payload expansion bypass.

Code Showcase

Practical usage patterns across PSR-16, namespace invalidation, multi-worker pools, and Symfony integration.

<?php
use Orieg\JudyCache\JudySimpleCache;

// Initialize high-performance in-memory cache
$cache = new JudySimpleCache();

// Standard PSR-16 operations
$cache->set('user.profile.42', ['name' => 'Nicolas', 'role' => 'admin'], $ttl = 300);

$profile = $cache->get('user.profile.42');
$exists  = $cache->has('user.profile.42');

// Bulk operations
$cache->setMultiple([
    'stats.hits' => 1024,
    'stats.miss' => 12,
], 3600);

$items = $cache->getMultiple(['stats.hits', 'stats.miss']);
<?php
use Orieg\JudyCache\JudySimpleCache;

$cache = new JudySimpleCache();

// Populate structured namespace keys
$cache->set('tenant.101.orders.1', $order1);
$cache->set('tenant.101.orders.2', $order2);
$cache->set('tenant.102.orders.1', $otherOrder);

// Invalidate all keys under tenant 101 in 53 microseconds flat
$deletedCount = $cache->deletePrefix('tenant.101.');

// Extract all keys under a prefix without scanning entire cache
$tenantKeys = $cache->keysByPrefix('tenant.102.');
<?php
use Orieg\JudyCache\JudySimpleCache;
use Orieg\JudyCache\Storage\SharedMemoryPool;

// Allocate 64 MB zero-copy shared memory segment across worker processes
$shm = new SharedMemoryPool($shmKey = 0x1234, $size = 64 * 1024 * 1024);

// Attach cache instance to shared segment
$cache = new JudySimpleCache(
    shmPool: $shm,
    enableInterning: true // Content-addressable payload deduplication
);

$cache->set('shared.heavy.document', $jsonBlob);
<?php
use Orieg\JudyCache\JudySimpleCache;

// Enable adaptive transparent compression for large payloads
$cache = new JudySimpleCache(
    compressionThreshold: 1024,     // Only compress payloads >= 1 KB
    compressionCodec:     'zstd',   // 'zstd', 'lz4', 'gzip', or 'deflate'
    compressionLevel:     3
);

// Compressed automatically; if compressed size >= raw, stores raw
$cache->set('huge.html.render', $renderedHtml);
<?php
use Orieg\JudyCache\Adapter\JudyAdapter;

// Use as a PSR-6 / Symfony Cache pool adapter
$pool = new JudyAdapter(
    namespace: 'app.cache',
    defaultLifetime: 3600
);

$item = $pool->getItem('config.routes');
if (!$item->isHit()) {
    $item->set($routes);
    $pool->save($item);
}
Benchmark Shootout

Empirical measurements across 1,000,000 cached items comparing memory footprint and invalidation scaling.

Peak Host RAM: 1,000,000 Cached Items

Measured VmRSS in separate process.

judy-cache (STRING_TO_ENTRY)172.4 MB (-88%)
APCu (Shared Memory Segment)294.1 MB (-79%)
Native PHP Array495.2 MB (-65%)
Symfony ArrayAdapter921.6 MB (-34%)
Symfony TagAwareAdapter1,420.0 MB (Baseline)

Namespace Drop (1M Entries)

Latency to invalidate a sub-namespace slice.

judy-cache (deletePrefix)53 µs (17,000x faster)
APCu (Regex Key Sweep)81,000 µs (81 ms)
Symfony ArrayAdapter900,000 µs (900 ms)
Installation

Install via Composer in any PHP 8.1+ project.

Composer Setup

composer require orieg/judy-cache

For optimal performance, install the native C extension via pie install orieg/judy. If the extension is absent, judy-cache automatically runs on the pure-PHP polyfill.