AtteanX-Store-LMDB
view release on metacpan or search on metacpan
lib/AtteanX/Store/LMDB.pm view on Meta::CPAN
=head1 SYNOPSIS
use AtteanX::Store::LMDB;
=head1 DESCRIPTION
AtteanX::Store::LMDB provides a persistent quad-store based on LMDB.
=cut
use v5.14;
use warnings;
package AtteanX::Store::LMDB {
our $VERSION = '0.003';
use Moo;
use Type::Tiny::Role;
use Types::Standard qw(Bool Str InstanceOf HashRef);
use LMDB_File qw(:flags :cursor_op);
use Digest::SHA qw(sha256 sha256_hex);
use Scalar::Util qw(refaddr reftype blessed);
use Math::Cartesian::Product;
use List::Util qw(any all first);
use File::Path qw(make_path);
use DateTime::Format::W3CDTF;
use Devel::Peek;
use Encode qw(encode_utf8 decode_utf8);
use namespace::clean;
with 'Attean::API::QuadStore';
with 'Attean::API::MutableQuadStore';
=head1 METHODS
Beyond the methods documented below, this class inherits methods from the
L<Attean::API::QuadStore> class.
=over 4
=item C<< new () >>
Returns a new LMDB-backed store object.
=cut
has initialize => (is => 'ro', isa => Bool, default => 0);
has filename => (is => 'ro', isa => Str, required => 1);
has env => (is => 'rw', isa => InstanceOf['LMDB::Env']);
has indexes => (is => 'rw', isa => HashRef, default => sub { +{} });
sub BUILDARGS {
my $class = shift;
my @params = @_;
my %args;
if (scalar(@params) == 1) {
%args = (filename => shift(@params));
} else {
%args = @params;
}
return $class->SUPER::BUILDARGS(%args);
}
sub BUILD {
my $self = shift;
my $file = $self->filename;
unless (-d $file) {
make_path($file);
}
my $env = LMDB::Env->new($file, {
mapsize => 100 * 1024 * 1024 * 1024, # Plenty space, don't worry
maxdbs => 20, # Some databases
mode => 0640,
});
$self->env($env);
if ($self->initialize) {
my $txn = $self->env->BeginTxn();
my %databases;
foreach my $name (qw(quads stats fullIndexes term_to_id id_to_term graphs prefixes)) {
$databases{$name} = $txn->OpenDB({ dbname => $name, flags => MDB_CREATE });
}
my $f = DateTime::Format::W3CDTF->new();
my $stats = $databases{'stats'};
$stats->put("Diomede-Version", '0.0.13');
$stats->put("Last-Modified", $f->format_datetime(DateTime->now()));
foreach my $key (qw(next_unassigned_term_id next_unassigned_quad_id)) {
$stats->put($key, pack('Q>', 1));
}
my $indexes = $databases{'fullIndexes'};
my %positions = ('s' => 0, 'p' => 1, 'o' => 2, 'g' => 3);
foreach my $key (qw(spog pogs gops)) {
my @pos = map { $positions{$_} } split(//, $key);
$txn->OpenDB({ dbname => $key, flags => MDB_CREATE });
$indexes->put($key, pack('Q>4', @pos));
}
$txn->commit();
}
my $txn = $self->env->BeginTxn(MDB_RDONLY);
my $indexes = $txn->OpenDB({ dbname => 'fullIndexes' });
$self->iterate_database($indexes, sub {
my ($key, $value) = @_;
my @order = unpack('Q>4', $value);
$self->indexes->{$key} = \@order;
});
}
sub iterate_database {
my $self = shift;
my $db = shift;
my $handler = shift;
my $cursor = $db->Cursor;
eval {
local($LMDB_File::die_on_err) = 0;
my ($key, $value);
unless ($cursor->get($key, $value, MDB_FIRST)) {
while (1) {
$handler->($key, $value);
( run in 2.882 seconds using v1.01-cache-2.11-cpan-98e64b0badf )