Data-SortedSet-Shared
view release on metacpan or search on metacpan
lib/Data/SortedSet/Shared/Strings.pm view on Meta::CPAN
$self->_decode($opt{withscores}, $self->{set}->range_by_score($min, $max, %opt));
}
sub rev_range_by_score {
my ($self, $max, $min, %opt) = @_;
$self->_decode($opt{withscores}, $self->{set}->rev_range_by_score($max, $min, %opt));
}
# ---- pop / peek (id -> string) ----
for my $m (qw(pop_min pop_max peek_min peek_max)) {
no strict 'refs';
*$m = sub {
my ($id, $score) = $_[0]{set}->$m;
return defined $id ? ($_[0]{keys}->string($id), $score) : ();
};
}
# ---- iteration ----
sub each {
my ($self, $cb) = @_;
my $k = $self->{keys};
$self->{set}->each(sub { $cb->($k->string($_[0]), $_[1]) });
return;
}
# ---- lifecycle ----
sub sync { $_[0]{set}->sync; $_[0]{keys}->sync; return }
sub unlink { $_[0]{set}->unlink; $_[0]{keys}->unlink; return }
sub stats { { set => $_[0]{set}->stats, keys => $_[0]{keys}->stats } }
1;
__END__
=encoding utf-8
=head1 NAME
Data::SortedSet::Shared::Strings - string-keyed shared-memory sorted set (ZSET)
=head1 SYNOPSIS
use Data::SortedSet::Shared::Strings;
# anonymous (fork-shared); or pass set => $path, keys => $path for file-backed
my $z = Data::SortedSet::Shared::Strings->new(max => 1_000_000);
$z->add("alice", 1500);
$z->incr("alice", 50); # 1550
my @top = $z->rev_range_by_rank(0, 9); # ("alice", "bob", ...)
my $score = $z->score("alice");
my ($who, $sc) = $z->pop_min; # remove + return the lowest
=head1 DESCRIPTION
A string-keyed sorted set in shared memory: the same API as
L<Data::SortedSet::Shared> but with B<string members> instead of int64 ids. It is
a thin layer composing two shared structures -- a L<Data::SortedSet::Shared> for
the (id, score) ordering and a L<Data::Intern::Shared> mapping each string key to
a dense id. Keys are interned on the way in and decoded back to strings on the way
out.
Because both backing stores live in shared memory, the set works B<across
processes>: every process resolves a key to the same id, so a string-keyed
leaderboard, priority queue, or rate limiter can be shared by many workers.
Ties among equal scores break by interning id (roughly insertion order of
first-seen keys), B<not> lexicographically. Keys are interned by byte content and
stay interned until C<clear> (see L<Data::Intern::Shared/LIMITS>). B<Linux-only>, 64-bit Perl.
=head1 METHODS
=head2 Construction
my $z = Data::SortedSet::Shared::Strings->new(
max => $max_members, # required
set => $path_or_undef, # SortedSet backing (undef = anonymous)
keys => $path_or_undef, # Intern backing (undef = anonymous)
max_keys => $max_members, # distinct-key capacity (default: max)
arena => $bytes, # key-arena bytes (default: max_keys * 32)
mode => $octal, # file mode for both backing files (default: 0600)
);
my $z = Data::SortedSet::Shared::Strings->wrap($set, $intern);
C<new> creates (or reopens) both backing stores; for cross-process file-backed use,
every process passes the same C<set>/C<keys> paths. C<mode> sets the file mode for
both backing files (default 0600, subject to umask); it is used only when a file is
created and ignored when attaching an existing one. C<wrap> wraps two
already-constructed objects (e.g. memfd-backed ones shared by fd). C<set> and
C<key_table> return the underlying L<Data::SortedSet::Shared> and
L<Data::Intern::Shared> objects.
=head2 API
Every method takes/returns B<string> members; otherwise the semantics are exactly
those of L<Data::SortedSet::Shared>:
$z->add($str, $score); # 1 new / 0 updated / undef if a pool is full
$z->incr($str, $delta); # add to the score (creates the key if absent); returns the new score
$z->remove($str); # true if removed, false if absent
$z->add_many([ [$s1,$sc1], ... ]);
$z->clear;
$z->score($str); $z->rank($str); $z->rev_rank($str); $z->exists($str);
$z->count; $z->count_in_score($min, $max);
$z->at_rank($r);
$z->range_by_rank($start, $stop, %opts); # ($str, ...) or ($str,$score,...) with withscores
$z->rev_range_by_rank($start, $stop, %opts);
$z->range_by_score($min, $max, %opts); # limit / offset / withscores
$z->rev_range_by_score($max, $min, %opts);
my ($str, $score) = $z->pop_min; # pop_max / peek_min / peek_max
$z->each(sub { my ($str, $score) = @_; ... });
$z->sync; $z->unlink; $z->stats; # stats: { set => {...}, keys => {...} }
C<remove> leaves the key interned (ids are stable); the key universe (C<max_keys>)
must therefore accommodate every distinct key ever added, not just those currently
( run in 2.727 seconds using v1.01-cache-2.11-cpan-600a1bdf6e4 )