=pod =encoding UTF-8 =head1 NAME Riak::Client - Fast and lightweight Perl client for Riak =head1 VERSION version 1.95 =head1 SYNOPSIS use Riak::Client; # normal mode my $client = Riak::Client->new( host => '127.0.0.1', port => 8087, r => 2, w => 2, dw => 1, connection_timeout => 5, read_timeout => 5, write_timeout => 5, no_auto_connect => 0, ); $client->is_alive() or die "riak is not alive"; # store hashref. will be serialized as JSON $client->put( 'bucket_name', 'key_name', { some => 'structure' } ); # store text $client->put( 'bucket_name', 'key_name', 'sometext', 'text/plain' ); # store raw data $client->put_raw( 'bucket_name', 'key_name', 'rawdata' ); # fetch hashref my $hash = $client->get( 'bucket_name', 'key_name' ); # fetch raw data my $text = $client->get_raw( 'bucket_name', 'key_name'); # delete data $client->del( 'bucket_name', 'key_name'); # list keys in stream $client->get_keys(foo => sub{ my ($key, $done) = @_; # you should use another client inside this callback! $another_client->del(foo => $key); }); =head1 DESCRIPTION Riak::Client is a fast and light Perl client for Riak using PBC interface It supports operations like ping, get, exists, put, del, secondary indexes (so-called 2i) setting and querying, and Map Reduce querying. It started as a fork of C<Riak::Light> to fix some bugs, but actually ended up in a complete rewrite with more features, but the same performance. =head1 ATTRIBUTES =head2 host Str, Required. Riak IP or hostname. =head2 port Int, Required. Port of the PBC interface. =head2 r Int, Default 2. R value setting for this client. =head2 w Int, Default 2. W value setting for this client. =head2 dw Int, Default 1. DW value setting for this client. =head2 connection_timeout Float, Default 5. Timeout for connection operation, in seconds. Set to 0 for no timeout. =head2 read_timeout Float, Default 5. Timeout for read operation, in seconds. Set to 0 for no timeout. =head2 no_delay Boolean, Default 0. If set to a true value, TCP_NODELAY will be enabled on the socket, which means deactivating Nagle's algorithm. Use only if you know what you're doing. =head2 no_auto_connect Bool, Default 0. If set to true, then the module won't automatically connect upon instanciation. Instead, you'll have to call C<connect()> yourself. =head1 METHODS =head2 connect $client->connect(); $client->connect($coderef); Connects to the Riak server. On error, will raise an exception. This is automatically done when C<new()> is called, unless the C<no_auto_connect> attribute is set to true. Accepts an optional callback, that will be executed when connected. =head2 ping( [$cb->()] ) my $result = $client->ping(); $client->ping(sub { print "ping successful\n" }); Performs a ping operation. On error, will raise an exception. Accepts an optional callback (a CodeRef), that will be executed upon completion. # an other example use Try::Tiny; try { $client->ping() } catch { "oops... something is wrong: $_" }; See also C<is_alive()>. =head2 is_alive( [$cb->($bool)] ) my $is_alive = $client->is_alive(); $client->is_alive($coderef); Checks if the connection is alive. Returns true or false. On error, will raise an exception. Accepts an optional callback, that will be executed upon completion. =head2 get( $bucket, $key, [$cb->($value)] ) my $value = $client->get($bucket, $key); $client->get($bucket, $key, $coderef); Performs a fetch operation. Expects bucket and key names. Returns the value. On error, will raise an exception. Accepts an optional callback, that will be called upon completion, with the value as first argument. If the content_type of the fetched value is C<'application/json'>, automatically decodes the JSON into a Perl structure. If you need the raw data you can use C<get_raw>. =head2 get_raw( $bucket, $key, [$cb->($value)] ) my $value = $client->get_raw($bucket, $key); $client->get_raw($bucket, $key, $coderef); Same as C<get>, but no automatic JSON decoding will be performed. If you want JSON to be automatically decoded, you should use C<get()> instead. =head2 put( $bucket, $key, $value, [ $mime_type, $secondary_indexes, $links ], [ $cb->($value) ] ) $client->put($bucket, $key, $value); $client->put($bucket, $key, $value, $coderef); $client->put($bucket, $key, $value, $mime_type, $coderef); $client->put($bucket, $key, $value, $mime_type, $secondary_indexes, $coderef); $client->put($bucket, $key, $value, $mime_type, $secondary_indexes, $links, $coderef); Performs a store operation. Expects bucket and key names, the value, the content type (optional, default is 'application/json'), the indexes to set for this value (optional, default is none), the links to set for this value (optional, default is none), and an optional coderef. On error, will raise an exception Will encode the structure in json string if necessary. If you need to store the raw data you should use C<put_raw> instead. B<IMPORTANT>: all the index field names should end by either C<_int> or C<_bin>, depending if the index type is integer or binary. To query secondary indexes, see C<query_index>. $client->put('bucket', 'key', { some_values => [1,2,3] }); $client->put('bucket', 'key', { some_values => [1,2,3] }, 'application/json'); $client->put('bucket', 'key', 'text', 'plain/text'); # you can set secondary indexes (2i) $client->put( 'bucket', 'key', 'text_value', 'plain/text', { field1_bin => 'abc', field2_int => 42 } ); $client->put( 'bucket', 'key', { some_values => [1,2,3] }, undef, { field1_bin => 'abc', field2_int => 42 } ); # you can also set links $client->put( 'bucket', 'key', 'text', 'plain/text', undef, { link_tag1 => 'bucket/key', link_tag2 => 'other_bucket/key', } ); # you can set multiple links for the same tag $client->put( 'bucket', 'key', 'text', 'plain/text', undef, { link_tag1 => [ qw( bucket/key bucket2/key2 ) ], link_tag2 => 'other_bucket/key', } ); # you can also use this form (marginally faster) $client->put( 'bucket', 'key', 'text', 'plain/text', undef, [ { tag => 'link_tag1', bucket => 'bucket1', key => 'key1'}, { tag => 'link_tag2', bucket => 'bucket2', key => 'key2'}, ], ); =head2 put_raw ( $bucket, $key, $value, [ $mime_type, $secondary_indexes, $links ], [ $cb->($value) ] ) $client->put_raw('bucket', 'key', encode_json({ some_values => [1,2,3] }), 'application/json'); $client->put_raw('bucket', 'key', 'text'); $client->put_raw('bucket', 'key', 'text', undef, {field_bin => 'foo'}); $client->put_raw('bucket', 'key', 'text', undef, {field_bin => 'foo'}, $links); For more example, see C<put>. Perform a store operation. Expects bucket and key names, the value, the content type (optional, default is 'plain/text'), the indexes (optional, default is none), and links (optional, default is none) to set for this value This method won't encode the data, but pass it as such, trusting it's in the type you've indicated in the passed content-type. If you want the structure to be automatically encoded, use C<put> instead. B<IMPORTANT>: all the index field names should end by either C<_int> or C<_bin>, depending if the index type is integer or binary. To query secondary indexes, see C<query_index>. =head2 del ( $bucket, $key, [ $cb->() ] ) $client->del(bucket => key); Perform a delete operation. Expects bucket and key names. =head2 get_keys( $bucket, $cb->($key, $bool) ) # in default mode $client->get_keys(foo => sub{ my ($key, $done) = @_; # you should use another client inside this callback! $another_client->del(foo => $key); }); B<WARNING>, this method should not be called on a production Riak cluster, as it can have a big performance impact. See Riak's documentation. B<WARNING>, because Riak doesn't handles pipelining, you cannot use the same C<Riak::Client> instance inside the callback, it would raise an exception. Perform a list keys operation. Receive a callback and will call it for each key. The callback will receive two arguments: the key, and a boolean indicating if it's the last key. The callback is optional. If not provided C<get_keys()> will return an ArrayRef of B<all> the keys. Don't do that, and always provide a callback, to avoid your RAM usage to skyrocket... =head2 exists($bucket, $key, [ $cb->($bool) ] ) $client->exists(bucket => 'key') or warn "key not found"; Perform a fetch operation but with head => 0, and the if there is something stored in the bucket/key. =head2 query_index( $bucket, $index, $value, [ $cb->($key) ] ) Perform a secondary index (2i) query. Expects a bucket name, the index field name, the index value you're searching on, and optionally a callback. If a callback has been provided, doesn't return anything, but executes the callback on each matching keys. callback will receive the key name as first argument. key name will also be in C<$_>. If no callback is provided, returns and ArrayRef of matching keys. The index value you're searching on can be of two types. If it's a Scalar, an B<exact match> query will be performed. if the value is an ArrayRef, then a B<range> query will be performed, the first element in the array will be the range_min, the second element the range_max. other elements will be ignored. Based on the example in C<put>, here is how to query it: # exact match my $matching_keys = $client->query_index( 'bucket', 'field2_int', 42 ), # range match my $matching_keys = $client->query_index( 'bucket', 'field2_int', [ 40, 50] ), # range match with callback $client->query_index( 'bucket', 'field2_int', [ 40, 50], sub { print "key : $_" } ), =head2 get_buckets( [ $cb->($buckets) ] ) B<WARNING>, this method should not be called on a production Riak cluster, as it can have a big performance impact. See Riak's documentation. =head2 get_bucket_props($bucket, [ $cb->($properties) ] ) =head2 set_bucket_props($bucket, $properties) =head2 map_reduce Perform a map/reduce operation. # using a javascript function my $json_hash = { inputs => 'training', query => [{ map => { language =>"javascript", source =>"function(riakObject) { var val = riakObject.values[0].data.match(/pizza/g); return [[riakObject.key, (val ? val.length : 0 )]]; }" } }] }; # using an erlang function my $json_hash = { inputs => 'messages', query => [{ map => { language => 'erlang', module => 'mr_example', function => 'get_keys' } }] }; $client->map_reduce($json_hash, sub { ... }); =head1 BENCHMARKS Note: These benchmarks are the one provided by C<Riak::Light>. =head2 GETS Rate Data::Riak (REST) Riak::Tiny (REST) Net::Riak (REST) Data::Riak::Fast (REST) Net::Riak (PBC) Riak::Client Riak::Light (PBC) Riak::Client (PBC) Data::Riak (REST) 427/s -- -30% -31% -43% -65% -90% -91% Riak::Tiny (REST) 611/s 43% -- -2% -19% -51% -86% -87% Net::Riak (REST) 623/s 46% 2% -- -17% -50% -86% -87% Data::Riak::Fast (REST) 755/s 77% 24% 21% -- -39% -83% -84% Net::Riak (PBC) 1238/s 190% 103% 99% 64% -- -72% -74% Riak::Light (PBC) 4348/s 917% 612% 598% 476% 251% -- -8% Riak::Client (PBC) 4706/s 1001% 671% 655% 524% 280% 8% -- =head2 PUTS Rate Net::Riak (REST) Data::Riak (REST) Riak::Tiny (REST) Data::Riak::Fast (REST) Net::Riak (PBC) Riak::Light (PBC) Riak::Client (PBC) Net::Riak (REST) 542/s -- -15% -29% -55% -57% -90% -92% Data::Riak (REST) 635/s 17% -- -17% -47% -49% -89% -90% Riak::Tiny (REST) 765/s 41% 20% -- -36% -39% -86% -88% Data::Riak::Fast (REST) 1198/s 121% 89% 57% -- -4% -79% -82% Net::Riak (PBC) 1254/s 131% 97% 64% 5% -- -78% -81% Riak::Light (PBC) 5634/s 939% 787% 637% 370% 349% -- -14% Riak::Client (PBC) 6557/s 1110% 933% 757% 448% 423% 16% -- =for Pod::Coverage BUILD =head1 SEE ALSO L<Net::Riak> L<Data::Riak> L<Data::Riak::Fast> L<Action::Retry> L<Riak::Light> =head1 CONTRIBUTORS Ivan Kruglov <ivan.kruglov@yahoo.com> =head1 AUTHOR Damien Krotkine <dams@cpan.org> =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Damien Krotkine. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut