1package Data::Localize::Storage::BerkeleyDB;
2use Moo;
3use BerkeleyDB;
4use Carp ();
5use Encode ();
6use File::Spec ();
7use File::Temp ();
8use Data::Localize ();
9BEGIN {
10    if (Data::Localize::DEBUG) {
11        require Data::Localize::Log;
12        Data::Localize::Log->import;
13    }
14}
15with 'Data::Localize::Storage';
16
17has '_db' => (
18    is => 'rw',
19    init_arg => 'db',
20);
21
22has 'store_as_refs' => (
23    is      => 'ro',
24    default => sub { 0 },
25);
26
27sub is_volatile { 0 }
28
29sub BUILD {
30    my ($self, $args) = @_;
31    if (! $self->_db) {
32        my $class = $args->{bdb_class} || 'Hash';
33        if ($class !~ s/^\+//) {
34            $class = "BerkeleyDB::$class";
35        }
36        Module::Load::load($class);
37
38        my $dir = ($args->{dir} ||= File::Temp::tempdir(CLEANUP => 1));
39        $args->{bdb_args} ||= {
40            -Filename => File::Spec->catfile($dir, $self->lang),
41            -Flags    => BerkeleyDB::DB_CREATE(),
42        };
43
44        if (Data::Localize::DEBUG) {
45            local $Log::Minimal::AUTODUMP = 1;
46            debugf("Storage::BerkeleyDB Automatically building storage db with class = %s, args = %s", $class, $args->{bdb_args});
47        }
48        $self->_db( $class->new( $args->{bdb_args} || {} ) ||
49            Carp::confess("Failed to create $class: $BerkeleyDB::Error")
50        );
51    }
52
53    if ( $self->store_as_refs ) {
54        require Storable;
55    }
56
57    $self;
58}
59
60sub get {
61    my ($self, $key, $flags) = @_;
62    my $value;
63    my $rc = $self->_db->db_get($key, $value, $flags || 0);
64    if ($rc == 0) {
65        if ( $self->store_as_refs ) {
66            # Storeable handles utf8 correctly
67            my $thawed = Storable::thaw( $value );
68            return $thawed->{'__' . __PACKAGE__ . '::key__'}
69                if exists $thawed->{'__' . __PACKAGE__ . '::key__'};
70            return $thawed;
71        }
72        else {
73            # BerkeleyDB gives us values with the flags off, so put them back on
74            return Encode::decode_utf8($value);
75        }
76    }
77    return ();
78}
79
80sub set {
81    my ($self, $key, $value, $flags) = @_;
82
83    if (Data::Localize::DEBUG) {
84        debugf("Storage::BerkeleyDB: Set %s -> %s", $key, $value);
85    }
86
87    if ( $self->store_as_refs ) {
88        unless ( ref $value ) {
89            $value = { ('__' . __PACKAGE__ . '::key__') => $value };
90        }
91        $value = Storable::freeze( $value );
92    }
93
94    my $rc = $self->_db->db_put($key, $value, $flags || 0);
95    if ($rc != 0) {
96        Carp::confess("Failed to set value $key");
97    }
98}
99
1001;
101
102__END__
103
104=head1 NAME
105
106Data::Localize::Storage::BerkeleyDB - BerkeleyDB Backend
107
108=head1 SYNOPSIS
109
110    use Data::Localize::Storage::BerkeleyDB;
111
112    Data::Localize::Storage::BerkeleDB->new(
113        bdb_class => 'Hash', # default
114        bdb_args  => {
115            -Filename => ....
116            -Flags    => BerkeleyDB::DB_CREATE
117        }
118    );
119
120=head1 METHODS
121
122=head2 get
123
124=head2 set
125
126=head2 is_volatile
127
128=cut
129