AnyEvent-KVStore-Etcd

 view release on metacpan or  search on metacpan

lib/AnyEvent/KVStore/Etcd.pm  view on Meta::CPAN

but there are some important limitations discussed here.

This module can also be used directly for simplified access to an Etcd database.

=head2 AnyEvent Loops, Callbacks, and KVStore Operations

Net::Etcd uses L<AnyEvent::HTTP> for its transport layer.  It further blocks in
an L<AnyEvent> loop to wait for the response.  For obvious reasons, this does
not work.  So, the main key/value operations cannot be done from inside an
event loop.  This leads to a number of possible solutions including forking and
running the request in another process.

One option, though it does incur significant startup cost, is to use L<Coro>
and move the callback from a C<sub {}> call to an C<unblock_sub {}> call.  This
is probably the simplest approach and it works.  In general you get sequential
ordering but this is not a hard guarantee.  Another approach might be to move
processing into worker threads.

=head1 ATTRIBUTES/ACCESSORS

If accessing the module directly, the following accessors are available.  These
are not generally needed and are mostly used internally for managing the
connection to the etcd server.

These are also keys for the config hash.

All attributes are optional.

=head2 host Str

This is the hostname for the etcd connection.  It defaults to localhost.

=cut

has host => (is => 'ro', isa => Str, default => sub { 'localhost' });

=head2 port Int

Port for connection.  It defaults to 2379.

=cut

has port => (is => 'ro', isa => Int, default => sub { 2379 } );

=head2 ssl Bool default false

whether to use SSL or not.  The default is no.

=cut

has ssl => (is => 'ro', isa => Bool, default => 0);

=head2 user Str

Username for authentication.  Does not authenticate if not set.

=cut

has user => (is => 'ro', isa => Str);

=head2 password Str

Password for authentication.

=cut


has password => (is => 'ro', isa => Str);

=head2 cnx Net::Etcd

This is the active connection to the etcd database.

=cut

# $self->_slice returns a hashref with the properties requested.
# This relies on the fact that Moo(se) objects are blessed hashrefs.

sub _slice {
    my $self = shift;
    my @vars = @_;
    return { %{$self}{@vars} };
}

sub _etcd_connect {
    my $self = shift;
    my $cnx = Net::Etcd->new($self->_slice('host', 'port', 'ssl'));
    die 'Could not create new etcd connection' unless $cnx;
    $cnx->auth($self->_slice('user', 'password'))->authenticate if $self->user;
    return $cnx;
}


has cnx => (is => 'ro', builder => '_etcd_connect', lazy => 1);

=head1 METHODS

=head2 read

Reads a value from a key and returns a JSON document payload.

=cut

sub read($$) {
    my ($self, $key) = @_;
    my $value =  $self->cnx->range({key => $key })->{response}->{content};
    $value = decode_json($value)->{kvs}->[0]->{value};
    return decode_base64($value);
}



=head2 exists

Checks to see if a key exists.  Here this is no less costly than read.

=cut

sub exists($$) {
    my ($self, $key) = @_;
    my $value =  $self->cnx->range({key => $key })->{response}->{content};
    $value = decode_json($value)->{kvs}->[0]->{value};
    return defined $value;;
}

=head2 list($pfx)

Returns a list of keys

=cut

# adds one to the binary representation of the string for prefix searches
sub _add_one($){
    my ($str) = @_;
    if ($str =~ /^\xff*$/){ # for empty string too
        return "\x00";
    }
    my $inc = $str;
    $inc =~ s/([^\xff])\xff*\z/ $1 =~ tr||\x01-\xff|cr /e;
    return $inc;
}

sub list($$) {
    my ($self, $pfx) = @_;
    my $value =  $self->cnx->range({key => $pfx, range_end => _add_one($pfx)})->{response}->{content};
    return  map { decode_base64($_->{key} ) }  @{decode_json($value)->{kvs}};
}




( run in 0.950 second using v1.01-cache-2.11-cpan-bbe5e583499 )