Data-Queue-Shared

 view release on metacpan or  search on metacpan

lib/Data/Queue/Shared.pm  view on Meta::CPAN

        $child->push(99);
        exit;
    }
    wait;
    print $q->pop;  # 99

=head1 DESCRIPTION

Data::Queue::Shared provides bounded MPMC (multi-producer, multi-consumer)
queues stored in file-backed shared memory (C<mmap(MAP_SHARED)>), enabling
efficient multiprocess data sharing on Linux.

B<Linux-only>. Requires 64-bit Perl.

=head2 Variants

=over

=item L<Data::Queue::Shared::Int> - int64 values, lock-free (16 bytes/slot)

Uses the Vyukov bounded MPMC algorithm. Push and pop are lock-free
(CAS-based). Optimal for integer job IDs, counters, indices.

=item L<Data::Queue::Shared::Int32> - int32 values, lock-free (8 bytes/slot)

=item L<Data::Queue::Shared::Int16> - int16 values, lock-free (8 bytes/slot)

Compact variants with 32-bit Vyukov sequence numbers. Half the memory
footprint per slot = double the cache density. Same lock-free algorithm.
Same API as Int. Values outside the type range are silently truncated
(standard C cast semantics).

=item L<Data::Queue::Shared::Str> - byte string values, mutex-protected

Uses a futex-based mutex with a circular arena for variable-length string
storage. Supports UTF-8 flag preservation. Optimal for messages,
serialized data, filenames.

Memory-efficient for mixed lengths (short + occasional long strings share
the arena), but throughput degrades under heavy multi-producer contention
because all pushes serialize on one mutex.

B<For fixed-length FIFO workloads that need maximum throughput:> use
L<Data::Deque::Shared::Str> with only C<push_back> / C<pop_front>. It's
fixed-slot-per-entry (memory use = capacity x max_len), uses a per-slot
publication state machine instead of a shared mutex, and measures
1.3x-4.7x faster than Queue::Str depending on contention (1 vs 8 writers,
32-byte payloads, single box). Use that if your messages share an upper
bound and you want lock-free-style scaling.

=back

=head2 Features

=over

=item * File-backed mmap for cross-process sharing

=item * Lock-free MPMC for integer queues (Vyukov algorithm)

=item * Futex-based blocking wait with timeout (no busy-spin)

=item * PID-based stale lock recovery (dead process detection)

=item * Batch push/pop operations

=item * Circular arena for zero-fragmentation string storage

=item * Optional keyword API via XS::Parse::Keyword (zero method-dispatch overhead)

=back

=head2 Constructor

    # Int queue
    my $q = Data::Queue::Shared::Int->new($path, $capacity);

    # Str queue
    my $q = Data::Queue::Shared::Str->new($path, $capacity);
    my $q = Data::Queue::Shared::Str->new($path, $capacity, $arena_bytes);

Creates or opens a shared queue backed by file C<$path>.
C<$capacity> is rounded up to the next power of 2.
When opening an existing file, parameters are read from the stored header.
Multiple processes can open the same file simultaneously.

Pass C<undef> for C<$path> to create an anonymous queue using
C<MAP_SHARED|MAP_ANONYMOUS>. Anonymous queues are shared with child
processes via C<fork()> but cannot be opened by unrelated processes.

=head2 memfd Constructor

    my $q = Data::Queue::Shared::Int->new_memfd($name, $capacity);
    my $q = Data::Queue::Shared::Str->new_memfd($name, $capacity);
    my $q = Data::Queue::Shared::Str->new_memfd($name, $cap, $arena);

Creates a queue backed by C<memfd_create(2)>. No filesystem path -- the
backing memory is identified by a file descriptor. Use C<memfd()> to
retrieve the fd and pass it to other processes via C<SCM_RIGHTS>
(Unix domain socket fd passing) or C<fork()> inheritance.

    my $q2 = Data::Queue::Shared::Int->new_from_fd($fd);
    my $q2 = Data::Queue::Shared::Str->new_from_fd($fd);

Opens a queue from a received memfd. The fd is dup'd internally.

    my $fd = $q->memfd;    # backing fd (-1 if file-backed/anonymous)

For Str queues, C<$arena_bytes> sets the string storage arena size
(default: C<$capacity * 256>, minimum 4096, maximum 4GB). Strings are
stored in a circular arena; total stored string bytes cannot exceed the
arena capacity. Individual strings are limited to ~2GB.

=head2 API

=head3 Core operations

    my $ok  = $q->push($value);             # non-blocking, false if full
    my $val = $q->pop;                       # non-blocking, undef if empty
    my $ok  = $q->push_wait($value);         # blocking, infinite wait
    my $ok  = $q->push_wait($value, $secs);  # blocking with timeout



( run in 1.946 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )