Packet Pools

  1. Packet Pools

    Complete examples for different packet pooling strategies.

    Pool Types Overview

    Pool Type
    Data Memory
    Descriptor Memory
    Use Case

    Scoped

    ScopedMemory

    ScopedMemory

    Zero-copy capture

    Fixed

    FixedMemory (slab)

    FixedMemory (slab)

    Copied packets

    Bucketed

    FixedMemory (sized)

    FixedMemory (slab)

    Variable sizes

    Hybrid

    ScopedMemory

    FixedMemory (arena)

    Zero-copy + descriptor conversion

    Scoped Packet Pool (Zero-Copy)

    For maximum performance with native capture backends (DPDK, Napatech):

    PoolSettings settings = new PoolSettings()
        .minCapacity(1000)
        .maxCapacity(10000);
    
    // One-liner
    FreeListPool<Packet> scopedPool = new FreeListPool<>(settings, Packet::ofScoped);

    Capture Loop

    while (capturing) {
        Packet packet = scopedPool.allocate();
        
        // Bind to native packet data (zero-copy)
        packet.memory().bind(nativeDataSegment, dataOffset, dataLength);
        packet.descriptor().memory().bind(nativeDescSegment, descOffset, descLength);
        
        // Process - direct access to native memory
        processPacket(packet);
        
        // Unbind and recycle
        packet.memory().unbind();
        packet.descriptor().memory().unbind();
        packet.recycle();
    }

    Bucketed Fixed Packet Pool (Variable Sizes)

    For mixed packet sizes with minimal memory waste:

    long[] packetSizes = {64, 1518, 9000, 16384, 65536};
    
    PoolSettings settings = new PoolSettings()
        .minCapacity(100)
        .maxCapacity(1000);
    
    // One-liner - Packet::ofFixed matches BucketFactory signature perfectly
    BucketPool<Packet> bucketPool = new BucketPool<>(settings, packetSizes, Packet::ofFixed);

    Capture Loop

    while (capturing) {
        int packetSize = getPacketSize(nativePacket);
        
        // Allocate from smallest fitting bucket
        Packet packet = bucketPool.allocate(packetSize);
        if (packet == null) continue;
        
        // Copy data
        packet.memory().segment().copyFrom(nativeData, 0, packetSize);
        
        // Process
        processPacket(packet);
        
        // Recycle - returns to correct bucket automatically
        packet.recycle();
    }

    Bucket Metrics

    PoolMetrics metrics = bucketPool.metrics();
    
    System.out.printf("Total: %d allocations%n", metrics.allocations());
    
    for (int i = 0; i < metrics.bucketCount(); i++) {
        System.out.printf("Bucket[%d] %d bytes: %d allocs%n",
            i, metrics.bucketSize(i), metrics.allocations(i));
    }

    Hybrid Packet Pool (Scoped Data + Fixed Descriptor)

    Zero-copy data with descriptor conversion capability:

    PoolSettings settings = new PoolSettings()
        .minCapacity(1000)
        .maxCapacity(10000);
    
    // One-liner - descriptor allocated from Arena.ofShared()
    FreeListPool<Packet> hybridPool = new FreeListPool<>(settings, Packet::ofHybrid);

    Capture Loop

    while (capturing) {
        Packet packet = hybridPool.allocate();
        
        // Bind data to native (zero-copy)
        packet.memory().bind(nativeDataSegment, dataOffset, dataLength);
        
        // Convert native descriptor to our format (into fixed memory)
        convertDescriptor(nativeDescriptor, packet.descriptor());
        
        // Process
        processPacket(packet);
        
        // Unbind data only (descriptor stays in fixed memory)
        packet.memory().unbind();
        packet.recycle();
    }

    Summary: Pool Creation One-Liners

    // Scoped - zero-copy capture
    var scopedPool = new FreeListPool<>(settings, Packet::ofScoped);
    
    // Bucketed - variable size copy
    var bucketPool = new BucketPool<>(settings, sizes, Packet::ofFixed);
    
    // Hybrid - zero-copy data + fixed descriptor
    var hybridPool = new FreeListPool<>(settings, Packet::ofHybrid);

    All three use method references - no lambda expressions needed!

    Complete Example

    public class PacketProcessingExample {
        
        public static void main(String[] args) {
            // === Scoped Pool (Zero-Copy) ===
            var scopedPool = new FreeListPool<Packet>(
                new PoolSettings().capacity(10000),
                Packet::ofScoped
            );
            
            // === Bucketed Pool (Variable Sizes) ===
            var bucketPool = new BucketPool<Packet>(
                new PoolSettings().minCapacity(100).maxCapacity(1000),
                new long[]{64, 1518, 9000, 65536},
                Packet::ofFixed
            );
            
            // === Hybrid Pool (Scoped Data + Fixed Descriptor) ===
            var hybridPool = new FreeListPool<Packet>(
                new PoolSettings().capacity(10000),
                Packet::ofHybrid
            );
            
            // Use appropriate pool
            processWithPool(scopedPool);
            
            // Cleanup
            scopedPool.close();
            bucketPool.close();
            hybridPool.close();
        }
    }

    Performance Tips

    1. Size pools appropriately - minCapacity handles typical load without growth

    2. Use scoped pools for maximum throughput when data doesn't persist

    3. Use bucketed pools for mixed sizes to minimize memory waste

    4. Use hybrid pools when you need descriptor conversion with zero-copy data

    5. Per-thread pools for multi-threaded processing to avoid contention

Last updated