Cache-Memcached-libmemcached

 view release on metacpan or  search on metacpan

lib/Cache/Memcached/libmemcached.pm  view on Meta::CPAN

        my $code = "sub $set { \$_[0]->memcached_behavior_set($behavior(), \$_[1]) }\n"
                 . "sub $get { \$_[0]->memcached_behavior_get($behavior()) }";
        eval $code;
        die "$@ while executing $code" if $@;
    }

}

sub import
{
    my $class = shift;
    Memcached::libmemcached->export_to_level(1, undef, @_) ;
}

sub new
{
    my $class = shift;
    my %args  = %{ shift || {} };

    my $self = $class->SUPER::new();

    $self->trace_level(delete $args{debug}) if exists $args{debug};

    $self->namespace(delete $args{namespace})
        if exists $args{namespace};

    $self->{compress_threshold} = delete $args{compress_threshold};
    # Add support for Cache::Memcache::Fast's compress_ratio
    $self->{compress_savingsS}  = delete $args{compress_savings} || 0.20;
    $self->{compress_enable}    =
        exists $args{compress_enable} ? delete $args{compress_enable} : 1;

    # servers 
    $args{servers} || croak "No servers specified";
    $self->set_servers(delete $args{servers});

    # old-style behavior options (see behavior_ block below)
    foreach my $option (qw(no_block hashing_algorithm distribution_method binary_protocol)) {
        my $behavior = $behavior{$option}->[1] || $option;
        $args{"behavior_$behavior"} = delete $args{$option} if exists $args{$option};
    }

    # allow any libmemcached behavior to be set via args to new()
    for my $name (grep { /^behavior_/ } keys %args) {
        my $value = delete $args{$name};
        my $behavior = "Memcached::libmemcached::MEMCACHED_\U$name";
        no strict 'refs';
        if (not defined &$behavior) {
            carp "$name ($behavior) isn't available"; # sanity check
            next;
        }
        $self->memcached_behavior_set(&$behavior(), $value);
    }

    delete $args{readonly};
    delete $args{no_rehash};

    carp "Unrecognised options: @{[ sort keys %args ]}"
        if %args;

    # Set compression/serialization callbacks
    $self->set_callback_coderefs(
        # Closures so we have reference to $self
        $self->_mk_callbacks()
    );

    # behavior options
    foreach my $option (qw(no_block hashing_algorithm distribution_method binary_protocol)) {
        my $method = "set_$option";
        $self->$method( $args{$option} ) if exists $args{$option};
    }

    return $self;
}

sub namespace {
    my $self = shift;

    my $old_namespace = $self->memcached_callback_get(MEMCACHED_CALLBACK_PREFIX_KEY);
    if (@_) {
        my $namespace = shift;
        $self->memcached_callback_set(MEMCACHED_CALLBACK_PREFIX_KEY, $namespace)
            or carp $self->errstr;
    }

    return $old_namespace;
}

sub set_servers
{
    my $self = shift;
    my $servers = shift || [];

    # $self->{servers} = []; # for compatibility with Cache::Memcached

    # XXX should delete any existing servers from libmemcached
    foreach my $server (@$servers) {
        $self->server_add($server);
    }
}

sub server_add
{
    my $self = shift;
    my $server = shift
        or Carp::confess("server not specified");

    my $weight = 0;
    if (ref $server eq 'ARRAY') {
        my @ary = @$server;
        $server = shift @ary;
        $weight = shift @ary || 0 if @ary;
    }
    elsif (ref $server eq 'HASH') { # Cache::Memcached::Fast
        my $h = $server;
        $server = $h->{address};
        $weight = $h->{weight} if exists $h->{weight};
        # noreply is not supported
    }

    if ($server =~ /^([^:]+):([^:]+)$/) {
        my ($hostname, $port) = ($1, $2);
        $self->memcached_server_add_with_weight($hostname, $port, $weight);
    } else {
        $self->memcached_server_add_unix_socket_with_weight( $server, $weight );
    }

    # for compatibility with Cache::Memcached
    # push @{$self->{servers}}, $server;
}


sub _mk_callbacks
{
    my $self = shift;

    weaken($self);
    my $inflate = sub {
        my ($key, $flags) = @_;
        if ($flags & F_COMPRESS) {
            if (! HAVE_ZLIB) {
                croak("Data for $key is compressed, but we have no Compress::Zlib");
            }
            $_ = Compress::Zlib::memGunzip($_);
        }

        if ($flags & F_STORABLE) {
            $_ = Storable::thaw($_);
        }
        return ();
    };

    my $deflate = sub {
        # Check if we have a complex structure
        if (ref $_) {
            $_ = Storable::nfreeze($_);
            $_[1] |= F_STORABLE;
        }

        # Check if we need compression
        if (HAVE_ZLIB && $self->{compress_enable} && $self->{compress_threshold}) {
            # Find the byte length
            my $length = bytes::length($_);
            if ($length > $self->{compress_threshold}) {
                my $tmp = Compress::Zlib::memGzip($_);
                if (bytes::length($tmp) / $length < 1 - $self->{compress_savingsS}) {
                    $_ = $tmp;
                    $_[1] |= F_COMPRESS;
                }
            }
        }
        return ();
    };
    return ($deflate, $inflate);
}

sub incr
{
    my $self = shift;
    my $key  = shift;
    my $offset = shift || 1;
    my $val = 0;
    $self->memcached_increment($key, $offset, $val) || return undef;
    return $val;
}

sub decr
{
    my $self = shift;
    my $key  = shift;
    my $offset = shift || 1;
    my $val = 0;
    $self->memcached_decrement($key, $offset, $val) || return undef;



( run in 0.378 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )