File Coverage

blib/lib/Cache/BerkeleyDB_Backend.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package Cache::BerkeleyDB_Backend;
2              
3             our $VERSION = '0.03';
4              
5 1     1   5 use strict;
  1         2  
  1         39  
6 1     1   6 use Storable qw(freeze thaw);
  1         1  
  1         47  
7 1     1   1718 use BerkeleyDB;
  0            
  0            
8             use Fcntl qw(:DEFAULT);
9              
10             my $Caches = {};
11              
12             sub new {
13             my ($class, $root, $namespace) = @_;
14             $namespace = _canonic_namespace($namespace);
15             $class = ref $class if ref $class;
16             my $obj = _initial_tie($root,$namespace);
17             my $self = { _filename => $obj->{filename},
18             _cache_root => $root,
19             _namespace => $namespace };
20             $self = bless($self, $class);
21             return $self;
22             }
23              
24             sub _initial_tie {
25             my ($root,$namespace) = @_;
26             $root ||= '/tmp';
27             $namespace ||= 'Default';
28             return $Caches->{$namespace} if $Caches->{$namespace};
29             my $env = new BerkeleyDB::Env(
30             -Home => $root,
31             -Flags => DB_INIT_CDB | DB_CREATE | DB_INIT_MPOOL,
32             )
33             or die "Can't create BerkeleyDB::Env (home=$root): $BerkeleyDB::Error";
34             my $fn = "$root/$namespace.bdbcache";
35             my $obj = BerkeleyDB::Btree->new(
36             -Filename => $fn,
37             -Flags => DB_CREATE,
38             -Mode => 0666,
39             -Env => $env, )
40             or die "Can't tie to $root/$namespace.bdbcache";
41             $Caches->{$namespace} = {};
42             $Caches->{$namespace}->{obj} = $obj;
43             $Caches->{$namespace}->{filename} = $fn;
44             $Caches->{$namespace}->{namespace} = $namespace;
45             return $Caches->{$namespace};
46             }
47              
48             sub _canonic_namespace {
49             my $namespace = shift;
50             $namespace =~ s/[^A-Za-z0-9\-_\+]/+/g;
51             $namespace = substr($namespace,0,56) if length($namespace)>56;
52             return $namespace;
53             }
54              
55             sub _retie {
56             my ($self, $namespace) = @_;
57             $namespace ||= 'Default';
58             return if $namespace eq $self->{_namespace};
59             my $obj = _initial_tie($self->{_cache_root},$namespace);
60             $self->{_filename} = $obj->{filename};
61             $self->{_namespace} = $namespace;
62             }
63              
64             sub get_root {
65             my $self = shift;
66             return $self->{_cache_root};
67             }
68              
69             sub set_root {
70             my ($self,$root) = @_;
71             $root ||= '/tmp';
72             return $root if $self->{_cache_root} eq $root;
73             $self->{_cache_root} = $root;
74             $Caches = {};
75             my $obj = _initial_tie($root,$self->{_namespace});
76             $self->{_filename} = $obj->{filename};
77             return $root;
78             }
79              
80             sub delete_key {
81             my ($self, $namespace, $key) = @_;
82             $self->_retie($namespace);
83             $self->_get_obj->db_del($key);
84             }
85              
86             sub delete_namespace {
87             my $self = shift;
88             my $count = 0;
89             $self->_get_obj->truncate($count);
90             return $count;
91             }
92              
93             sub get_keys {
94             my ($self, $namespace) = @_;
95             $self->_retie($namespace);
96             my $db = $Caches->{ $self->{_namespace} }->{obj};
97             my ($k,$v) = ('','');
98             my @keys = ();
99             my $cursor = $db->db_cursor();
100             while ($cursor->c_get($k, $v, DB_NEXT) == 0) {
101             push @keys, $k;
102             }
103             undef $cursor;
104             return @keys;
105             }
106              
107             sub get_namespaces {
108             my $self = shift;
109             opendir DIR, $self->{_cache_root} or return;
110             my @ns = ();
111             while (my $fn = readdir DIR) {
112             push @ns, $fn if $fn =~ s/\.bdbcache$//;
113             }
114             closedir DIR;
115             return @ns;
116             }
117              
118             sub get_size {
119             my ($self, $namespace, $key) = @_;
120             $self->_retie($namespace);
121             my $val;
122             $self->_get_obj->db_get( $key, $val);
123             return defined $val ? length($val) : undef;
124             }
125              
126             sub _get {
127             my ($self,$key) = @_;
128             my $val;
129             my $rc = $self->_get_obj->db_get( $key, $val);
130             my $ret = eval { thaw($val) };
131             return $ret;
132             }
133              
134             sub _get_obj {
135             my $self = shift;
136             return $Caches->{ $self->{_namespace} }->{obj};
137             }
138              
139             sub _set {
140             my ($self,$key,$val) = @_;
141             $self->_get_obj->db_put($key, freeze($val));
142             }
143              
144             sub restore {
145             my ($self,$namespace,$key) = @_;
146             $self->_retie($namespace);
147             return $self->_get($key);
148             }
149              
150             sub store {
151             my ($self,$namespace,$key,$val) = @_;
152             $self->_retie($namespace);
153             $self->_set($key,$val);
154             }
155              
156              
157             1;
158              
159             __END__