You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you create a parent transaction using LMDB::Txn->new(), then a child transaction using Env->BeginTxn(), no problem.
The reverse order utterly breaks: using the parent transaction causes MDB_BAD_TXN error.
Not certain if this is an issue with my understanding, or LMDB_File.
I've attached a test case, and below
Edit: Similar issues arise with read_only transactions, except it becomes impossible to have two simultaneous transactions. This seems strange to me: as LMDB transactions are isolated there should be no issue with N transactions per thread.
I think this is actually correct: I believe LMDB does not allow any read-only sub transactions.
NO_TLS should remove this restriction
Is there a way to issue several, non-sub transactions, without NO_TLS.
Is the problem that only one transaction per thread can have access to one dbi (like a file handle) at a time?
use 5.10.0;
use strict;
use warnings;
packageDBManager;
use LMDB_File qw/:all/;
my%envs;
subnew {
my$class = shift;
my$self = { };
bless$self, $class;
}
subdbPut {
my ($self,$dbName, $key, $data, $skipCommit) = @_;
# 0 to create database if not foundmy$db = $self->_getDbi($dbName);
if(!$db->{db}->Alive) {
$db->{db}->Txn = $db->{env}->BeginTxn();
# not strictly necessary, but I am concerned about hard to trace abort bugs related to scope$db->{db}->Txn->AutoCommit(1);
}
$db->{db}->Txn->put($db->{dbi}, $key, $data);
$db->{db}->Txn->commit() unless$skipCommit;
if($LMDB_File::last_err) {
if($LMDB_File::last_err != MDB_KEYEXIST) {
die$LMDB_File::last_err;
}
#reset the class error variable, to avoid crazy error reporting later$LMDB_File::last_err = 0;
}
return 0;
}
subdbReadOne {
my ($self, $dbName, $key, $skipCommit) = @_;
my$db = $self->_getDbi($dbName) orreturnundef;
if(!$db->{db}->Alive) {
$db->{db}->Txn = $db->{env}->BeginTxn();
# not strictly necessary, but I am concerned about hard to trace abort bugs related to scope$db->{db}->Txn->AutoCommit(1);
}
$db->{db}->Txn->get($db->{dbi}, $key, my$data);
# Commit unless the user specifically asks not to#if(!$skipCommit) {$db->{db}->Txn->commit() unless$skipCommit;
if($LMDB_File::last_err) {
if($LMDB_File::last_err != MDB_NOTFOUND ) {
die$LMDB_File::last_err;
}
$LMDB_File::last_err = 0;
}
return$data;
}
subdbStartCursorTxn {
my ($self, $dbName) = @_;
my$db = $self->_getDbi($dbName) orreturn;
my$txn = $db->{env}->BeginTxn();
# Help LMDB_File track our cursor
LMDB::Cursor::open($txn, $db->{dbi}, my$cursor);
# Unsafe, private LMDB_File method access but Cursor::open does not track cursors$LMDB::Txn::Txns{$$txn}{Cursors}{$$cursor} = 1;
return [$txn, $cursor];
}
sub_getDbi {
# Exists and not defined, because in read only database we may discover# that some chromosomes don't have any data (example: hg38 refSeq chrM)# $_[0] $_[1], $_[2]# Don't create used by dbGetNumberOfEntriesmy ($self, $dbPath) = @_;
if ($envs{$dbPath}) {
return$envs{$dbPath};
}
my$env = LMDB::Env->new($dbPath, {
mapsize=> 128 * 1024 * 1024 * 1024, # Plenty space, don't worry#maxdbs => 20, # Some databasesmode=> 0600,
maxdbs=> 0, # Some databases; else we get a MDB_DBS_FULL error (max db limit reached)
});
if(! $env ) {
die'No env';
}
my$txn = $env->BeginTxn();
my$dbFlags;
my$DB = $txn->OpenDB(undef, MDB_INTEGERKEY);
# ReadMode 1 gives memory pointer for perf reasons, not safe$DB->ReadMode(1);
if($LMDB_File::last_err) {
die$LMDB_File::last_err;
}
# Now db is openmy$err = $txn->commit();
if($err) {
die$err;
}
$envs{$dbPath} = {env=>$env, dbi=>$DB->dbi, db=>$DB};
return$envs{$dbPath};
}
1;
use Test::More;
use DDP;
my$db = DBManager->new();
my$dbIdx = 1;
my$pos = 99;
my$val = "HELLO WORLD";
system('rm -rf ./test && mkdir ./test');
#### WORKS GREAT ####my$cursor;
$cursor = $db->dbStartCursorTxn('test');
### Test Unsafe Transactions (Manually Managed) ##########$db->dbPut('test', $pos, [], 1);
$db->dbReadOne('test', $pos);
p %LMDB::Env::Envs;
$db->dbReadOne('test', $pos);
undef$db;
undef$cursor;
system('rm -rf ./test && mkdir ./test');
$db = DBManager->new();
#### DIES MISERABLE DEATH ####say"The reverse order doesn't work";
$db->dbPut('test', $pos, [], 1);
$cursor = $db->dbStartCursorTxn('test');
$db->dbReadOne('test', $pos);
say"We will never see this";
Issue:
If you create a parent transaction using LMDB::Txn->new(), then a child transaction using Env->BeginTxn(), no problem.
The reverse order utterly breaks: using the parent transaction causes MDB_BAD_TXN error.
Not certain if this is an issue with my understanding, or LMDB_File.
I've attached a test case, and below
Edit: Similar issues arise with read_only transactions, except it becomes impossible to have two simultaneous transactions. This seems strange to me: as LMDB transactions are isolated there should be no issue with N transactions per thread.
subtxn_bug.pl.zip
The text was updated successfully, but these errors were encountered: