root/lang/perl/Cache-Memcached-libmemcached/trunk/lib/Cache/Memcached/libmemcached.pm @ 5726

Revision 5726, 13.9 kB (checked in by daisuke, 5 years ago)

lang/perl/Cache-Memcached-LibMemcached?; now you can export everything that Memcached::libmemcached can export

  • Property svn:keywords set to Id
Line 
1# $Id$
2#
3# Copyright (c) 2008 Daisuke Maki <daisuke@endeworks.jp>
4# All rights reserved.
5
6package Cache::Memcached::libmemcached;
7use strict;
8use warnings;
9use Carp qw(croak);
10use Memcached::libmemcached ();
11use Storable ();
12
13our $VERSION = '0.01000';
14
15use constant MEMD_BACKEND            => 0;
16use constant MEMD_COMPRESS_ENABLE    => 1;
17use constant MEMD_COMPRESS_THRESHOLD => 2;
18use constant MEMD_COMPRESS_SAVINGS   => 3;
19
20use constant HAVE_ZLIB    => eval { require Compress::Zlib } && !$@;
21use constant F_STORABLE   => 1;
22use constant F_COMPRESS   => 2;
23
24BEGIN
25{
26    # accessors
27    foreach my $field qw(compress_enable compress_threshold compress_savings) {
28        eval sprintf(<<"        EOSUB", $field, uc $field, $field, uc $field);
29            sub set_%s {
30                my \$self = shift;
31                \$self->[ MEMD_%s ] = shift;
32            }
33
34            sub get_%s {
35                shift->[ MEMD_%s ];
36            }
37        EOSUB
38        die if $@;
39    }
40
41    # proxy these methods
42    foreach my $method qw(delete get set add replace prepend append cas) {
43        eval <<"        EOSUB";
44            sub $method {
45                Memcached::libmemcached::memcached_$method(shift->[MEMD_BACKEND], \@_)
46            }
47        EOSUB
48        die if $@;
49    }
50}
51
52sub import
53{
54    my $class = shift;
55    Memcached::libmemcached->export_to_level(1, undef, @_) ;
56}
57
58sub new
59{
60    my $class = shift;
61    my $args  = shift || {};
62
63    $args->{servers} || die "No servers specified";
64
65    my $memd  = Memcached::libmemcached::memcached_create();
66    my $self = bless [], $class;
67
68    $self->[MEMD_BACKEND]            = $memd;
69    $self->[MEMD_COMPRESS_THRESHOLD] = $args->{compress_threshold};
70    $self->[MEMD_COMPRESS_SAVINGS]   = $args->{compress_savings} || 0.20;
71    $self->[MEMD_COMPRESS_ENABLE]    =
72        exists $args->{compress_enable} ? $args->{compress_enable} : 1;
73
74    # servers
75    $self->set_servers($args->{servers});
76
77    # Set compression/serialization callbacks
78    Memcached::libmemcached::memcached_set_callback_coderefs($memd,
79        # Closures so we have reference to $self
80        $self->_mk_callbacks()
81    );
82
83    # behavior options
84    $self->set_no_block( $args->{no_block} ) if exists $args->{no_block};
85
86    return $self;
87}
88
89sub set_servers
90{
91    my $self = shift;
92    my $servers = shift || [];
93    foreach my $server (@$servers) {
94        $self->server_add($server);
95    }
96}
97
98sub server_add
99{
100    my $self = shift;
101    my $server = shift;
102
103    # check for existance of :
104    if (my ($hostname, $port) = split(/:/, $server)) {
105        Memcached::libmemcached::memcached_server_add( $self->[MEMD_BACKEND], $hostname, $port );
106    } else {
107        Memcached::libmemcached::memcached_server_add_unix( $self->[MEMD_BACKEND], $server );
108    }
109}
110
111sub get_multi
112{
113    my $self = shift;
114    my $hv = {};
115    Memcached::libmemcached::memcached_mget_into_hashref($self->[MEMD_BACKEND], [ @_ ], $hv);
116    return $hv;
117}
118
119sub _mk_callbacks
120{
121    my $self = shift;
122
123    my $inflate = sub {
124        my ($key, $flags) = @_;
125        if ($flags & F_COMPRESS) {
126            if (! HAVE_ZLIB) {
127                croak("Data for $key is compressed, but we have no Compress::Zlib");
128            }
129            $_ = Compress::Zlib::memGunzip($_);
130        }
131
132        if ($flags & F_STORABLE) {
133            $_ = Storable::thaw($_);
134        }
135        return ();
136    };
137
138    my $deflate = sub {
139        # Check if we have a complex structure
140        if (ref $_) {
141            $_ = Storable::nfreeze($_);
142            $_[1] |= F_STORABLE;
143        }
144
145        # Check if we need compression
146        if (HAVE_ZLIB && $self->[MEMD_COMPRESS_ENABLE] && $self->[MEMD_COMPRESS_THRESHOLD]) {
147            # Find the byte length
148            my $length = bytes::length($_);
149            if ($length > $self->[MEMD_COMPRESS_THRESHOLD]) {
150                my $tmp = Compress::Zlib::memGzip($_);
151                if (1 - bytes::length($tmp) / $length < $self->[MEMD_COMPRESS_SAVINGS]) {
152                    $_ = $tmp;
153                    $_[1] |= F_COMPRESS;
154                }
155            }
156        }
157        return ();
158    };
159    return ($deflate, $inflate);
160}
161
162sub incr
163{
164    my $self = shift;
165    $_[0] or croak("No key specified in incr");
166    $_[1] ||= 1 if @_ < 2;
167    my $val = 0;
168    Memcached::libmemcached::memcached_increment($self->[MEMD_BACKEND], @_[0,1], $val);
169    return $val;
170}
171
172sub decr
173{
174    my $self = shift;
175    $_[0] or croak("No key specified in decr");
176    $_[1] ||= 1 if @_ < 2;
177    my $val = 0;
178    Memcached::libmemcached::memcached_decrement($self->[MEMD_BACKEND], @_[0,1], $val);
179    return $val;
180}
181
182sub flush_all
183{
184    my $self = shift;
185    Memcached::libmemcached::memcached_flush($self->[MEMD_BACKEND], 0);
186}
187
188*remove = \&delete;
189
190sub disconnect_all
191{
192    my $self = shift;
193    Memcached::libmemcached::memcached_quit($self->[MEMD_BACKEND]);
194}
195
196sub stats { die "stats() not implemented" }
197
198sub is_no_block
199{
200    my $self = shift;
201    Memcached::libmemcached::memcached_behavior_get(
202        $self->[MEMD_BACKEND],
203        Memcached::libmemcached::MEMCACHED_BEHAVIOR_NO_BLOCK(),
204    );
205}
206
207sub set_no_block
208{
209    my $self = shift;
210    Memcached::libmemcached::memcached_behavior_set(
211        $self->[MEMD_BACKEND],
212        Memcached::libmemcached::MEMCACHED_BEHAVIOR_NO_BLOCK(),
213        $_[0]
214    );
215}
216
2171;
218
219__END__
220
221=head1 NAME
222
223Cache::Memcached::libmemcached - Perl Interface to libmemcached
224
225=head1 SYNOPSIS
226
227  use Cache::Memcached::libmemcached;
228  my $memd = Cache::Memcached::libmemcached->new({
229    servers => [ "10.0.0.15:11211", "10.0.0.15:11212", "/var/sock/memcached" ],
230    compress_threshold => 10_000
231  });
232
233  $memd->set("my_key", "Some value");
234  $memd->set("object_key", { 'complex' => [ "object", 2, 4 ]});
235
236  $val = $memd->get("my_key");
237  $val = $memd->get("object_key");
238  if ($val) { print $val->{complex}->[2] }
239
240  $memd->incr("key");
241  $memd->decr("key");
242  $memd->incr("key", 2);
243
244  $memd->delete("key");
245  $memd->remove("key"); # Alias to delete
246
247  my $hashref = $memd->get_multi(@keys);
248
249=head1 DESCRIPTION
250
251This is the Cache::Memcached compatible interface to libmemcached,
252a C library to interface with memcached.
253
254Cache::Memcached::libmemcached is built on top of Memcached::libmemcached.
255While Memcached::libmemcached aims to port libmemcached API to perl,
256Cache::Memcached::libmemcached attempts to be API compatible with
257Cache::Memcached, so it can be used as a drop-in replacement.
258
259=head1 FOR Cache::Memcached::LibMemcached USERS
260
261Cache::Memcached::libmemcached is a rewrite of Cache::Memcached::LibMemcached,
262using Memcached::libmemcached instead of straight XS as its backend.
263
264Therefore you might notice some differences. Here are the ones we are
265aware of:
266
267=over 4
268
269=item cas() and stats() are not implemented
270
271They were sort of implemented in a previous life, but since
272Memcached::libmemcached is still undecided how to handle these, we don't
273support it either.
274
275=item performance is probably a bit different
276
277To be honest, we haven't ran benchmarks comparing the two (yet). In general,
278you might see a decrease in performance here and there because we've
279essentially added another call stack (instead of going straight from perl to
280XS, we are now going from perl to perl to XS). But on the other hand,
281Memcached::libmemcached is in the hands of XS gurus like Time Bunce, so
282you are probably sparing yourself some accidental hooplas that occasional
283C programmers like me might introduce.
284
285=back
286
287=head1 Cache::Memcached COMPATIBLE METHODS
288
289Except for the minor incompatiblities, below methods are generally compatible
290with Cache::Memcached.
291
292=head2 new
293
294Takes on parameter, a hashref of options.
295
296=head2 set_servers
297
298  $memd->set_servers( [ qw(serv1:port1 serv2:port2 ...) ]);
299
300Sets the server list.
301
302=head2 get
303
304  my $val = $memd->get($key);
305
306Retrieves a key from the memcached. Returns the value (automatically thawed
307with Storable, if necessary) or undef.
308
309Currently the arrayref form of $key is NOT supported. Perhaps in the future.
310
311=head2 get_multi
312
313  my $hashref = $memd->get_multi(@keys);
314
315Retrieves multiple keys from the memcache doing just one query.
316Returns a hashref of key/value pairs that were available.
317
318=head2 set
319
320  $memd->set($key, $value[, $expires]);
321
322Unconditionally sets a key to a given value in the memcache. Returns true if
323it was stored successfully.
324
325Currently the arrayref form of $key is NOT supported. Perhaps in the future.
326
327=head2 add
328
329  $memd->add($key, $value[, $expires]);
330
331Like set(), but only stores in memcache if they key doesn't already exist.
332
333=head2 replace
334
335  $memd->replace($key, $value[, $expires]);
336
337Like set(), but only stores in memcache if they key already exist.
338
339=head2 append
340
341  $memd->append($key, $value);
342
343Appends $value to whatever value associated with $key. Only available for
344memcached > 1.2.4
345
346=head2 prepend
347
348  $memd->prepend($key, $value);
349
350Prepends $value to whatever value associated with $key. Only available for
351memcached > 1.2.4
352
353=head2 incr
354
355=head2 decr
356
357  my $newval = $memd->incr($key);
358  my $newval = $memd->decr($key);
359  my $newval = $memd->incr($key, $offset);
360  my $newval = $memd->decr($key, $offset);
361
362Atomically increments or decrements the specified the integer value specified
363by $key. Returns undef if the key doesn't exist on the server.
364
365=head2 delete
366
367=head2 remove
368
369  $memd->delete($key);
370
371Deletes a key.
372
373XXX - The behavior when second argument is specified may differ from
374Cache::Memcached -- this hasn't been very well tested. Patches welcome!
375
376=head2 flush_all
377
378  $memd->fush_all;
379
380Runs the memcached "flush_all" command on all configured hosts, emptying all
381their caches.
382
383=head2 set_compress_threshold
384
385  $memd->set_compress_threshold($threshold);
386
387Set the compress threshold.
388
389=head2 enable_compress
390
391  $memd->enable_compress($bool);
392
393This is actually an alias to set_compress_enable(). The original version
394from Cache::Memcached is, despite its naming, a setter as well.
395
396=head2 stats
397
398  my $h = $memd->stats();
399
400This method is still half-baked. Patches welcome.
401
402=head2 disconnect_all
403
404Disconnects from servers
405
406=head2 cas
407
408  $memd->cas($key, $cas, $value[, $exptime]);
409
410XXX - This method is still broken.
411
412Sets if $cas matches the value on the server.
413
414=head2 gets
415
416=head2 get_cas
417
418  my $cas = $memd->gets($key);
419  my $cas = $memd->get_cas($key);
420
421Get the CAS value for $key
422
423=head2 get_cas_multi
424
425  my $h = $memd->get_cas_multi(@keys)
426
427Gets CAS values for multiple keys
428
429=head1 Cache::Memcached::libmemcached SPECIFIC METHODS
430
431These methods are libmemcached-specific.
432
433=head2 server_add
434
435Adds a memcached server.
436
437=head2 server_add_unix_socket
438
439Adds a memcached server, connecting via unix socket.
440
441=head2 server_list_free
442
443Frees the memcached server list.
444
445=head1 UTILITY METHODS
446
447WARNING: Please do not consider the existance for these methods to be final.
448They may be renamed or may entirely disappear from future releases.
449
450=head2 get_compress_threshold
451
452Return the current value of compress_threshold
453
454=head2 set_compress_enable
455
456Set the value of compress_enable
457
458=head2 get_compress_enable
459
460Return the current value of compress_enable
461
462=head2 set_compress_savings
463
464Set the value of compress_savings
465
466=head2 get_compress_savings
467
468Return the current value of compress_savings
469
470=head1 BEHAVIOR CUSTOMIZATION
471
472Certain libmemcached behaviors can be configured with the following
473methods.
474
475(NOTE: This API is not fixed yet)
476
477=head2 set_no_block
478
479  Cache::Memcached::libmemcached->new({
480    ...
481    no_block => 1
482  });
483  # or
484  $memd->set_no_block( 1 );
485
486Set to use blocking/non-blocking I/O. When this is in effect, get() becomes
487flaky, so don't attempt to call it. This has the most effect for set()
488operations, because libmemcached stops waiting for server response after
489writing to the socket (set() will also always return success)
490
491Please consult the man page for C<memcached_behavior_set()> for details
492before setting.
493
494=head2 is_no_block
495
496Get the current value of no_block behavior.
497
498=head2 set_distribution_method
499
500  $memd->set_distribution_method( MEMCACHED_DISTRIBUTION_CONSISTENT );
501
502Set the distribution behavior.
503
504=head2 get_distribution_method
505
506Get the distribution behavior.
507
508=head2 set_hashing_algorithm
509
510  $memd->set_hashing_algorithm( MEMCACHED_HASH_KETAMA );
511
512Set the hashing algorithm used.
513
514=head2 get_hashing_algorithm
515
516Get the hashing algorithm used.
517
518=head2 set_support_cas
519
520  $memd->set_support_cas($boolean);
521  # or
522  $memd = Cache::Memcached::libmemcached->new( {
523    ...
524    support_cas => 1
525  } );
526
527Enable/disable CAS support.
528
529=head1 VARIOUS MEMCACHED MODULES
530
531Below are the various memcached modules available on CPAN.
532
533Please check tool/benchmark.pl for a live comparison of these modules.
534(except for Cache::Memcached::XS, which I wasn't able to compile under my
535main dev environment)
536
537=head2 Cache::Memcached
538
539This is the "main" module. It's mostly written in Perl.
540
541=head2 Cache::Memcached::libmemcached
542
543Cache::Memcached::libmemcached, which is the module for which your reading
544the document of, is a perl binding for libmemcached (http://tangent.org/552/libmemcached.html). Not to be confused with libmemcache (see below).
545
546=head2 Cache::Memcached::XS
547
548Cache::Memcached::XS is a binding for libmemcache (http://people.freebsd.org/~seanc/libmemcache/).
549The main memcached site at http://danga.com/memcached/apis.bml seems to
550indicate that the underlying libmemcache is no longer in active development.
551
552=head2 Cache::Memcached::Fast
553
554Cache::Memcached::Fast is a memcached client written in XS from scratch.
555
556=head2 Memcached::libmemcached
557
558Memcached::libmemcached is a straight binding to libmemcached. It has all
559of the libmemcached API. If you don't care about a drop-in replacement for
560Cache::Memcached, and want to benefit from *all* of libmemcached offers,
561this is the way to go.
562
563=head1 CAVEATS
564
565Unless you know what you're getting yourself into, don't try to subclass this
566module just yet. Internal structures may change without notice.
567
568=head1 AUTHOR
569
570Copyright (c) 2008 Daisuke Maki E<lt>daisuke@endeworks.jpE<gt>
571
572=head1 LICENSE
573
574This program is free software; you can redistribute it and/or modify it
575under the same terms as Perl itself.
576
577See http://www.perl.com/perl/misc/Artistic.html
578
579=cut
Note: See TracBrowser for help on using the browser.