| Brackup documentation | Contained in the Brackup distribution. |
Brackup::Dict::SQLite - key-value dictionary implementation, using a SQLite database for storage
Brackup::Dict::SQLite implements a simple key-value dictionary using a SQLite database (in a single file) for storage. It provides the default storage backend for both the Brackup::DigestCache digest cache and the Brackup::InventoryDatabase inventory database (as separate databases). The database schema is created automatically as needed - no database maintenance is required.
Brackup::Dict::SQLite is optimised for speed and loads the entire database into memory at startup. If you wish to trade-off some performance for a more conservative memory footprint, you should consider using Brackup::Dict::SQLite2 instead.
See Brackup::DigestCache and Brackup::InventoryDatabase for how to manually specify the dictionary class to use.
The database file location is a parameter defined by the using class, so see Brackup::DigestCache and Brackup::InventoryDatabase for their respective database locations.
This is defined automatically, but if you want to look around in it, the schema is:
CREATE TABLE <TABLE> (
key TEXT PRIMARY KEY,
value TEXT
)
| Brackup documentation | Contained in the Brackup distribution. |
package Brackup::Dict::SQLite; use strict; use warnings; use DBI; use DBD::SQLite; sub new { my ($class, %opts) = @_; my $self = bless { table => $opts{table}, file => $opts{file}, data => {}, }, $class; my $dbh = $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$opts{file}","","", { RaiseError => 1, PrintError => 0 }) or die "Failed to connect to SQLite filesystem digest cache database at $opts{file}: " . DBI->errstr; eval { $dbh->do("CREATE TABLE $opts{table} (key TEXT PRIMARY KEY, value TEXT)"); }; die "Error: $@" if $@ && $@ !~ /table \w+ already exists/; return $self; } sub _reset { my $self = shift; $self->{data} = {}; $self->{keys} = []; $self->{_loaded_keys} = 0; } sub _load_all { my $self = shift; unless ($self->{_loaded_all}++) { # SQLite sucks at doing anything quickly (likes hundred thousand # selects back-to-back), so we just suck the whole damn thing into # a perl hash. cute, huh? then it doesn't have to # open/read/seek/seek/seek/read/close for each select later. $self->_reset; my $sth = $self->{dbh}->prepare("SELECT key, value FROM $self->{table}"); $sth->execute; while (my ($k, $v) = $sth->fetchrow_array) { $self->{data}{$k} = $v; } } } sub get { my ($self, $key) = @_; $self->_load_all unless $self->{_loaded_all}; return $self->{data}{$key}; } sub set { my ($self, $key, $val) = @_; $self->{dbh}->do("REPLACE INTO $self->{table} VALUES (?,?)", undef, $key, $val); $self->{data}{$key} = $val; return 1; } # Iterator interface, returning ($key, $value), and () on eod sub each { my $self = shift; $self->_load_all unless $self->{_loaded_all}; $self->{keys} = [ keys %{$self->{data}} ] unless $self->{_loaded_keys}++; if (! @{$self->{keys}}) { $self->{_loaded_keys} = 0; return wantarray ? () : undef; } my $next = shift @{$self->{keys}}; return wantarray ? ($next, $self->{data}{$next}) : $next; } sub delete { my ($self, $key) = @_; $self->{dbh}->do("DELETE FROM $self->{table} WHERE key = ?", undef, $key); delete $self->{data}{$key}; return 1; } sub count { my $self = shift; $self->_load_all unless $self->{_loaded_all}; return scalar keys %{$self->{data}}; } sub backing_file { my $self = shift; return $self->{file}; } sub wipe { die "not implemented"; } 1; __END__