salortiz / LMDB_File

Perl wrapper around the OpenLDAP's LMDB
Other
8 stars 12 forks source link

Potential bug "Transaction Terminated", or documentation issue, for use of $txn reset/renew #20

Open akotlar opened 8 years ago

akotlar commented 8 years ago

My use case below. "Transaction Terminated" returned when $txn->renew() called. I don't think this is the expected behavior, because transaction termination should only occur if there are no remaining references to the transaction, according to LMDB_File.pm, but there clearly are, below.

There may be a better way of doing what I aim: Reuse a read-only transaction, in a read-only environment, across multiple dbRead function calls.

Thanks!

sub dbRead {
 my $db = $_[0]-> _getDbi($_[1]);

  my $txn;

  if(defined $db->{rdOnlyTxn} ) {
    $txn = $db->{rdOnlyTxn};

   ## Results in "Transaction Terminated"
    $txn->renew();
  }
}

sub _getDbi {
 my $env = LMDB::Env->new($dbPath, {
    ...
 });

 if(! $env ) {
   # handle
 }

 my $txn = $env->BeginTxn();

 my $DB = $txn->OpenDB();

 my $err = $txn->commit();
 # Check error

 $envs->{$name} = {env => $env, dbi => $DB->dbi};

 if($dbReadOnly) {
     $envs->{$name}{rdOnlyTxn} = $env->BeginTxn(MDB_RDONLY);
 }

 return  $envs->{$name};
}

Same thing occurs in a version where the new transaction is given to $DB->Txn instead, and the entire $DB reference is stored in $envs.

$envs->{$name} = {env => $env, dbi => $DB->dbi, DB => $DB};

 if($dbReadOnly) {
     $DB->Txn = $env->BeginTxn(MDB_RDONLY);
 }
hoytech commented 8 years ago

Sorry I've never really used the reset/renew stuff -- hopefully @salortiz can look at this when he has some time available.

As for alternatives, you could just create a new transaction for every dbRead call. I suspect the extra locking/allocation would be lost in the noise of the perl interpreter's slowness -- do you have some reason to believe otherwise, such as high-levels of contention on the reader table lock?