db-4.1.17 orphans.
authorjbj <devnull@localhost>
Wed, 14 Aug 2002 16:42:12 +0000 (16:42 +0000)
committerjbj <devnull@localhost>
Wed, 14 Aug 2002 16:42:12 +0000 (16:42 +0000)
CVS patchset: 5631
CVS date: 2002/08/14 16:42:12

77 files changed:
db/perl/BerkeleyDB/BerkeleyDB.pm
db/perl/BerkeleyDB/BerkeleyDB.pod
db/perl/BerkeleyDB/BerkeleyDB.pod.P
db/perl/BerkeleyDB/BerkeleyDB.xs
db/perl/BerkeleyDB/Changes
db/perl/BerkeleyDB/MANIFEST
db/perl/BerkeleyDB/Makefile.PL
db/perl/BerkeleyDB/README
db/perl/BerkeleyDB/config.in
db/perl/BerkeleyDB/constants.h
db/perl/BerkeleyDB/dbinfo
db/perl/BerkeleyDB/mkconsts
db/perl/DB_File/Changes
db/perl/DB_File/DB_File.pm
db/perl/DB_File/DB_File.xs
db/perl/DB_File/Makefile.PL
db/perl/DB_File/README
db/perl/DB_File/config.in
db/perl/DB_File/dbinfo
db/perl/DB_File/t/db-btree.t
db/perl/DB_File/t/db-hash.t
db/perl/DB_File/t/db-recno.t
db/perl/DB_File/version.c
db/rep/rep_method.c
db/rep/rep_record.c
db/rep/rep_region.c
db/rep/rep_util.c
db/tcl/docs/rep.html
db/test/bigfile002.tcl
db/test/dead006.tcl
db/test/dead007.tcl
db/test/env009.tcl
db/test/env010.tcl
db/test/lock004.tcl
db/test/lock005.tcl
db/test/parallel.tcl
db/test/recd016.tcl
db/test/recd15scr.tcl
db/test/rep001.tcl
db/test/reputils.tcl
db/test/rpc003.tcl
db/test/rsrc004.tcl
db/test/scr001/chk.code
db/test/scr002/chk.def
db/test/scr003/chk.define
db/test/scr004/chk.javafiles
db/test/scr005/chk.nl
db/test/scr007/chk.proto
db/test/scr008/chk.pubdef
db/test/scr009/chk.srcfiles
db/test/scr010/spell.ok
db/test/scr012/chk.vx_code
db/test/scr013/chk.stats
db/test/scr014/chk.err
db/test/scr015/TestConstruct01.cpp
db/test/scr015/TestExceptInclude.cpp
db/test/scr015/TestGetSetMethods.cpp
db/test/scr015/TestKeyRange.cpp
db/test/scr015/TestLogc.cpp
db/test/scr015/TestSimpleAccess.cpp
db/test/scr015/TestTruncate.cpp
db/test/scr015/chk.cxxtests
db/test/scr016/CallbackTest.java
db/test/scr016/TestClosedDb.java
db/test/scr016/TestConstruct01.java
db/test/scr016/TestConstruct02.java
db/test/scr016/TestReplication.java
db/test/scr016/TestSameDbt.java
db/test/scr016/TestSimpleAccess.java
db/test/scr016/TestTruncate.java
db/test/scr016/chk.javatests
db/test/shelltest.tcl
db/test/si005.tcl
db/test/test095.tcl
db/test/test096.tcl
db/test/txnscript.tcl
db/txn/txn_method.c

index e1ae757..9f145af 100644 (file)
@@ -2,7 +2,7 @@
 package BerkeleyDB;
 
 
-#     Copyright (c) 1997-2001 Paul Marquess. All rights reserved.
+#     Copyright (c) 1997-2002 Paul Marquess. All rights reserved.
 #     This program is free software; you can redistribute it and/or
 #     modify it under the same terms as Perl itself.
 #
@@ -14,14 +14,25 @@ BEGIN { require 5.004_04 }
 
 use strict;
 use Carp;
-use vars qw($VERSION @ISA @EXPORT $AUTOLOAD);
+use vars qw($VERSION @ISA @EXPORT $AUTOLOAD
+               $use_XSLoader);
 
-$VERSION = '0.17';
+$VERSION = '0.19';
 
 require Exporter;
-require DynaLoader;
+#require DynaLoader;
 require AutoLoader;
-use IO ;
+
+BEGIN {
+    $use_XSLoader = 1 ;
+    { local $SIG{__DIE__} ; eval { require XSLoader } ; }
+    if ($@) {
+        $use_XSLoader = 0 ;
+        require DynaLoader;
+        @ISA = qw(DynaLoader);
+    }
+}
 
 @ISA = qw(Exporter DynaLoader);
 # Items to export into callers namespace by default. Note: do not export
@@ -39,6 +50,7 @@ use IO ;
        DB_ARCH_ABS
        DB_ARCH_DATA
        DB_ARCH_LOG
+       DB_AUTO_COMMIT
        DB_BEFORE
        DB_BROADCAST_EID
        DB_BTREE
@@ -48,6 +60,7 @@ use IO ;
        DB_CACHED_COUNTS
        DB_CDB_ALLDB
        DB_CHECKPOINT
+       DB_CHKSUM_SHA1
        DB_CLIENT
        DB_CL_WRITER
        DB_COMMIT
@@ -59,16 +72,26 @@ use IO ;
        DB_CXX_NO_EXCEPTIONS
        DB_DELETED
        DB_DELIMITER
+       DB_DIRECT
+       DB_DIRECT_DB
+       DB_DIRECT_LOG
        DB_DIRTY_READ
        DB_DONOTINDEX
        DB_DUP
        DB_DUPCURSOR
        DB_DUPSORT
+       DB_EID_BROADCAST
+       DB_EID_INVALID
+       DB_ENCRYPT
+       DB_ENCRYPT_AES
        DB_ENV_APPINIT
        DB_ENV_CDB
        DB_ENV_CDB_ALLDB
        DB_ENV_CREATE
        DB_ENV_DBLOCAL
+       DB_ENV_DIRECT_DB
+       DB_ENV_DIRECT_LOG
+       DB_ENV_FATAL
        DB_ENV_LOCKDOWN
        DB_ENV_LOCKING
        DB_ENV_LOGGING
@@ -76,6 +99,7 @@ use IO ;
        DB_ENV_NOMMAP
        DB_ENV_NOPANIC
        DB_ENV_OPEN_CALLED
+       DB_ENV_OVERWRITE
        DB_ENV_PANIC_OK
        DB_ENV_PRIVATE
        DB_ENV_REGION_INIT
@@ -89,6 +113,7 @@ use IO ;
        DB_ENV_THREAD
        DB_ENV_TXN
        DB_ENV_TXN_NOSYNC
+       DB_ENV_TXN_WRITE_NOSYNC
        DB_ENV_USER_ALLOC
        DB_ENV_YIELDCPU
        DB_EXCL
@@ -105,6 +130,7 @@ use IO ;
        DB_GET_BOTHC
        DB_GET_BOTH_RANGE
        DB_GET_RECNO
+       DB_HANDLE_LOCK
        DB_HASH
        DB_HASHMAGIC
        DB_HASHOLDVER
@@ -141,6 +167,7 @@ use IO ;
        DB_LOCK_MINLOCKS
        DB_LOCK_MINWRITE
        DB_LOCK_NORUN
+       DB_LOCK_NOTEXIST
        DB_LOCK_NOTGRANTED
        DB_LOCK_NOTHELD
        DB_LOCK_NOWAIT
@@ -151,11 +178,13 @@ use IO ;
        DB_LOCK_PUT_READ
        DB_LOCK_RANDOM
        DB_LOCK_RECORD
+       DB_LOCK_REMOVE
        DB_LOCK_RIW_N
        DB_LOCK_RW_N
        DB_LOCK_SET_TIMEOUT
        DB_LOCK_SWITCH
        DB_LOCK_TIMEOUT
+       DB_LOCK_TRADE
        DB_LOCK_UPGRADE
        DB_LOCK_UPGRADE_WRITE
        DB_LOCK_YOUNGEST
@@ -186,6 +215,7 @@ use IO ;
        DB_NEXT
        DB_NEXT_DUP
        DB_NEXT_NODUP
+       DB_NOCOPY
        DB_NODUPDATA
        DB_NOLOCKING
        DB_NOMMAP
@@ -207,15 +237,23 @@ use IO ;
        DB_OPEN_CALLED
        DB_OPFLAGS_MASK
        DB_ORDERCHKONLY
+       DB_OVERWRITE
        DB_PAD
        DB_PAGEYIELD
        DB_PAGE_LOCK
        DB_PAGE_NOTFOUND
        DB_PANIC_ENVIRONMENT
+       DB_PERMANENT
        DB_POSITION
        DB_POSITIONI
        DB_PREV
        DB_PREV_NODUP
+       DB_PRINTABLE
+       DB_PRIORITY_DEFAULT
+       DB_PRIORITY_HIGH
+       DB_PRIORITY_LOW
+       DB_PRIORITY_VERY_HIGH
+       DB_PRIORITY_VERY_LOW
        DB_PRIVATE
        DB_PR_HEADERS
        DB_PR_PAGE
@@ -237,6 +275,7 @@ use IO ;
        DB_REGION_MAGIC
        DB_REGION_NAME
        DB_REGISTERED
+       DB_RENAMEMAGIC
        DB_RENUMBER
        DB_REP_CLIENT
        DB_REP_DUPMASTER
@@ -283,6 +322,7 @@ use IO ;
        DB_TEST_PREEXTUNLINK
        DB_TEST_PREOPEN
        DB_TEST_PRERENAME
+       DB_TEST_SUBDB_LOCKS
        DB_THREAD
        DB_TIMEOUT
        DB_TRUNCATE
@@ -293,6 +333,8 @@ use IO ;
        DB_TXN_BACKWARD_ROLL
        DB_TXN_CKP
        DB_TXN_FORWARD_ROLL
+       DB_TXN_GETPGNOS
+       DB_TXN_LOCK
        DB_TXN_LOCK_2PL
        DB_TXN_LOCK_MASK
        DB_TXN_LOCK_OPTIMIST
@@ -305,9 +347,11 @@ use IO ;
        DB_TXN_NOWAIT
        DB_TXN_OPENFILES
        DB_TXN_POPENFILES
+       DB_TXN_PRINT
        DB_TXN_REDO
        DB_TXN_SYNC
        DB_TXN_UNDO
+       DB_TXN_WRITE_NOSYNC
        DB_UNKNOWN
        DB_UNRESOLVED_CHILD
        DB_UPDATE_SECONDARY
@@ -317,6 +361,7 @@ use IO ;
        DB_VERB_CHKPOINT
        DB_VERB_DEADLOCK
        DB_VERB_RECOVERY
+       DB_VERB_REPLICATION
        DB_VERB_WAITSFOR
        DB_VERIFY
        DB_VERIFY_BAD
@@ -328,6 +373,8 @@ use IO ;
        DB_VRFY_FLAGMASK
        DB_WRITECURSOR
        DB_WRITELOCK
+       DB_WRITEOPEN
+       DB_WRNOSYNC
        DB_XA_CREATE
        DB_XIDDATASIZE
        DB_YIELDCPU
@@ -343,7 +390,11 @@ sub AUTOLOAD {
     goto &{$AUTOLOAD};
 }         
 
-bootstrap BerkeleyDB $VERSION;
+#bootstrap BerkeleyDB $VERSION;
+if ($use_XSLoader)
+  { XSLoader::load("BerkeleyDB", $VERSION)}
+else
+  { bootstrap BerkeleyDB $VERSION }  
 
 # Preloaded methods go here.
 
@@ -407,15 +458,6 @@ sub env_remove
                                        Config          => undef,
                                        }, @_) ;
 
-    if (defined $got->{ErrFile}) {
-       if (!isaFilehandle($got->{ErrFile})) {
-           my $handle = new IO::File ">$got->{ErrFile}"
-               or croak "Cannot open file $got->{ErrFile}: $!\n" ;
-           $got->{ErrFile} = $handle ;
-       }
-    }
-
-    
     if (defined $got->{Config}) {
        croak("Config parameter must be a hash reference")
             if ! ref $got->{Config} eq 'HASH' ;
@@ -452,6 +494,52 @@ sub db_remove
     return _db_remove($got);
 }
 
+sub db_rename
+{
+    my $got = BerkeleyDB::ParseParameters(
+                     {
+                       Filename        => undef,
+                       Subname         => undef,
+                       Newname         => undef,
+                       Flags           => 0,
+                       Env             => undef,
+                     }, @_) ;
+
+    croak("Env not of type BerkeleyDB::Env")
+       if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env');
+
+    croak("Must specify a filename")
+       if ! defined $got->{Filename} ;
+
+    croak("Must specify a Subname")
+       if ! defined $got->{Subname} ;
+
+    croak("Must specify a Newname")
+       if ! defined $got->{Newname} ;
+
+    return _db_rename($got);
+}
+
+sub db_verify
+{
+    my $got = BerkeleyDB::ParseParameters(
+                     {
+                       Filename        => undef,
+                       Subname         => undef,
+                       Outfile         => undef,
+                       Flags           => 0,
+                       Env             => undef,
+                     }, @_) ;
+
+    croak("Env not of type BerkeleyDB::Env")
+       if defined $got->{Env} and ! isa($got->{Env},'BerkeleyDB::Env');
+
+    croak("Must specify a filename")
+       if ! defined $got->{Filename} ;
+
+    return _db_verify($got);
+}
+
 package BerkeleyDB::Env ;
 
 use UNIVERSAL qw( isa ) ;
@@ -477,9 +565,10 @@ sub new
     #                  [ -Home         => $path, ]
     #                  [ -Mode         => mode, ]
     #                  [ -Config       => { name => value, name => value }
-    #                  [ -ErrFile      => filename or filehandle, ]
+    #                  [ -ErrFile      => filename, ]
     #                  [ -ErrPrefix    => "string", ]
     #                  [ -Flags        => DB_INIT_LOCK| ]
+    #                  [ -Set_Flags    => $flags,]
     #                  [ -Cachesize    => number ]
     #                  [ -LockDetect   =>  ]
     #                  [ -Verbose      => boolean ]
@@ -493,6 +582,7 @@ sub new
                                        ErrFile         => undef,
                                        ErrPrefix       => undef,
                                        Flags           => 0,
+                                       SetFlags        => 0,
                                        Cachesize       => 0,
                                        LockDetect      => 0,
                                        Verbose         => 0,
@@ -500,11 +590,13 @@ sub new
                                        }, @_) ;
 
     if (defined $got->{ErrFile}) {
-       if (!isaFilehandle($got->{ErrFile})) {
-           my $handle = new IO::File ">$got->{ErrFile}"
-               or croak "Cannot open file $got->{ErrFile}: $!\n" ;
-           $got->{ErrFile} = $handle ;
-       }
+       croak("ErrFile parameter must be a file name")
+            if ref $got->{ErrFile} ;
+       #if (!isaFilehandle($got->{ErrFile})) {
+       #    my $handle = new IO::File ">$got->{ErrFile}"
+#              or croak "Cannot open file $got->{ErrFile}: $!\n" ;
+#          $got->{ErrFile} = $handle ;
+#      }
     }
 
     
@@ -627,7 +719,8 @@ sub new
     if ($addr) {
         $obj = bless [$addr] , $self ;
        push @{ $obj }, $got->{Env} if $got->{Env} ;
-        $obj->Txn($got->{Txn}) if $got->{Txn} ;
+        $obj->Txn($got->{Txn}) 
+            if $got->{Txn} ;
     }
     return $obj ;
 }
@@ -682,7 +775,8 @@ sub new
     if ($addr) {
         $obj = bless [$addr] , $self ;
        push @{ $obj }, $got->{Env} if $got->{Env} ;
-        $obj->Txn($got->{Txn}) if $got->{Txn} ;
+        $obj->Txn($got->{Txn}) 
+            if $got->{Txn} ;
     }
     return $obj ;
 }
@@ -744,7 +838,8 @@ sub new
     if ($addr) {
         $obj = bless [$addr] , $self ;
        push @{ $obj }, $got->{Env} if $got->{Env} ;
-        $obj->Txn($got->{Txn}) if $got->{Txn} ;
+        $obj->Txn($got->{Txn}) 
+            if $got->{Txn} ;
     }  
     return $obj ;
 }
@@ -804,7 +899,8 @@ sub new
     if ($addr) {
         $obj = bless [$addr] , $self ;
        push @{ $obj }, $got->{Env} if $got->{Env} ;
-        $obj->Txn($got->{Txn}) if $got->{Txn} ;
+        $obj->Txn($got->{Txn})
+            if $got->{Txn} ;
     }  
     return $obj ;
 }
@@ -910,7 +1006,8 @@ sub new
     if ($addr) {
         $obj = bless [$addr], "BerkeleyDB::$type" ;
        push @{ $obj }, $got->{Env} if $got->{Env} ;
-        $obj->Txn($got->{Txn}) if $got->{Txn} ;
+        $obj->Txn($got->{Txn})
+            if $got->{Txn} ;
     }  
     return $obj ;
 }
index a6c18c8..60f30e2 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
+BerkeleyDB - Perl extension for Berkeley DB version 2, 3 or 4
 
 =head1 SYNOPSIS
 
@@ -23,6 +23,8 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $db  = new BerkeleyDB::Unknown [OPTIONS] ;
 
   $status = BerkeleyDB::db_remove [OPTIONS]
+  $status = BerkeleyDB::db_rename [OPTIONS]
+  $status = BerkeleyDB::db_verify [OPTIONS]
 
   $hash{$key} = $value ;
   $value = $hash{$key} ;
@@ -35,11 +37,14 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $db->db_del() ;
   $status = $db->db_sync() ;
   $status = $db->db_close() ;
+  $status = $db->db_close() ;
+  $status = $db->db_pget()
   $hash_ref = $db->db_stat() ;
   $status = $db->db_key_range();
   $type = $db->type() ;
   $status = $db->status() ;
   $boolean = $db->byteswapped() ;
+  $status = $db->truncate($count) ;
 
   ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ;
   ($flag, $old_offset, $old_length) = $db->partial_clear() ;
@@ -50,6 +55,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $cursor->c_put() ;
   $status = $cursor->c_del() ;
   $status = $cursor->c_count() ;
+  $status = $cursor->c_pget() ;
   $status = $cursor->status() ;
   $status = $cursor->c_close() ;
 
@@ -60,6 +66,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $env->txn_checkpoint()
   $hash_ref = $env->txn_stat()
   $status = $env->setmutexlocks()
+  $status = $env->set_flags()
 
   $txn = $env->txn_begin() ;
   $db->Txn($txn);
@@ -76,6 +83,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
 
   $status = $env->set_data_dir() ;
   $status = $env->set_tmp_dir() ;
+  $status = $env->set_verbose() ;
 
   $BerkeleyDB::Error
   $BerkeleyDB::db_version
@@ -98,11 +106,12 @@ B<NOTE: This document is still under construction. Expect it to be
 incomplete in places.>
 
 This Perl module provides an interface to most of the functionality
-available in Berkeley DB versions 2 and 3. In general it is safe to assume
+available in Berkeley DB versions 2, 3 and 4. In general it is safe to assume
 that the interface provided here to be identical to the Berkeley DB
 interface. The main changes have been to make the Berkeley DB API work
 in a Perl way. Note that if you are using Berkeley DB 2.x, the new
-features available in Berkeley DB 3.x are not available via this module.
+features available in Berkeley DB 3.x or DB 4.x are not available via
+this module.
 
 The reader is expected to be familiar with the Berkeley DB
 documentation. Where the interface provided here is identical to the
@@ -118,7 +127,7 @@ classes.
 
 The B<BerkeleyDB::Env> class provides an interface to the Berkeley DB
 function B<db_appinit> in Berkeley DB 2.x or B<db_env_create> and
-B<DBENV-E<gt>open> in Berkeley DB 3.x. Its purpose is to initialise a
+B<DBENV-E<gt>open> in Berkeley DB 3.x/4.x. Its purpose is to initialise a
 number of sub-systems that can then be used in a consistent way in all
 the databases you make use of the environment.
 
@@ -132,9 +141,10 @@ shouldn't need to make use of B<BerkeleyDB::Env>.
              [ -Server       => $name, ]
              [ -CacheSize    => $number, ]
              [ -Config       => { name => value, name => value }, ]
-             [ -ErrFile      => filename or filehandle, ]
+             [ -ErrFile      => filename, ]
              [ -ErrPrefix    => "string", ]
              [ -Flags        => number, ]
+             [ -SetFlags     => bitmask, ]
              [ -LockDetect   => number, ]
              [ -Verbose      => boolean, ]
 
@@ -197,8 +207,8 @@ The code below shows an example of how it can be used.
 
 =item -ErrFile
 
-Expects either the name of a file or a reference to a filehandle. Any
-errors generated internally by Berkeley DB will be logged to this file.
+Expects a filenme. Any errors generated internally by Berkeley DB will
+be logged to this file.
 
 =item -ErrPrefix
 
@@ -263,6 +273,13 @@ B<DB_USE_ENVIRON>
 
 B<DB_USE_ENVIRON_ROOT>
 
+=item -SetFlags
+
+Calls ENV->set_flags with the supplied bitmask. Use this when you need to make
+use of DB_ENV->set_flags before DB_ENV->open is called.
+
+Only valid when Berkeley DB 3.x or better is used.
+
 =item -LockDetect
 
 Specifies what to do when a lock conflict occurs. The value should be one of
@@ -292,6 +309,8 @@ The environment class has the following methods:
 This method is identical to the B<-ErrPrefix> flag. It allows the
 error prefix string to be changed dynamically.
 
+=item $env->set_flags(bitmask, 1|0);
+
 =item $txn = $env->TxnMgr()
 
 Constructor for creating a B<TxnMgr> object.
@@ -328,6 +347,12 @@ Berkeley DB 3.0 or 3.2 and better it calls B<DBENV-E<gt>set_mutexlocks>.
 
 TODO.
 
+=head1 Global Classes
+
+  $status = BerkeleyDB::db_remove [OPTIONS]
+  $status = BerkeleyDB::db_rename [OPTIONS]
+  $status = BerkeleyDB::db_verify [OPTIONS]
+  
 =head1 THE DATABASE CLASSES
 
 B<BerkeleyDB> supports the following database formats:
@@ -381,7 +406,7 @@ the next sections.
 
 Equivalent to calling B<db_open> with type B<DB_HASH> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_HASH> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -690,7 +715,7 @@ TODO
 
 Equivalent to calling B<db_open> with type B<DB_BTREE> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_BTREE> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -938,7 +963,7 @@ TODO
 
 Equivalent to calling B<db_open> with type B<DB_RECNO> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_RECNO> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -1031,8 +1056,8 @@ Here is the output from the script:
 =head1 BerkeleyDB::Queue
 
 Equivalent to calling B<db_create> followed by B<DB-E<gt>open> with
-type B<DB_QUEUE> in Berkeley DB 3.x. This database format isn't available if
-you use Berkeley DB 2.x.
+type B<DB_QUEUE> in Berkeley DB 3.x or greater. This database format
+isn't available if you use Berkeley DB 2.x.
 
 Two forms of constructor are supported:
 
@@ -1076,7 +1101,7 @@ This class is used to open an existing database.
 
 Equivalent to calling B<db_open> with type B<DB_UNKNOWN> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_UNKNOWN> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 The constructor looks like this:
 
@@ -1110,7 +1135,7 @@ be created and removed once the program terminates.
 =item -Subname
 
 Specifies the name of the sub-database to open.
-This option is only valid if you are using Berkeley DB 3.x.
+This option is only valid if you are using Berkeley DB 3.x or greater.
 
 =item -Flags
 
@@ -1286,13 +1311,19 @@ equivalent field would be accessed as follows:
 
     $version = $ref->{'bt_version'} ;
 
-If you are using Berkeley DB 3.x, this method will work will all database
-formats. When DB 2.x is used, it only works with B<BerkeleyDB::Btree>.
+If you are using Berkeley DB 3.x or better, this method will work will
+all database formats. When DB 2.x is used, it only works with
+B<BerkeleyDB::Btree>.
 
 =head2 $status = $db->status()
 
 Returns the status of the last C<$db> method called.
 
+=head2 $status = $db->truncate($count)
+
+Truncates the datatabase and returns the number or records deleted
+in C<$count>.
+
 =head1 CURSORS
 
 A cursor is used whenever you want to access the contents of a database
@@ -1700,10 +1731,10 @@ I get asked.
 
 Before Berkeley DB 2.x was written there was only one Perl module that
 interfaced to Berkeley DB. That module is called B<DB_File>. Although
-B<DB_File> can be build with Berkeley DB 1.x, 2.x or 3.x, it only provides
+B<DB_File> can be build with Berkeley DB 1.x, 2.x, 3.x or 4.x, it only provides
 an interface to the functionality available in Berkeley DB 1.x. That
 means that it doesn't support transactions, locking or any of the other
-new features available in DB 2.x or 3.x.
+new features available in DB 2.x or better.
 
 =head2 How do I store Perl data structures with BerkeleyDB?
 
@@ -1723,7 +1754,7 @@ The official web site for Berkeley DB is F<http://www.sleepycat.com>.
 
 =head1 COPYRIGHT
 
-Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This program
+Copyright (c) 1997-2002 Paul Marquess. All rights reserved. This program
 is free software; you can redistribute it and/or modify it under the
 same terms as Perl itself.
 
index 644cdb9..4a848f5 100644 (file)
@@ -1,6 +1,6 @@
 =head1 NAME
 
-BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
+BerkeleyDB - Perl extension for Berkeley DB version 2, 3 or 4
 
 =head1 SYNOPSIS
 
@@ -23,6 +23,8 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $db  = new BerkeleyDB::Unknown [OPTIONS] ;
 
   $status = BerkeleyDB::db_remove [OPTIONS]
+  $status = BerkeleyDB::db_rename [OPTIONS]
+  $status = BerkeleyDB::db_verify [OPTIONS]
 
   $hash{$key} = $value ;
   $value = $hash{$key} ;
@@ -35,11 +37,14 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $db->db_del() ;
   $status = $db->db_sync() ;
   $status = $db->db_close() ;
+  $status = $db->db_close() ;
+  $status = $db->db_pget()
   $hash_ref = $db->db_stat() ;
   $status = $db->db_key_range();
   $type = $db->type() ;
   $status = $db->status() ;
   $boolean = $db->byteswapped() ;
+  $status = $db->truncate($count) ;
 
   ($flag, $old_offset, $old_length) = $db->partial_set($offset, $length) ;
   ($flag, $old_offset, $old_length) = $db->partial_clear() ;
@@ -50,6 +55,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $cursor->c_put() ;
   $status = $cursor->c_del() ;
   $status = $cursor->c_count() ;
+  $status = $cursor->c_pget() ;
   $status = $cursor->status() ;
   $status = $cursor->c_close() ;
 
@@ -60,6 +66,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
   $status = $env->txn_checkpoint()
   $hash_ref = $env->txn_stat()
   $status = $env->setmutexlocks()
+  $status = $env->set_flags()
 
   $txn = $env->txn_begin() ;
   $db->Txn($txn);
@@ -76,6 +83,7 @@ BerkeleyDB - Perl extension for Berkeley DB version 2 or 3
 
   $status = $env->set_data_dir() ;
   $status = $env->set_tmp_dir() ;
+  $status = $env->set_verbose() ;
 
   $BerkeleyDB::Error
   $BerkeleyDB::db_version
@@ -98,11 +106,12 @@ B<NOTE: This document is still under construction. Expect it to be
 incomplete in places.>
 
 This Perl module provides an interface to most of the functionality
-available in Berkeley DB versions 2 and 3. In general it is safe to assume
+available in Berkeley DB versions 2, 3 and 4. In general it is safe to assume
 that the interface provided here to be identical to the Berkeley DB
 interface. The main changes have been to make the Berkeley DB API work
 in a Perl way. Note that if you are using Berkeley DB 2.x, the new
-features available in Berkeley DB 3.x are not available via this module.
+features available in Berkeley DB 3.x or DB 4.x are not available via
+this module.
 
 The reader is expected to be familiar with the Berkeley DB
 documentation. Where the interface provided here is identical to the
@@ -118,7 +127,7 @@ classes.
 
 The B<BerkeleyDB::Env> class provides an interface to the Berkeley DB
 function B<db_appinit> in Berkeley DB 2.x or B<db_env_create> and
-B<DBENV-E<gt>open> in Berkeley DB 3.x. Its purpose is to initialise a
+B<DBENV-E<gt>open> in Berkeley DB 3.x/4.x. Its purpose is to initialise a
 number of sub-systems that can then be used in a consistent way in all
 the databases you make use of the environment.
 
@@ -132,9 +141,10 @@ shouldn't need to make use of B<BerkeleyDB::Env>.
              [ -Server       => $name, ]
              [ -CacheSize    => $number, ]
              [ -Config       => { name => value, name => value }, ]
-             [ -ErrFile      => filename or filehandle, ]
+             [ -ErrFile      => filename, ]
              [ -ErrPrefix    => "string", ]
              [ -Flags        => number, ]
+             [ -SetFlags     => bitmask, ]
              [ -LockDetect   => number, ]
              [ -Verbose      => boolean, ]
 
@@ -197,8 +207,8 @@ The code below shows an example of how it can be used.
 
 =item -ErrFile
 
-Expects either the name of a file or a reference to a filehandle. Any
-errors generated internally by Berkeley DB will be logged to this file.
+Expects a filenme. Any errors generated internally by Berkeley DB will
+be logged to this file.
 
 =item -ErrPrefix
 
@@ -263,6 +273,13 @@ B<DB_USE_ENVIRON>
 
 B<DB_USE_ENVIRON_ROOT>
 
+=item -SetFlags
+
+Calls ENV->set_flags with the supplied bitmask. Use this when you need to make
+use of DB_ENV->set_flags before DB_ENV->open is called.
+
+Only valid when Berkeley DB 3.x or better is used.
+
 =item -LockDetect
 
 Specifies what to do when a lock conflict occurs. The value should be one of
@@ -292,6 +309,8 @@ The environment class has the following methods:
 This method is identical to the B<-ErrPrefix> flag. It allows the
 error prefix string to be changed dynamically.
 
+=item $env->set_flags(bitmask, 1|0);
+
 =item $txn = $env->TxnMgr()
 
 Constructor for creating a B<TxnMgr> object.
@@ -328,6 +347,12 @@ Berkeley DB 3.0 or 3.2 and better it calls B<DBENV-E<gt>set_mutexlocks>.
 
 TODO.
 
+=head1 Global Classes
+
+  $status = BerkeleyDB::db_remove [OPTIONS]
+  $status = BerkeleyDB::db_rename [OPTIONS]
+  $status = BerkeleyDB::db_verify [OPTIONS]
+  
 =head1 THE DATABASE CLASSES
 
 B<BerkeleyDB> supports the following database formats:
@@ -381,7 +406,7 @@ the next sections.
 
 Equivalent to calling B<db_open> with type B<DB_HASH> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_HASH> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -582,7 +607,7 @@ TODO
 
 Equivalent to calling B<db_open> with type B<DB_BTREE> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_BTREE> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -777,7 +802,7 @@ TODO
 
 Equivalent to calling B<db_open> with type B<DB_RECNO> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_RECNO> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 Two forms of constructor are supported:
 
@@ -837,8 +862,8 @@ Here is the output from the script:
 =head1 BerkeleyDB::Queue
 
 Equivalent to calling B<db_create> followed by B<DB-E<gt>open> with
-type B<DB_QUEUE> in Berkeley DB 3.x. This database format isn't available if
-you use Berkeley DB 2.x.
+type B<DB_QUEUE> in Berkeley DB 3.x or greater. This database format
+isn't available if you use Berkeley DB 2.x.
 
 Two forms of constructor are supported:
 
@@ -882,7 +907,7 @@ This class is used to open an existing database.
 
 Equivalent to calling B<db_open> with type B<DB_UNKNOWN> in Berkeley DB 2.x and
 calling B<db_create> followed by B<DB-E<gt>open> with type B<DB_UNKNOWN> in
-Berkeley DB 3.x. 
+Berkeley DB 3.x or greater
 
 The constructor looks like this:
 
@@ -916,7 +941,7 @@ be created and removed once the program terminates.
 =item -Subname
 
 Specifies the name of the sub-database to open.
-This option is only valid if you are using Berkeley DB 3.x.
+This option is only valid if you are using Berkeley DB 3.x or greater.
 
 =item -Flags
 
@@ -1092,13 +1117,19 @@ equivalent field would be accessed as follows:
 
     $version = $ref->{'bt_version'} ;
 
-If you are using Berkeley DB 3.x, this method will work will all database
-formats. When DB 2.x is used, it only works with B<BerkeleyDB::Btree>.
+If you are using Berkeley DB 3.x or better, this method will work will
+all database formats. When DB 2.x is used, it only works with
+B<BerkeleyDB::Btree>.
 
 =head2 $status = $db->status()
 
 Returns the status of the last C<$db> method called.
 
+=head2 $status = $db->truncate($count)
+
+Truncates the datatabase and returns the number or records deleted
+in C<$count>.
+
 =head1 CURSORS
 
 A cursor is used whenever you want to access the contents of a database
@@ -1467,10 +1498,10 @@ I get asked.
 
 Before Berkeley DB 2.x was written there was only one Perl module that
 interfaced to Berkeley DB. That module is called B<DB_File>. Although
-B<DB_File> can be build with Berkeley DB 1.x, 2.x or 3.x, it only provides
+B<DB_File> can be build with Berkeley DB 1.x, 2.x, 3.x or 4.x, it only provides
 an interface to the functionality available in Berkeley DB 1.x. That
 means that it doesn't support transactions, locking or any of the other
-new features available in DB 2.x or 3.x.
+new features available in DB 2.x or better.
 
 =head2 How do I store Perl data structures with BerkeleyDB?
 
@@ -1490,7 +1521,7 @@ The official web site for Berkeley DB is F<http://www.sleepycat.com>.
 
 =head1 COPYRIGHT
 
-Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This program
+Copyright (c) 1997-2002 Paul Marquess. All rights reserved. This program
 is free software; you can redistribute it and/or modify it under the
 same terms as Perl itself.
 
index 5a26166..47ca616 100644 (file)
@@ -6,7 +6,7 @@
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1997-2001 Paul Marquess. All rights reserved.
+     Copyright (c) 1997-2002 Paul Marquess. All rights reserved.
      This program is free software; you can redistribute it and/or
      modify it under the same terms as Perl itself.
 
 #ifdef __cplusplus
 extern "C" {
 #endif
+
 #define PERL_POLLUTE
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#include "ppport.h"
+
+
+/* XSUB.h defines a macro called abort                                 */
+/* This clashes with the txn abort method in Berkeley DB 4.x   */
+/* This is a problem with ActivePerl (at least)                        */
+
+#ifdef _WIN32
+#  ifdef abort
+#    undef abort
+#  endif
+#  ifdef fopen
+#    undef fopen
+#  endif
+#  ifdef fclose
+#    undef fclose
+#  endif
+#endif
 
 /* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
  * shortly #included by the <db.h>) __attribute__ to the possibly
@@ -34,28 +53,29 @@ extern "C" {
 
 #undef __attribute__
 
-#ifndef PERL_VERSION
-#    include "patchlevel.h"
-#    define PERL_REVISION      5
-#    define PERL_VERSION       PATCHLEVEL
-#    define PERL_SUBVERSION    SUBVERSION
+#ifdef USE_PERLIO
+#    define GetFILEptr(sv) PerlIO_findFILE(IoOFP(sv_2io(sv)))
+#else
+#    define GetFILEptr(sv) IoOFP(sv_2io(sv))
 #endif
 
-#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
+#include <db.h>
 
-#    define PL_sv_undef                sv_undef
-#    define PL_na              na
-#    define PL_dirty           dirty
+/* Check the version of Berkeley DB */
 
+#ifndef DB_VERSION_MAJOR
+#ifdef HASHMAGIC
+#error db.h is from Berkeley DB 1.x - need at least Berkeley DB 2.6.4
+#else
+#error db.h is not for Berkeley DB at all.
+#endif
 #endif
 
-#ifdef USE_PERLIO
-#    define GetFILEptr(sv) PerlIO_findFILE(IoOFP(sv_2io(sv)))
-#else
-#    define GetFILEptr(sv) IoOFP(sv_2io(sv))
+#if (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6) ||\
+    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 6 && DB_VERSION_PATCH < 4)
+#  error db.h is from Berkeley DB 2.0-2.5 - need at least Berkeley DB 2.6.4
 #endif
 
-#include <db.h>
 
 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0)
 #  define IS_DB_3_0_x
@@ -87,38 +107,10 @@ extern "C" {
 #  define AT_LEAST_DB_4
 #endif
 
-/* need to define DEFSV & SAVE_DEFSV for older version of Perl */
-#ifndef DEFSV
-#    define DEFSV GvSV(defgv)
-#endif
-
-#ifndef SAVE_DEFSV
-#    define SAVE_DEFSV SAVESPTR(GvSV(defgv))
-#endif
-
-#ifndef pTHX
-#    define pTHX
-#    define pTHX_
-#    define aTHX
-#    define aTHX_
-#endif
-
-#ifndef dTHR
-#    define dTHR
-#endif
-
-#ifndef newSVpvn
-#    define newSVpvn(a,b)       newSVpv(a,b)
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+#  define AT_LEAST_DB_4_1
 #endif
 
-#ifndef PTR2IV
-#    define PTR2IV(d)  (IV)(d) 
-#endif /* PTR2IV */
-
-#ifndef INT2PTR
-#    define INT2PTR(any,d)     (any)(d) 
-#endif /* INT2PTR */
-
 #ifdef __cplusplus
 }
 #endif
@@ -183,7 +175,7 @@ typedef struct {
        int             Status ;
        /* char         ErrBuff[1000] ; */
        SV *            ErrPrefix ;
-       SV *            ErrHandle ;
+       FILE *          ErrHandle ;
        DB_ENV *        Env ;
        int             open_dbs ;
        int             TxnMgrStatus ;
@@ -199,9 +191,17 @@ typedef struct {
        BerkeleyDB_ENV_type * parent_env ;
         DB *           dbp ;
         SV *           compare ;
+        bool           in_compare ;
         SV *           dup_compare ;
+        bool           in_dup_compare ;
         SV *           prefix ;
+        bool           in_prefix ;
         SV *                   hash ;
+        bool           in_hash ;
+#ifdef AT_LEAST_DB_3_3
+        SV *                   associated ;
+       bool            secondary_db ;
+#endif
        int             Status ;
         DB_INFO *      info ;
         DBC *          cursor ;
@@ -233,6 +233,10 @@ typedef struct {
         SV *           dup_compare ;
         SV *           prefix ;
         SV *                   hash ;
+#ifdef AT_LEAST_DB_3_3
+        SV *                   associated ;
+       bool            secondary_db ;
+#endif
        int             Status ;
         DB_INFO *      info ;
         DBC *          cursor ;
@@ -333,6 +337,16 @@ hash_delete(char * hash, char * key);
 #  define flagSet(bitmask)     ((flags & DB_OPFLAGS_MASK) == (bitmask))
 #endif
 
+#if DB_VERSION_MAJOR == 2 
+#  define BackRef      internal
+#else
+#  if DB_VERSION_MAJOR == 3 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0)
+#    define BackRef    cj_internal
+#  else
+#    define BackRef    api_internal
+#  endif
+#endif
+
 #ifdef DBM_FILTERING
 #define ckFilter(arg,type,name)                                 \
         if (db->type) {                                         \
@@ -472,6 +486,7 @@ hash_delete(char * hash, char * key);
 static db_recno_t Value ;
 static db_recno_t zero = 0 ;
 static BerkeleyDB      CurrentDB ;
+
 static DBTKEY  empty ;
 #if 0
 static char    ErrBuff[1000] ;
@@ -685,6 +700,10 @@ destroyDB(BerkeleyDB db)
                  SvREFCNT_dec(db->compare) ;
     if (db->dup_compare)
                  SvREFCNT_dec(db->dup_compare) ;
+#ifdef AT_LEAST_DB_3_3
+    if (db->associated && !db->secondary_db)
+                 SvREFCNT_dec(db->associated) ;
+#endif
     if (db->prefix)
                  SvREFCNT_dec(db->prefix) ;
 #ifdef DBM_FILTERING
@@ -847,6 +866,7 @@ btree_compare(DB_callback const DBT * key1, const DBT * key2 )
     char * data1, * data2 ;
     int retval ;
     int count ;
+    BerkeleyDB keepDB = CurrentDB ;
 
     data1 = (char*) key1->data ;
     data2 = (char*) key2->data ;
@@ -883,6 +903,7 @@ btree_compare(DB_callback const DBT * key1, const DBT * key2 )
     PUTBACK ;
     FREETMPS ;
     LEAVE ;
+    CurrentDB = keepDB ;
     return (retval) ;
 
 }
@@ -894,6 +915,7 @@ dup_compare(DB_callback const DBT * key1, const DBT * key2 )
     char * data1, * data2 ;
     int retval ;
     int count ;
+    BerkeleyDB keepDB = CurrentDB ;
 
     Trace(("In dup_compare \n")) ;
     if (!CurrentDB)
@@ -936,6 +958,7 @@ dup_compare(DB_callback const DBT * key1, const DBT * key2 )
     PUTBACK ;
     FREETMPS ;
     LEAVE ;
+    CurrentDB = keepDB ;
     return (retval) ;
 
 }
@@ -947,6 +970,7 @@ btree_prefix(DB_callback const DBT * key1, const DBT * key2 )
     char * data1, * data2 ;
     int retval ;
     int count ;
+    BerkeleyDB keepDB = CurrentDB ;
 
     data1 = (char*) key1->data ;
     data2 = (char*) key2->data ;
@@ -983,6 +1007,7 @@ btree_prefix(DB_callback const DBT * key1, const DBT * key2 )
     PUTBACK ;
     FREETMPS ;
     LEAVE ;
+    CurrentDB = keepDB ;
 
     return (retval) ;
 }
@@ -993,6 +1018,7 @@ hash_cb(DB_callback const void * data, u_int32_t size)
     dSP ;
     int retval ;
     int count ;
+    BerkeleyDB keepDB = CurrentDB ;
 
 #ifndef newSVpvn
     if (size == 0)
@@ -1019,10 +1045,84 @@ hash_cb(DB_callback const void * data, u_int32_t size)
     PUTBACK ;
     FREETMPS ;
     LEAVE ;
+    CurrentDB = keepDB ;
 
     return (retval) ;
 }
 
+#ifdef AT_LEAST_DB_3_3
+
+static int
+associate_cb(DB_callback const DBT * pkey, const DBT * pdata, DBT * skey)
+{
+    dSP ;
+    char * pk_dat, * pd_dat, *sk_dat ;
+    int retval ;
+    int count ;
+    SV * skey_SV ;
+
+    Trace(("In associate_cb \n")) ;
+    if (((BerkeleyDB)db->BackRef)->associated == NULL){
+        Trace(("No Callback registered\n")) ;
+        return EINVAL ;
+    }
+
+    skey_SV = newSVpv("",0);
+
+
+    pk_dat = (char*) pkey->data ;
+    pd_dat = (char*) pdata->data ;
+
+#ifndef newSVpvn
+    /* As newSVpv will assume that the data pointer is a null terminated C
+       string if the size parameter is 0, make sure that data points to an
+       empty string if the length is 0
+    */
+    if (pkey->size == 0)
+        pk_dat = "" ;
+    if (pdata->size == 0)
+        pd_dat = "" ;
+#endif
+
+    ENTER ;
+    SAVETMPS;
+
+    PUSHMARK(SP) ;
+    EXTEND(SP,2) ;
+    PUSHs(sv_2mortal(newSVpvn(pk_dat,pkey->size)));
+    PUSHs(sv_2mortal(newSVpvn(pd_dat,pdata->size)));
+    PUSHs(sv_2mortal(skey_SV));
+    PUTBACK ;
+
+    Trace(("calling associated cb\n"));
+    count = perl_call_sv(((BerkeleyDB)db->BackRef)->associated, G_SCALAR);
+    Trace(("called associated cb\n"));
+
+    SPAGAIN ;
+
+    if (count != 1)
+        softCrash ("associate: expected 1 return value from prefix sub, got %d", count) ;
+
+    retval = POPi ;
+
+    PUTBACK ;
+    
+    /* retrieve the secondary key */
+    DBT_clear(*skey);
+    skey->flags = DB_DBT_APPMALLOC;
+    skey->size = SvCUR(skey_SV);
+    skey->data = (char*)safemalloc(skey->size);
+    memcpy(skey->data, SvPVX(skey_SV), skey->size);
+    Trace(("key is %d -- %.*s\n", skey->size, skey->size, skey->data));
+
+    FREETMPS ;
+    LEAVE ;
+
+    return (retval) ;
+}
+
+#endif /* AT_LEAST_DB_3_3 */
+
 static void
 db_errcall_cb(const char * db_errpfx, char * buffer)
 {
@@ -1089,6 +1189,7 @@ my_db_open(
                SV *            ref,
                SV *            ref_dbenv ,
                BerkeleyDB__Env dbenv ,
+               BerkeleyDB__Txn txn, 
                const char *    file,
                const char *    subname,
                DBTYPE          type,
@@ -1101,14 +1202,21 @@ my_db_open(
     BerkeleyDB         RETVAL = NULL ;
     DB *       dbp ;
     int                Status ;
+    DB_TXN*    txnid = NULL ;
 
-    Trace(("_db_open(dbenv[%lu] ref_dbenv [%lu] file[%s] subname [%s] type[%d] flags[%d] mode[%d]\n",
+    Trace(("_db_open(dbenv[%p] ref_dbenv [%p] file[%s] subname [%s] type[%d] flags[%d] mode[%d]\n",
                dbenv, ref_dbenv, file, subname, type, flags, mode)) ;
 
     CurrentDB = db ;
     if (dbenv)
        env = dbenv->Env ;
 
+    if (txn)
+        txnid = txn->txn;
+
+    Trace(("_db_open(dbenv[%p] ref_dbenv [%p] txn [%p] file[%s] subname [%s] type[%d] flags[%d] mode[%d]\n",
+               dbenv, ref_dbenv, txn, file, subname, type, flags, mode)) ;
+
 #if DB_VERSION_MAJOR == 2
     if (subname)
         softCrash("Subname needs Berkeley DB 3 or better") ;
@@ -1120,6 +1228,13 @@ my_db_open(
     if (Status)
         return RETVAL ;
 
+#ifdef AT_LEAST_DB_3_3
+    if (! env) {
+       dbp->set_alloc(dbp, safemalloc, MyRealloc, safefree) ;
+       dbp->set_errcall(dbp, db_errcall_cb) ;
+    }
+#endif
+
     if (info->re_source) {
         Status = dbp->set_re_source(dbp, info->re_source) ;
        Trace(("set_re_source [%s] returned %s\n",
@@ -1178,7 +1293,7 @@ my_db_open(
 
     if (info->bt_compare) {
         Status = dbp->set_bt_compare(dbp, info->bt_compare) ;
-       Trace(("set_bt_compare [%d] returned %s\n",
+       Trace(("set_bt_compare [%p] returned %s\n",
                info->bt_compare, my_db_strerror(Status)));
         if (Status)
             return RETVAL ;
@@ -1252,17 +1367,22 @@ my_db_open(
 #endif
     }
 
+#ifdef AT_LEAST_DB_4_1
+    if ((Status = (dbp->open)(dbp, txnid, file, subname, type, flags, mode)) == 0) {
+#else
     if ((Status = (dbp->open)(dbp, file, subname, type, flags, mode)) == 0) {
+#endif /* AT_LEAST_DB_4_1 */
 #else /* DB_VERSION_MAJOR == 2 */
     if ((Status = db_open(file, type, flags, mode, env, info, &dbp)) == 0) {
 #endif /* DB_VERSION_MAJOR == 2 */
 
        Trace(("db_opened ok\n"));
-       RETVAL = db ;
 #ifdef AT_LEAST_DB_3_3
-       dbp->set_alloc(dbp, safemalloc, MyRealloc, safefree) ;
+       dbp->BackRef = db;
 #endif
+       RETVAL = db ;
        RETVAL->dbp  = dbp ;
+       RETVAL->txn  = txnid ;
 #if DB_VERSION_MAJOR == 2
        RETVAL->type = dbp->type ;
 #else /* DB_VERSION_MAJOR > 2 */
@@ -1278,7 +1398,7 @@ my_db_open(
        RETVAL->Status = Status ;
        RETVAL->active = TRUE ;
        hash_store_iv("BerkeleyDB::Term::Db", (char *)RETVAL, 1) ;
-       Trace(("  storing %d %d in BerkeleyDB::Term::Db\n", RETVAL, dbp)) ;
+       Trace(("  storing %p %p in BerkeleyDB::Term::Db\n", RETVAL, dbp)) ;
        if (dbenv) {
            RETVAL->parent_env = dbenv ;
            dbenv->Status = Status ;
@@ -1355,6 +1475,87 @@ _db_remove(ref)
        OUTPUT:
            RETVAL
 
+DualType
+_db_verify(ref)
+       SV *            ref
+       CODE:
+       {
+#ifndef AT_LEAST_DB_3_1
+           softCrash("BerkeleyDB::db_verify needs Berkeley DB 3.1.x or better") ;
+#else
+           HV *                hash ;
+           DB *                dbp ;
+           SV *                sv ;
+           const char *        db = NULL ;
+           const char *        subdb   = NULL ;
+           const char *        outfile = NULL ;
+           FILE *              ofh = NULL;
+           BerkeleyDB__Env     env     = NULL ;
+           DB_ENV *            dbenv   = NULL ;
+           u_int32_t           flags   = 0 ;
+
+           hash = (HV*) SvRV(ref) ;
+           SetValue_pv(db,    "Filename", char *) ;
+           SetValue_pv(subdb, "Subname", char *) ;
+           SetValue_pv(outfile, "Outfile", char *) ;
+           SetValue_iv(flags, "Flags") ;
+           SetValue_ov(env, "Env", BerkeleyDB__Env) ;
+            RETVAL = 0;
+            if (outfile){
+               ofh = fopen(outfile, "w");
+                if (! ofh)
+                    RETVAL = errno;
+            }
+            if (! RETVAL) {
+               if (env)
+                   dbenv = env->Env ;
+                RETVAL = db_create(&dbp, dbenv, 0) ;
+               if (RETVAL == 0) {
+                   RETVAL = dbp->verify(dbp, db, subdb, ofh, flags) ;
+               }
+               if (outfile) 
+                    fclose(ofh);
+            }
+#endif
+       }
+       OUTPUT:
+           RETVAL
+
+DualType
+_db_rename(ref)
+       SV *            ref
+       CODE:
+       {
+#ifndef AT_LEAST_DB_3_1
+           softCrash("BerkeleyDB::db_rename needs Berkeley DB 3.1.x or better") ;
+#else
+           HV *                hash ;
+           DB *                dbp ;
+           SV *                sv ;
+           const char *        db = NULL ;
+           const char *        subdb   = NULL ;
+           const char *        newname = NULL ;
+           BerkeleyDB__Env     env     = NULL ;
+           DB_ENV *            dbenv   = NULL ;
+           u_int32_t           flags   = 0 ;
+
+           hash = (HV*) SvRV(ref) ;
+           SetValue_pv(db,    "Filename", char *) ;
+           SetValue_pv(subdb, "Subname", char *) ;
+           SetValue_pv(newname, "Newname", char *) ;
+           SetValue_iv(flags, "Flags") ;
+           SetValue_ov(env, "Env", BerkeleyDB__Env) ;
+           if (env)
+               dbenv = env->Env ;
+            RETVAL = db_create(&dbp, dbenv, 0) ;
+           if (RETVAL == 0) {
+               RETVAL = dbp->rename(dbp, db, subdb, newname, flags) ;
+           }
+#endif
+       }
+       OUTPUT:
+           RETVAL
+
 MODULE = BerkeleyDB::Env               PACKAGE = BerkeleyDB::Env PREFIX = env_
 
 
@@ -1367,9 +1568,11 @@ _db_appinit(self, ref)
            HV *        hash ;
            SV *        sv ;
            char *      home = NULL ;
+           char *      errfile = NULL ;
            char *      server = NULL ;
            char **     config = NULL ;
            int         flags = 0 ;
+           int         setflags = 0 ;
            int         cachesize = 0 ;
            int         lk_detect = 0 ;
            SV *        errprefix = NULL;
@@ -1382,9 +1585,14 @@ _db_appinit(self, ref)
            SetValue_pv(config,    "Config", char **) ;
            SetValue_sv(errprefix, "ErrPrefix") ;
            SetValue_iv(flags,     "Flags") ;
+           SetValue_iv(setflags,  "SetFlags") ;
            SetValue_pv(server,    "Server", char *) ;
            SetValue_iv(cachesize, "Cachesize") ;
            SetValue_iv(lk_detect, "LockDetect") ;
+#ifndef AT_LEAST_DB_3_2
+           if (setflags)
+               softCrash("-SetFlags needs Berkeley DB 3.x or better") ;
+#endif /* ! AT_LEAST_DB_3 */
 #ifndef AT_LEAST_DB_3_1
            if (server)
                softCrash("-Server needs Berkeley DB 3.1 or better") ;
@@ -1419,13 +1627,13 @@ _db_appinit(self, ref)
            if (RETVAL->ErrPrefix)
                RETVAL->Env->db_errpfx = SvPVX(RETVAL->ErrPrefix) ;
 
-           if ((sv = readHash(hash, "ErrFile")) && sv != &PL_sv_undef) {
-               env->db_errfile = GetFILEptr(sv);
-               RETVAL->ErrHandle = newRV(sv) ;
+           SetValue_pv(errfile,      "ErrFile", char *) ;
+           if (errfile) {
+               RETVAL->ErrHandle = env->db_errfile = fopen(errfile, "w");
+               if (RETVAL->ErrHandle == NULL)
+                   croak("Cannot open file %s: %s\n", errfile,  Strerror(errno));
            }
-           /* SetValue_io(RETVAL->Env.db_errfile, "ErrFile") ; */
            SetValue_iv(env->db_verbose, "Verbose") ;
-           /* env->db_errbuf = RETVAL->ErrBuff ; */
            env->db_errcall = db_errcall_cb ;
            RETVAL->active = TRUE ;
            status = db_appinit(home, config, env, flags) ;
@@ -1434,7 +1642,7 @@ _db_appinit(self, ref)
                hash_store_iv("BerkeleyDB::Term::Env", (char *)RETVAL, 1) ;
            else {
                 if (RETVAL->ErrHandle)
-                    SvREFCNT_dec(RETVAL->ErrHandle) ;
+                    fclose(RETVAL->ErrHandle) ;
                 if (RETVAL->ErrPrefix)
                     SvREFCNT_dec(RETVAL->ErrPrefix) ;
                 Safefree(RETVAL->Env) ;
@@ -1458,7 +1666,7 @@ _db_appinit(self, ref)
              Trace(("set_cachesize [%d] returned %s\n",
                        cachesize, my_db_strerror(status)));
          }
-
+       
          if (status == 0 && lk_detect) {
              status = env->set_lk_detect(env, lk_detect) ;
              Trace(("set_lk_detect [%d] returned %s\n",
@@ -1483,6 +1691,14 @@ _db_appinit(self, ref)
          }
 #  endif
 #endif
+#ifdef AT_LEAST_DB_3_2
+         if (setflags && status == 0)
+         {
+             status = env->set_flags(env, setflags, 1);
+             Trace(("ENV->set_flags value = %d returned %s\n", setflags,
+                                               my_db_strerror(status))) ;
+         }
+#endif
          if (status == 0)
          {
            int         mode = 0 ;
@@ -1495,13 +1711,15 @@ _db_appinit(self, ref)
            if (RETVAL->ErrPrefix)
                env->set_errpfx(env, SvPVX(RETVAL->ErrPrefix)) ;
 
-           if ((sv = readHash(hash, "ErrFile")) && sv != &PL_sv_undef) {
-               env->set_errfile(env, GetFILEptr(sv)) ;
-               RETVAL->ErrHandle = newRV(sv) ;
+           SetValue_pv(errfile,      "ErrFile", char *) ;
+           if (errfile) {
+               RETVAL->ErrHandle = fopen(errfile, "w");
+               if (RETVAL->ErrHandle == NULL)
+                   croak("Cannot open file %s: %s\n", errfile,  Strerror(errno));
+               env->set_errfile(env, RETVAL->ErrHandle) ;
            }
-           /* SetValue_iv(RETVAL->Env.db_verbose, "Verbose") ; */ /* TODO */
+
            SetValue_iv(mode, "Mode") ;
-           /* RETVAL->Env.db_errbuf = RETVAL->ErrBuff ; */
            env->set_errcall(env, db_errcall_cb) ;
            RETVAL->active = TRUE ;
 #ifdef IS_DB_3_0_x
@@ -1517,7 +1735,7 @@ _db_appinit(self, ref)
          else {
              (env->close)(env, 0) ;
               if (RETVAL->ErrHandle)
-                  SvREFCNT_dec(RETVAL->ErrHandle) ;
+                  fclose(RETVAL->ErrHandle) ;
               if (RETVAL->ErrPrefix)
                   SvREFCNT_dec(RETVAL->ErrPrefix) ;
               Safefree(RETVAL) ;
@@ -1592,7 +1810,7 @@ _txn_begin(env, pid=NULL, flags=0)
              ZMALLOC(RETVAL, BerkeleyDB_Txn_type) ;
              RETVAL->txn  = txn ;
              RETVAL->active = TRUE ;
-             Trace(("_txn_begin created txn [%d] in [%d]\n", txn, RETVAL));
+             Trace(("_txn_begin created txn [%p] in [%p]\n", txn, RETVAL));
              hash_store_iv("BerkeleyDB::Term::Txn", (char *)RETVAL, 1) ;
            }
            else
@@ -1727,6 +1945,7 @@ status(env)
 DualType
 db_appexit(env)
         BerkeleyDB::Env        env
+       ALIAS:  close =1
        INIT:
            ckActive_Environment(env->active) ;
        CODE:
@@ -1760,7 +1979,7 @@ _DESTROY(env)
              (env->Env->close)(env->Env, 0) ;
 #endif
           if (env->ErrHandle)
-              SvREFCNT_dec(env->ErrHandle) ;
+              fclose(env->ErrHandle) ;
           if (env->ErrPrefix)
               SvREFCNT_dec(env->ErrPrefix) ;
 #if DB_VERSION_MAJOR == 2
@@ -1870,7 +2089,7 @@ set_mutexlocks(env, do_lock)
            softCrash("$env->set_setmutexlocks needs Berkeley DB 3.0 or better") ;
 #else
 #  ifdef AT_LEAST_DB_4
-           RETVAL = env->Status = env->Env->set_flags(env->Env, DB_NOLOCKING, 1);
+           RETVAL = env->Status = env->Env->set_flags(env->Env, DB_NOLOCKING, do_lock);
 #  else
 #    if defined(AT_LEAST_DB_3_2_6) || defined(IS_DB_3_0_x)
            RETVAL = env->Status = env->Env->set_mutexlocks(env->Env, do_lock);
@@ -1882,6 +2101,39 @@ set_mutexlocks(env, do_lock)
        OUTPUT:
            RETVAL
 
+int
+set_verbose(env, which, onoff)
+        BerkeleyDB::Env  env
+       u_int32_t        which
+       int              onoff
+       INIT:
+         ckActive_Database(env->active) ;
+       CODE:
+#ifndef AT_LEAST_DB_3
+           softCrash("$env->set_verbose needs Berkeley DB 3.x or better") ;
+#else
+           RETVAL = env->Status = env->Env->set_verbose(env->Env, which, onoff);
+#endif
+       OUTPUT:
+           RETVAL
+
+int
+set_flags(env, flags, onoff)
+        BerkeleyDB::Env  env
+       u_int32_t        flags
+       int              onoff
+       INIT:
+         ckActive_Database(env->active) ;
+       CODE:
+#ifndef AT_LEAST_DB_3_2
+           softCrash("$env->set_flags needs Berkeley DB 3.2.x or better") ;
+#else
+           RETVAL = env->Status = env->Env->set_flags(env->Env, flags, onoff);
+#endif
+       OUTPUT:
+           RETVAL
+
+
 MODULE = BerkeleyDB::Term              PACKAGE = BerkeleyDB::Term
 
 void
@@ -1910,11 +2162,13 @@ _db_open_hash(self, ref)
            int                 flags = 0 ;
            int                 mode = 0 ;
            BerkeleyDB          db ;
+           BerkeleyDB__Txn     txn = NULL ;
 
            Trace(("_db_open_hash start\n")) ;
            hash = (HV*) SvRV(ref) ;
            SetValue_pv(file, "Filename", char *) ;
            SetValue_pv(subname, "Subname", char *) ;
+           SetValue_ov(txn, "Txn", BerkeleyDB__Txn) ;
            SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ;
            ref_dbenv = sv ;
            SetValue_iv(flags, "Flags") ;
@@ -1942,7 +2196,7 @@ _db_open_hash(self, ref)
                croak("DupCompare needs Berkeley DB 2.5.9 or later") ;
 #endif
            }
-           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_HASH, flags, mode, &info) ;
+           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, txn, file, subname, DB_HASH, flags, mode, &info) ;
            Trace(("_db_open_hash end\n")) ;
        }
        OUTPUT:
@@ -2018,11 +2272,13 @@ _db_open_unknown(ref)
            int                 mode = 0 ;
            BerkeleyDB          db ;
            BerkeleyDB          RETVAL ;
+           BerkeleyDB__Txn     txn = NULL ;
            static char *               Names[] = {"", "Btree", "Hash", "Recno"} ;
 
            hash = (HV*) SvRV(ref) ;
            SetValue_pv(file, "Filename", char *) ;
            SetValue_pv(subname, "Subname", char *) ;
+           SetValue_ov(txn, "Txn", BerkeleyDB__Txn) ;
            SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ;
            ref_dbenv = sv ;
            SetValue_iv(flags, "Flags") ;
@@ -2037,7 +2293,7 @@ _db_open_unknown(ref)
            SetValue_iv(info.flags, "Property") ;
            ZMALLOC(db, BerkeleyDB_type) ;
 
-           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_UNKNOWN, flags, mode, &info) ;
+           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, txn, file, subname, DB_UNKNOWN, flags, mode, &info) ;
            XPUSHs(sv_2mortal(newSViv(PTR2IV(RETVAL))));
            if (RETVAL)
                XPUSHs(sv_2mortal(newSVpv(Names[RETVAL->type], 0))) ;
@@ -2065,10 +2321,13 @@ _db_open_btree(self, ref)
            int                 flags = 0 ;
            int                 mode = 0 ;
            BerkeleyDB          db ;
+           BerkeleyDB__Txn     txn = NULL ;
 
+           Trace(("In _db_open_btree\n"));
            hash = (HV*) SvRV(ref) ;
            SetValue_pv(file, "Filename", char*) ;
            SetValue_pv(subname, "Subname", char *) ;
+           SetValue_ov(txn, "Txn", BerkeleyDB__Txn) ;
            SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ;
            ref_dbenv = sv ;
            SetValue_iv(flags, "Flags") ;
@@ -2082,12 +2341,14 @@ _db_open_btree(self, ref)
            SetValue_iv(info.flags, "Property") ;
            ZMALLOC(db, BerkeleyDB_type) ;
            if ((sv = readHash(hash, "Compare")) && sv != &PL_sv_undef) {
+               Trace(("    Parsed Compare callback\n"));
                info.bt_compare = btree_compare ;
                db->compare = newSVsv(sv) ;
            }
            /* DB_DUPSORT was introduced in DB 2.5.9 */
            if ((sv = readHash(hash, "DupCompare")) && sv != &PL_sv_undef) {
 #ifdef DB_DUPSORT
+               Trace(("    Parsed DupCompare callback\n"));
                info.dup_compare = dup_compare ;
                db->dup_compare = newSVsv(sv) ;
                info.flags |= DB_DUP|DB_DUPSORT ;
@@ -2096,11 +2357,12 @@ _db_open_btree(self, ref)
 #endif
            }
            if ((sv = readHash(hash, "Prefix")) && sv != &PL_sv_undef) {
+               Trace(("    Parsed Prefix callback\n"));
                info.bt_prefix = btree_prefix ;
                db->prefix = newSVsv(sv) ;
            }
 
-           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_BTREE, flags, mode, &info) ;
+           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, txn, file, subname, DB_BTREE, flags, mode, &info) ;
        }
        OUTPUT:
            RETVAL
@@ -2189,11 +2451,13 @@ _db_open_recno(self, ref)
            int                 flags = 0 ;
            int                 mode = 0 ;
            BerkeleyDB          db ;
+           BerkeleyDB__Txn     txn = NULL ;
 
            hash = (HV*) SvRV(ref) ;
            SetValue_pv(file, "Fname", char*) ;
            SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ;
            ref_dbenv = sv ;
+           SetValue_ov(txn, "Txn", BerkeleyDB__Txn) ;
            SetValue_iv(flags, "Flags") ;
            SetValue_iv(mode, "Mode") ;
 
@@ -2223,7 +2487,7 @@ _db_open_recno(self, ref)
            db->array_base = (db->array_base == 0 ? 1 : 0) ;
 #endif /* ALLOW_RECNO_OFFSET */
 
-           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_RECNO, flags, mode, &info) ;
+           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, txn, file, subname, DB_RECNO, flags, mode, &info) ;
        }
        OUTPUT:
            RETVAL
@@ -2250,11 +2514,13 @@ _db_open_queue(self, ref)
            int                 flags = 0 ;
            int                 mode = 0 ;
            BerkeleyDB          db ;
+           BerkeleyDB__Txn     txn = NULL ;
 
            hash = (HV*) SvRV(ref) ;
            SetValue_pv(file, "Fname", char*) ;
            SetValue_ov(dbenv, "Env", BerkeleyDB__Env) ;
            ref_dbenv = sv ;
+           SetValue_ov(txn, "Txn", BerkeleyDB__Txn) ;
            SetValue_iv(flags, "Flags") ;
            SetValue_iv(mode, "Mode") ;
 
@@ -2269,7 +2535,7 @@ _db_open_queue(self, ref)
            SetValue_iv(info.flags, "Property") ;
            if ((sv = readHash(hash, "Len")) && sv != &PL_sv_undef) {
                info.re_len = SvIV(sv) ; ;
-               flagSet_DB2(info.flags, DB_PAD) ;
+               flagSet_DB2(info.flags, DB_FIXEDLEN) ;
            }
            if ((sv = readHash(hash, "Pad")) && sv != &PL_sv_undef) {
                info.re_pad = (u_int32_t)SvPOK(sv) ? *SvPV(sv,PL_na) : SvIV(sv) ; ;
@@ -2281,7 +2547,7 @@ _db_open_queue(self, ref)
            db->array_base = (db->array_base == 0 ? 1 : 0) ;
 #endif /* ALLOW_RECNO_OFFSET */
 
-           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, file, subname, DB_QUEUE, flags, mode, &info) ;
+           RETVAL = my_db_open(db, ref, ref_dbenv, dbenv, txn, file, subname, DB_QUEUE, flags, mode, &info) ;
 #endif
        }
        OUTPUT:
@@ -2397,11 +2663,16 @@ _db_cursor(db, flags=0)
              RETVAL->parent_db  = db ;
              RETVAL->cursor  = cursor ;
              RETVAL->dbp     = db->dbp ;
+             RETVAL->txn     = db->txn ;
               RETVAL->type    = db->type ;
               RETVAL->recno_or_queue    = db->recno_or_queue ;
               RETVAL->filename    = my_strdup(db->filename) ;
               RETVAL->compare = db->compare ;
               RETVAL->dup_compare = db->dup_compare ;
+#ifdef AT_LEAST_DB_3_3
+              RETVAL->associated = db->associated ;
+             RETVAL->secondary_db  = db->secondary_db;
+#endif
               RETVAL->prefix  = db->prefix ;
               RETVAL->hash    = db->hash ;
              RETVAL->partial = db->partial ;
@@ -2467,6 +2738,10 @@ _db_join(db, cursors, flags=0)
               RETVAL->filename    = my_strdup(db->filename) ;
               RETVAL->compare = db->compare ;
               RETVAL->dup_compare = db->dup_compare ;
+#ifdef AT_LEAST_DB_3_3
+              RETVAL->associated = db->associated ;
+             RETVAL->secondary_db  = db->secondary_db;
+#endif
               RETVAL->prefix  = db->prefix ;
               RETVAL->hash    = db->hash ;
              RETVAL->partial = db->partial ;
@@ -2642,10 +2917,20 @@ db_del(db, key, flags=0)
        BerkeleyDB::Common      db
        DBTKEY          key
        INIT:
+           Trace(("db_del db[%p] in [%p] txn[%p] key[%.*s] flags[%d]\n", db->dbp, db, db->txn, key.size, key.data, flags)) ;
            ckActive_Database(db->active) ;
            CurrentDB = db ;
 
 
+#ifdef AT_LEAST_DB_3
+#  ifdef AT_LEAST_DB_3_2
+#    define writeToKey() (flagSet(DB_CONSUME)||flagSet(DB_CONSUME_WAIT)||flagSet(DB_GET_BOTH)||flagSet(DB_SET_RECNO))
+#  else
+#    define writeToKey() (flagSet(DB_CONSUME)||flagSet(DB_GET_BOTH)||flagSet(DB_SET_RECNO))
+#  endif
+#else
+#define writeToKey() (flagSet(DB_GET_BOTH)||flagSet(DB_SET_RECNO))
+#endif
 #define db_get(db, key, data, flags)   \
        (db->Status = ((db->dbp)->get)(db->dbp, db->txn, &key, &data, flags))
 DualType
@@ -2654,12 +2939,43 @@ db_get(db, key, data, flags=0)
        BerkeleyDB::Common      db
        DBTKEY_B        key
        DBT_OPT         data
-       INIT:
+       CODE:
+         ckActive_Database(db->active) ;
+         CurrentDB = db ;
+         SetPartial(data,db) ;
+         Trace(("db_get db[%p] in [%p] txn[%p] key [%.*s] flags[%d]\n", db->dbp, db, db->txn, key.size, key.data, flags)) ;
+         RETVAL = db_get(db, key, data, flags);
+         Trace(("  RETVAL %d\n", RETVAL));
+       OUTPUT:
+         RETVAL
+         key   if (writeToKey()) OutputValue(ST(1), key) ;
+         data
+
+#define db_pget(db, key, pkey, data, flags)   \
+       (db->Status = ((db->dbp)->pget)(db->dbp, db->txn, &key, &pkey, &data, flags))
+DualType
+db_pget(db, key, pkey, data, flags=0)
+       u_int           flags
+       BerkeleyDB::Common      db
+       DBTKEY_B        key
+       DBTKEY_B        pkey = NO_INIT
+       DBT_OPT         data
+       CODE:
+#ifndef AT_LEAST_DB_3_3
+          softCrash("db_pget needs at least Berkeley DB 3.3");
+#else
+         Trace(("db_pget db [%p] in [%p] txn [%p] flags [%d]\n", db->dbp, db, db->txn, flags)) ;
          ckActive_Database(db->active) ;
          CurrentDB = db ;
          SetPartial(data,db) ;
+         DBT_clear(pkey);
+         RETVAL = db_pget(db, key, pkey, data, flags);
+         Trace(("  RETVAL %d\n", RETVAL));
+#endif
        OUTPUT:
-         key   if (flagSet(DB_SET_RECNO)) OutputValue(ST(1), key) ;
+         RETVAL
+         key   if (writeToKey()) OutputValue(ST(1), key) ;
+         pkey
          data
 
 #define db_put(db,key,data,flag)       \
@@ -2670,11 +2986,15 @@ db_put(db, key, data, flags=0)
        BerkeleyDB::Common      db
        DBTKEY                  key
        DBT                     data
-       INIT:
+       CODE:
          ckActive_Database(db->active) ;
          CurrentDB = db ;
          /* SetPartial(data,db) ; */
+         Trace(("db_put db[%p] in [%p] txn[%p] key[%.*s] data [%.*s] flags[%d]\n", db->dbp, db, db->txn, key.size, key.data, data.size, data.data, flags)) ;
+         RETVAL = db_put(db, key, data, flags);
+         Trace(("  RETVAL %d\n", RETVAL));
        OUTPUT:
+         RETVAL
          key   if (flagSet(DB_APPEND)) OutputKey(ST(1), key) ;
 
 #define db_key_range(db, key, range, flags)   \
@@ -2741,16 +3061,64 @@ _Txn(db, txn=NULL)
          ckActive_Database(db->active) ;
        CODE:
           if (txn) {
-              Trace(("_Txn(%d in %d) active [%d]\n", txn->txn, txn, txn->active));
+              Trace(("_Txn[%p] in[%p] active [%d]\n", txn->txn, txn, txn->active));
               ckActive_Transaction(txn->active) ;
               db->txn = txn->txn ;
           }
           else {
-              Trace(("_Txn(undef) \n"));
+              Trace(("_Txn[undef] \n"));
               db->txn = NULL ;
           }
 
 
+#define db_truncate(db, countp, flags)  \
+       (db->Status = ((db->dbp)->truncate)(db->dbp, db->txn, &countp, flags))
+DualType
+truncate(db, countp, flags=0)
+       BerkeleyDB::Common      db
+       u_int32_t               countp
+       u_int32_t               flags
+       INIT:
+         ckActive_Database(db->active) ;
+       CODE:
+#ifndef AT_LEAST_DB_3_3
+          softCrash("truncate needs Berkeley DB 3.3 or later") ;
+#else
+         CurrentDB = db ;
+         RETVAL = db_truncate(db, countp, flags);
+#endif
+       OUTPUT:
+         RETVAL
+         countp
+
+#ifdef AT_LEAST_DB_4_1
+#  define db_associate(db, sec, cb, flags)\
+       (db->Status = ((db->dbp)->associate)(db->dbp, NULL, sec->dbp, &cb, flags))
+#else
+#  define db_associate(db, sec, cb, flags)\
+       (db->Status = ((db->dbp)->associate)(db->dbp, sec->dbp, &cb, flags))
+#endif
+DualType
+associate(db, secondary, callback, flags=0)
+       BerkeleyDB::Common      db
+       BerkeleyDB::Common      secondary
+       SV*                     callback
+       u_int32_t               flags
+       INIT:
+         ckActive_Database(db->active) ;
+       CODE:
+#ifndef AT_LEAST_DB_3_3
+          softCrash("associate needs Berkeley DB 3.3 or later") ;
+#else
+         CurrentDB = db ;
+         /* db->associated = newSVsv(callback) ; */
+         secondary->associated = newSVsv(callback) ;
+         /* secondary->dbp->app_private = secondary->associated ; */
+         secondary->secondary_db = TRUE;
+         RETVAL = db_associate(db, secondary, associate_cb, flags);
+#endif
+       OUTPUT:
+         RETVAL
 
 
 MODULE = BerkeleyDB::Cursor              PACKAGE = BerkeleyDB::Cursor  PREFIX = cu_
@@ -2781,6 +3149,9 @@ _c_dup(db, flags=0)
               RETVAL->filename    = my_strdup(db->filename) ;
               RETVAL->compare = db->compare ;
               RETVAL->dup_compare = db->dup_compare ;
+#ifdef AT_LEAST_DB_3_3
+              RETVAL->associated = db->associated ;
+#endif
               RETVAL->prefix  = db->prefix ;
               RETVAL->hash    = db->hash ;
              RETVAL->partial = db->partial ;
@@ -2865,7 +3236,7 @@ cu_c_get(db, key, data, flags=0)
     DBTKEY_B           key
     DBT_B              data
        INIT:
-         Trace(("c_get db [%d] flags [%d]\n", db, flags)) ;
+         Trace(("c_get db [%p] in [%p] flags [%d]\n", db->dbp, db, flags)) ;
          CurrentDB = db->parent_db ;
          ckActive_Cursor(db->active) ;
          SetPartial(data,db) ;
@@ -2875,6 +3246,33 @@ cu_c_get(db, key, data, flags=0)
          key
          data          if (! flagSet(DB_JOIN_ITEM)) OutputValue_B(ST(2), data) ;
 
+#define cu_c_pget(c,k,p,d,f) (c->Status = (c->secondary_db ? (c->cursor->c_pget)(c->cursor,&k,&p,&d,f) : EINVAL))
+DualType
+cu_c_pget(db, key, pkey, data, flags=0)
+    int                        flags
+    BerkeleyDB::Cursor db
+    DBTKEY_B           key
+    DBTKEY_B           pkey = NO_INIT
+    DBT_B              data
+       CODE:
+#ifndef AT_LEAST_DB_3_3
+          softCrash("db_c_pget needs at least Berkeley DB 3.3");
+#else
+         Trace(("c_pget db [%d] flags [%d]\n", db, flags)) ;
+         CurrentDB = db->parent_db ;
+         ckActive_Cursor(db->active) ;
+         SetPartial(data,db) ;
+         DBT_clear(pkey);
+         RETVAL = cu_c_pget(db, key, pkey, data, flags);
+         Trace(("c_pget end\n")) ;
+#endif
+       OUTPUT:
+         RETVAL
+         key
+         pkey
+         data          if (! flagSet(DB_JOIN_ITEM)) OutputValue_B(ST(2), data) ;
+
+
 
 #define cu_c_put(c,k,d,f)  (c->Status = (c->cursor->c_put)(c->cursor,&k,&d,f))
 DualType
index 732dbac..caad636 100644 (file)
@@ -1,12 +1,36 @@
 Revision history for Perl extension BerkeleyDB.
 
-0.17 26 23 September 2001
+0.19 5th June 2002
+        * Removed the targets that used mkconsts from Makefile.PL. They relied
+          on a module that is not available in all versions of Perl.
+        * added support for env->set_verbose
+        * added support for db->truncate
+        * added support for db->rename via BerkeleyDB::db_rename
+        * added support for db->verify via BerkeleyDB::db_verify
+        * added support for db->associate, db->pget & cursor->c_pget
+        * Builds with Berkeley DB 4.1.x
+
+0.18 6th January 2002
+        * Dropped support for ErrFile as a file handle. It was proving too
+          difficult to get at the underlying FILE * in XS.
+          Reported by Jonas Smedegaard (Debian powerpc) & Kenneth Olwing (Win32)
+        * Fixed problem with abort macro in XSUB.h clashing with txn abort
+          method in Berkeley DB 4.x -- patch supplied by Kenneth Olwing.
+        * DB->set_alloc was getting called too late in BerkeleyDB.xs. 
+          This was causing problems with ActivePerl -- problem reported
+          by Kenneth Olwing.
+        * When opening a queue, the Len proprty set the DB_PAD flag. 
+          Should have been DB_FIXEDLEN. Fix provided by Kenneth Olwing.
+        * Test harness fixes from Kenneth Olwing.
+
+0.17 23 September 2001
         * Fixed a bug in BerkeleyDB::Recno - reported by Niklas Paulsson. 
         * Added log_archive - patch supplied by Benjamin Holzman
         * Added txn_discard
         * Builds with Berkeley DB 4.0.x
 
-0.16 26 1 August 2001
+0.16 1 August 2001
         * added support for Berkeley DB 3.3.x (but no support for any of the
           new features just yet)
 
index 6e9857b..7da51ef 100644 (file)
@@ -9,17 +9,20 @@ config.in
 constants.h
 constants.xs
 dbinfo
+hints/dec_osf.pl
 hints/solaris.pl
 hints/irix_6_5.pl
 Makefile.PL
 MANIFEST
 mkconsts
 mkpod
+ppport.h
 README
 t/btree.t
 t/db-3.0.t
 t/db-3.1.t
 t/db-3.2.t
+t/db-3.3.t
 t/destroy.t
 t/env.t
 t/examples.t
@@ -50,3 +53,4 @@ patches/5.005_01
 patches/5.005_02
 patches/5.005_03
 patches/5.6.0
+scan
index dbf0f2c..e0e17bb 100644 (file)
@@ -43,7 +43,7 @@ $OS2 = "-DOS2" if $^O eq 'os2' ;
 WriteMakefile(
        NAME            => 'BerkeleyDB',
        LIBS            => ["-L${LIB_DIR} $LIBS"],
-        MAN3PODS        => ' ',         # Pods will be built by installman.
+       MAN3PODS        => {},         # Pods will be built by installman. 
        INC             => "-I$INC_DIR",
        VERSION_FROM    => 'BerkeleyDB.pm',
        XSPROTOARG      => '-noprototypes',
@@ -63,15 +63,9 @@ sub MY::postamble {
 $(NAME).pod:   $(NAME).pod.P t/examples.t.T t/examples3.t.T mkpod
        perl ./mkpod
 
-$(NAME).xs:    constants.h constants.xs typemap
+$(NAME).xs:    typemap
        $(TOUCH) $(NAME).xs
 
-constants.h constants.xs:      mkconsts
-       bleedperl mkconsts xs 
-
-$(NAME).pm:    mkconsts
-       bleedperl mkconsts pm $(NAME).pm > $(NAME).pm.tmp && mv $(NAME).pm.tmp $(NAME).pm
-
 Makefile:      config.in 
 
 
index 8640949..c4ed4da 100644 (file)
@@ -1,10 +1,10 @@
                                    BerkeleyDB
 
-                                  Version 0.17
+                                  Version 0.19
 
-                                22nd October 2001
+                                  5th June 2002
 
-       Copyright (c) 1997-2001 Paul Marquess. All rights reserved. This
+       Copyright (c) 1997-2002 Paul Marquess. All rights reserved. This
        program is free software; you can redistribute it and/or modify
        it under the same terms as Perl itself.
 
@@ -106,37 +106,56 @@ This symptom can imply:
     Solution: Edit config.in and set the LIB and INCLUDE variables to point
               to the directories where libdb.a and db.h are installed.
 
-Wrong db.h
-----------
+#error db.h is not for Berkeley DB at all.
+------------------------------------------
 
-If you get an error like this when building this module:
+If you get the error above when building this module it means that there
+is a file called "db.h" on your system that isn't the one that comes
+with Berkeley DB.
 
-  cc -c -I./libraries/ -Dbool=char -DHAS_BOOL -I/usr/local/include -O2
-  -DVERSION=\"0.07\" -DXS_VERSION=\"0.07\" -fpic
-  -I/usr/local/lib/perl5/5.00503/i586-linux/CORE  BerkeleyDB.c
-  BerkeleyDB.xs:93: parse error before `DB_INFO'
-  BerkeleyDB.xs:93: warning: no semicolon at end of struct or union
-  BerkeleyDB.xs:94: warning: data definition has no type or storage class
-  BerkeleyDB.xs:95: parse error before `0x80000000'
-  BerkeleyDB.xs:110: parse error before `}'
-  BerkeleyDB.xs:110: warning: data definition has no type or storage class
-  BerkeleyDB.xs:117: parse error before `DB_ENV'
-  ...
+Options:
+
+ 1. You don't have Berkeley DB installed on your system at all.
+    Solution: get & install Berkeley DB.
+
+ 2. Edit config.in and make sure the INCLUDE variable points to the
+    directory where the Berkeley DB file db.h is installed.
+
+ 3. If option 2 doesn't work, try tempoarily renaming the db.h file
+    that is causing the error.
 
-This error usually happens when if you only have Berkeley DB version 1
-on your system or you have both version 1 and version 2 (or 3) of Berkeley
-DB installed on your system. When building BerkeleyDB it attempts 
-to use the db.h for Berkeley DB version 1. This perl module can only
-be built with Berkeley DB version 2 or 3.
+#error db.h is for Berkeley DB 1.x - need at least Berkeley DB 2.6.4
+--------------------------------------------------------------------
+
+The error above will occur if there is a copy of the Berkeley DB 1.x
+file db.h on your system.
+
+This error will happen when 
+
+  1. you only have Berkeley DB version 1 on your system.
+     Solution: get & install a newer version of Berkeley DB.
+
+  2. you have both version 1 and a later version of Berkeley DB
+     installed on your system. When building BerkeleyDB it attempts to
+     use the db.h for Berkeley DB version 1.
+     Solution: Edit config.in and set the LIB and INCLUDE variables
+               to point to the directories where libdb.a and db.h are
+               installed.
+
+
+#error db.h is for Berkeley DB 2.0-2.5 - need at least Berkeley DB 2.6.4
+------------------------------------------------------------------------
+
+The error above will occur if there is a copy of the the file db.h for
+Berkeley DB 2.0 to 2.5 on your system.
 
 This symptom can imply:
 
- 1. You don't have Berkeley DB version 2 or 3 installed on your system
-    at all.
-    Solution: get & install Berkeley DB.
+ 1. You don't have a new enough version of Berkeley DB.
+    Solution: get & install a newer version of Berkeley DB.
 
- 2. You do have Berkeley DB 2 or 3 installed, but it isn't in a standard
-    place.
+ 2. You have the correct version of Berkeley DB installed, but it isn't
+    in a standard place.
     Solution: Edit config.in and set the LIB and INCLUDE variables
               to point to the directories where libdb.a and db.h are
               installed.
@@ -158,11 +177,11 @@ when you run the test harness:
   at /usr/local/lib/perl5/5.00503/i586-linux/DynaLoader.pm line 169.
   ...
 
-This error usually happens when you have both version 1 and version
-2 (or 3) of Berkeley DB installed on your system and BerkeleyDB attempts
-to build using the db.h for Berkeley DB version 2/3 and the version 1
+This error usually happens when you have both version 1 and a newer version
+of Berkeley DB installed on your system. BerkeleyDB attempts
+to build using the db.h for Berkeley DB version 2/3/4 and the version 1
 library. Unfortunately the two versions aren't compatible with each
-other. BerkeleyDB can only be built with Berkeley DB version 2 or 3.
+other. BerkeleyDB can only be built with Berkeley DB version 2, 3 or 4.
 
 Solution: Setting the LIB & INCLUDE variables in config.in to point to the
           correct directories can sometimes be enough to fix this
@@ -302,7 +321,7 @@ be used to build this module. Follow the instructions in "BUILDING THE
 MODULE", remembering to set the INCLUDE and LIB variables in config.in.
 
 
-The second approach will work with both Berkeley DB 2.x and 3.x.
+The second approach will work with Berkeley DB 2.x or better.
 Start by building Berkeley DB as a shared library. This is from
 the Berkeley DB build instructions:
 
@@ -420,7 +439,7 @@ To help me help you, I need of the following information:
  2. The version of BerkeleyDB you have. If you have successfully
     installed BerkeleyDB, this one-liner will tell you:
 
-       perl -MBerkeleyDB -e 'print "BerkeleyDB ver $BerkeleyDB::VERSION\n"'
+       perl -MBerkeleyDB -e 'print qq{BerkeleyDB ver $BerkeleyDB::VERSION\n}'
 
     If you haven't installed BerkeleyDB then search BerkeleyDB.pm for a
     line like this:
@@ -430,7 +449,7 @@ To help me help you, I need of the following information:
  3. The version of Berkeley DB you have installed. If you have
     successfully installed BerkeleyDB, this one-liner will tell you:
 
-        perl -MBerkeleyDB -e 'print BerkeleyDB::DB_VERSION_STRING."\n"'
+        perl -MBerkeleyDB -e 'print BerkeleyDB::DB_VERSION_STRING.qq{\n}'
 
     If you haven't installed BerkeleyDB then search db.h for a line
     like this:
index ab3c026..d5b4c00 100644 (file)
@@ -7,26 +7,28 @@
 #    Change the path below to point to the directory where db.h is
 #    installed on your system.
 
-INCLUDE        = /usr/local/include
-#INCLUDE       = /usr/local/BerkeleyDB/include
+#INCLUDE       = /usr/local/include
+INCLUDE        = /usr/local/BerkeleyDB/include
 #INCLUDE       = ./libraries/2.7.5/include
 #INCLUDE       = ./libraries/3.0.55/include
 #INCLUDE       = ./libraries/3.1.17/include
 #INCLUDE       = ./libraries/3.3.11/include
-#INCLUDE       = ./libraries/4.0.7/include
+#INCLUDE       = ./libraries/4.1.12/include
+#INCLUDE       = ./libraries/4.0.14/include
 
 # 2. Where is libdb?
 #
 #    Change the path below to point to the directory where libdb is
 #    installed on your system.
 
-LIB    = /usr/local/lib
-#LIB   = /usr/local/BerkeleyDB/lib
+#LIB   = /usr/local/lib
+LIB    = /usr/local/BerkeleyDB/lib
 #LIB   = ./libraries/2.7.5/lib
 #LIB   = ./libraries/3.0.55/lib
 #LIB   = ./libraries/3.1.17/lib
 #LIB   = ./libraries/3.3.11/lib
-#LIB   = ./libraries/4.0.7/lib
+#LIB   = ./libraries/4.1.12/lib
+#LIB   = ./libraries/4.0.14/lib
 
 # 3. Is the library called libdb?
 #
index 83db0fe..257d5c2 100644 (file)
@@ -245,77 +245,78 @@ static int
 constant_9 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_APPEND DB_BEFORE DB_CLIENT DB_COMMIT DB_CREATE DB_CURLSN DB_EXTENT
-     DB_GETREC DB_NOMMAP DB_NOSYNC DB_RDONLY DB_RECNUM DB_THREAD DB_VERIFY */
-  /* Offset 5 gives the best switch position.  */
-  switch (name[5]) {
-  case 'C':
-    if (memEQ(name, "DB_RECNUM", 9)) {
-    /*                    ^         */
-#ifdef DB_RECNUM
-      *iv_return = DB_RECNUM;
+     DB_APPEND DB_BEFORE DB_CLIENT DB_COMMIT DB_CREATE DB_CURLSN DB_DIRECT
+     DB_EXTENT DB_GETREC DB_NOCOPY DB_NOMMAP DB_NOSYNC DB_RDONLY DB_RECNUM
+     DB_THREAD DB_VERIFY */
+  /* Offset 7 gives the best switch position.  */
+  switch (name[7]) {
+  case 'A':
+    if (memEQ(name, "DB_NOMMAP", 9)) {
+    /*                      ^       */
+#ifdef DB_NOMMAP
+      *iv_return = DB_NOMMAP;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'E':
-    if (memEQ(name, "DB_CREATE", 9)) {
-    /*                    ^         */
-#ifdef DB_CREATE
-      *iv_return = DB_CREATE;
+    if (memEQ(name, "DB_THREAD", 9)) {
+    /*                      ^       */
+#ifdef DB_THREAD
+      *iv_return = DB_THREAD;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'F':
-    if (memEQ(name, "DB_BEFORE", 9)) {
-    /*                    ^         */
-#ifdef DB_BEFORE
-      *iv_return = DB_BEFORE;
+  case 'C':
+    if (memEQ(name, "DB_DIRECT", 9)) {
+    /*                      ^       */
+#ifdef DB_DIRECT
+      *iv_return = DB_DIRECT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'I':
-    if (memEQ(name, "DB_CLIENT", 9)) {
-    /*                    ^         */
-#ifdef DB_CLIENT
-      *iv_return = DB_CLIENT;
+  case 'E':
+    if (memEQ(name, "DB_GETREC", 9)) {
+    /*                      ^       */
+#ifdef DB_GETREC
+      *iv_return = DB_GETREC;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'M':
-    if (memEQ(name, "DB_COMMIT", 9)) {
-    /*                    ^         */
-#ifdef DB_COMMIT
-      *iv_return = DB_COMMIT;
+  case 'F':
+    if (memEQ(name, "DB_VERIFY", 9)) {
+    /*                      ^       */
+#ifdef DB_VERIFY
+      *iv_return = DB_VERIFY;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_NOMMAP", 9)) {
-    /*                    ^         */
-#ifdef DB_NOMMAP
-      *iv_return = DB_NOMMAP;
+    break;
+  case 'I':
+    if (memEQ(name, "DB_COMMIT", 9)) {
+    /*                      ^       */
+#ifdef DB_COMMIT
+      *iv_return = DB_COMMIT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'O':
+  case 'L':
     if (memEQ(name, "DB_RDONLY", 9)) {
-    /*                    ^         */
+    /*                      ^       */
 #ifdef DB_RDONLY
       *iv_return = DB_RDONLY;
       return PERL_constant_ISIV;
@@ -324,9 +325,9 @@ constant_9 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
-  case 'P':
+  case 'N':
     if (memEQ(name, "DB_APPEND", 9)) {
-    /*                    ^         */
+    /*                      ^       */
 #ifdef DB_APPEND
       *iv_return = DB_APPEND;
       return PERL_constant_ISIV;
@@ -334,30 +335,50 @@ constant_9 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'R':
-    if (memEQ(name, "DB_CURLSN", 9)) {
-    /*                    ^         */
-#ifdef DB_CURLSN
-      *iv_return = DB_CURLSN;
+    if (memEQ(name, "DB_CLIENT", 9)) {
+    /*                      ^       */
+#ifdef DB_CLIENT
+      *iv_return = DB_CLIENT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_THREAD", 9)) {
-    /*                    ^         */
-#ifdef DB_THREAD
-      *iv_return = DB_THREAD;
+    if (memEQ(name, "DB_EXTENT", 9)) {
+    /*                      ^       */
+#ifdef DB_EXTENT
+      *iv_return = DB_EXTENT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_VERIFY", 9)) {
-    /*                    ^         */
-#ifdef DB_VERIFY
-      *iv_return = DB_VERIFY;
+    if (memEQ(name, "DB_NOSYNC", 9)) {
+    /*                      ^       */
+#ifdef DB_NOSYNC
+      *iv_return = DB_NOSYNC;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
+  case 'P':
+    if (memEQ(name, "DB_NOCOPY", 9)) {
+    /*                      ^       */
+#ifdef DB_NOCOPY
+      *iv_return = DB_NOCOPY;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
+  case 'R':
+    if (memEQ(name, "DB_BEFORE", 9)) {
+    /*                      ^       */
+#ifdef DB_BEFORE
+      *iv_return = DB_BEFORE;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -365,10 +386,10 @@ constant_9 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'S':
-    if (memEQ(name, "DB_NOSYNC", 9)) {
-    /*                    ^         */
-#ifdef DB_NOSYNC
-      *iv_return = DB_NOSYNC;
+    if (memEQ(name, "DB_CURLSN", 9)) {
+    /*                      ^       */
+#ifdef DB_CURLSN
+      *iv_return = DB_CURLSN;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -376,19 +397,21 @@ constant_9 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'T':
-    if (memEQ(name, "DB_EXTENT", 9)) {
-    /*                    ^         */
-#ifdef DB_EXTENT
-      *iv_return = DB_EXTENT;
+    if (memEQ(name, "DB_CREATE", 9)) {
+    /*                      ^       */
+#ifdef DB_CREATE
+      *iv_return = DB_CREATE;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_GETREC", 9)) {
-    /*                    ^         */
-#ifdef DB_GETREC
-      *iv_return = DB_GETREC;
+    break;
+  case 'U':
+    if (memEQ(name, "DB_RECNUM", 9)) {
+    /*                      ^       */
+#ifdef DB_RECNUM
+      *iv_return = DB_RECNUM;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -403,9 +426,10 @@ static int
 constant_10 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_CONSUME DB_CURRENT DB_DELETED DB_DUPSORT DB_ENV_CDB DB_ENV_TXN
-     DB_JOINENV DB_KEYLAST DB_NOPANIC DB_OK_HASH DB_PRIVATE DB_PR_PAGE
-     DB_RECOVER DB_SALVAGE DB_TIMEOUT DB_TXN_CKP DB_UNKNOWN DB_UPGRADE */
+     DB_CONSUME DB_CURRENT DB_DELETED DB_DUPSORT DB_ENCRYPT DB_ENV_CDB
+     DB_ENV_TXN DB_JOINENV DB_KEYLAST DB_NOPANIC DB_OK_HASH DB_PRIVATE
+     DB_PR_PAGE DB_RECOVER DB_SALVAGE DB_TIMEOUT DB_TXN_CKP DB_UNKNOWN
+     DB_UPGRADE */
   /* Offset 8 gives the best switch position.  */
   switch (name[8]) {
   case 'D':
@@ -521,6 +545,17 @@ constant_10 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'P':
+    if (memEQ(name, "DB_ENCRYPT", 10)) {
+    /*                       ^        */
+#ifdef DB_ENCRYPT
+      *iv_return = DB_ENCRYPT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'R':
     if (memEQ(name, "DB_DUPSORT", 10)) {
     /*                       ^        */
@@ -611,8 +646,8 @@ constant_11 (pTHX_ const char *name, IV *iv_return) {
      DB_INIT_LOG DB_INIT_TXN DB_KEYEMPTY DB_KEYEXIST DB_KEYFIRST DB_LOCKDOWN
      DB_LOCK_GET DB_LOCK_PUT DB_LOGMAGIC DB_LOG_DISK DB_MULTIPLE DB_NEXT_DUP
      DB_NOSERVER DB_NOTFOUND DB_OK_BTREE DB_OK_QUEUE DB_OK_RECNO DB_POSITION
-     DB_QAMMAGIC DB_RENUMBER DB_SNAPSHOT DB_TRUNCATE DB_TXNMAGIC DB_TXN_REDO
-     DB_TXN_SYNC DB_TXN_UNDO DB_YIELDCPU */
+     DB_QAMMAGIC DB_RENUMBER DB_SNAPSHOT DB_TRUNCATE DB_TXNMAGIC DB_TXN_LOCK
+     DB_TXN_REDO DB_TXN_SYNC DB_TXN_UNDO DB_WRNOSYNC DB_YIELDCPU */
   /* Offset 8 gives the best switch position.  */
   switch (name[8]) {
   case 'A':
@@ -855,6 +890,15 @@ constant_11 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_TXN_LOCK", 11)) {
+    /*                       ^         */
+#ifdef DB_TXN_LOCK
+      *iv_return = DB_TXN_LOCK;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   case 'P':
     if (memEQ(name, "DB_KEYEMPTY", 11)) {
@@ -951,6 +995,15 @@ constant_11 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_WRNOSYNC", 11)) {
+    /*                       ^         */
+#ifdef DB_WRNOSYNC
+      *iv_return = DB_WRNOSYNC;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   }
   return PERL_constant_NOTFOUND;
@@ -960,13 +1013,14 @@ static int
 constant_12 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_ARCH_DATA DB_CDB_ALLDB DB_CL_WRITER DB_DELIMITER DB_DUPCURSOR
-     DB_FAST_STAT DB_GET_BOTHC DB_GET_RECNO DB_HASHMAGIC DB_INIT_LOCK
-     DB_JOIN_ITEM DB_LOCKMAGIC DB_LOCK_DUMP DB_LOCK_RW_N DB_LOGOLDVER
-     DB_MAX_PAGES DB_MPOOL_NEW DB_NEEDSPLIT DB_NODUPDATA DB_NOLOCKING
-     DB_NORECURSE DB_PAGEYIELD DB_PAGE_LOCK DB_POSITIONI DB_QAMOLDVER
+     DB_ARCH_DATA DB_CDB_ALLDB DB_CL_WRITER DB_DELIMITER DB_DIRECT_DB
+     DB_DUPCURSOR DB_ENV_FATAL DB_FAST_STAT DB_GET_BOTHC DB_GET_RECNO
+     DB_HASHMAGIC DB_INIT_LOCK DB_JOIN_ITEM DB_LOCKMAGIC DB_LOCK_DUMP
+     DB_LOCK_RW_N DB_LOGOLDVER DB_MAX_PAGES DB_MPOOL_NEW DB_NEEDSPLIT
+     DB_NODUPDATA DB_NOLOCKING DB_NORECURSE DB_OVERWRITE DB_PAGEYIELD
+     DB_PAGE_LOCK DB_PERMANENT DB_POSITIONI DB_PRINTABLE DB_QAMOLDVER
      DB_SET_RANGE DB_SET_RECNO DB_SWAPBYTES DB_TEMPORARY DB_TXN_ABORT
-     DB_TXN_APPLY DB_WRITELOCK DB_XA_CREATE */
+     DB_TXN_APPLY DB_TXN_PRINT DB_WRITELOCK DB_WRITEOPEN DB_XA_CREATE */
   /* Offset 3 gives the best switch position.  */
   switch (name[3]) {
   case 'A':
@@ -1010,6 +1064,15 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_DIRECT_DB", 12)) {
+    /*                  ^               */
+#ifdef DB_DIRECT_DB
+      *iv_return = DB_DIRECT_DB;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_DUPCURSOR", 12)) {
     /*                  ^               */
 #ifdef DB_DUPCURSOR
@@ -1020,6 +1083,17 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'E':
+    if (memEQ(name, "DB_ENV_FATAL", 12)) {
+    /*                  ^               */
+#ifdef DB_ENV_FATAL
+      *iv_return = DB_ENV_FATAL;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'F':
     if (memEQ(name, "DB_FAST_STAT", 12)) {
     /*                  ^               */
@@ -1183,6 +1257,17 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'O':
+    if (memEQ(name, "DB_OVERWRITE", 12)) {
+    /*                  ^               */
+#ifdef DB_OVERWRITE
+      *iv_return = DB_OVERWRITE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'P':
     if (memEQ(name, "DB_PAGEYIELD", 12)) {
     /*                  ^               */
@@ -1202,6 +1287,15 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_PERMANENT", 12)) {
+    /*                  ^               */
+#ifdef DB_PERMANENT
+      *iv_return = DB_PERMANENT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_POSITIONI", 12)) {
     /*                  ^               */
 #ifdef DB_POSITIONI
@@ -1211,6 +1305,15 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_PRINTABLE", 12)) {
+    /*                  ^               */
+#ifdef DB_PRINTABLE
+      *iv_return = DB_PRINTABLE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   case 'Q':
     if (memEQ(name, "DB_QAMOLDVER", 12)) {
@@ -1286,6 +1389,18 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_TXN_PRINT", 12)) {
+    /*                  ^               */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_TXN_PRINT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   case 'W':
     if (memEQ(name, "DB_WRITELOCK", 12)) {
@@ -1297,6 +1412,15 @@ constant_12 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_WRITEOPEN", 12)) {
+    /*                  ^               */
+#ifdef DB_WRITEOPEN
+      *iv_return = DB_WRITEOPEN;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   case 'X':
     if (memEQ(name, "DB_XA_CREATE", 12)) {
@@ -1317,13 +1441,14 @@ static int
 constant_13 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_AGGRESSIVE DB_BTREEMAGIC DB_CHECKPOINT DB_DIRTY_READ DB_DONOTINDEX
-     DB_ENV_CREATE DB_ENV_NOMMAP DB_ENV_THREAD DB_HASHOLDVER DB_INCOMPLETE
-     DB_INIT_MPOOL DB_LOCK_NORUN DB_LOCK_RIW_N DB_LOGVERSION DB_LOG_LOCKED
-     DB_MPOOL_LAST DB_MUTEXDEBUG DB_MUTEXLOCKS DB_NEXT_NODUP DB_NOORDERCHK
-     DB_PREV_NODUP DB_PR_HEADERS DB_QAMVERSION DB_RDWRMASTER DB_REGISTERED
-     DB_REP_CLIENT DB_REP_MASTER DB_SEQUENTIAL DB_STAT_CLEAR DB_SYSTEM_MEM
-     DB_TXNVERSION DB_TXN_NOSYNC DB_TXN_NOWAIT DB_VERIFY_BAD */
+     DB_AGGRESSIVE DB_BTREEMAGIC DB_CHECKPOINT DB_DIRECT_LOG DB_DIRTY_READ
+     DB_DONOTINDEX DB_ENV_CREATE DB_ENV_NOMMAP DB_ENV_THREAD DB_HASHOLDVER
+     DB_INCOMPLETE DB_INIT_MPOOL DB_LOCK_NORUN DB_LOCK_RIW_N DB_LOCK_TRADE
+     DB_LOGVERSION DB_LOG_LOCKED DB_MPOOL_LAST DB_MUTEXDEBUG DB_MUTEXLOCKS
+     DB_NEXT_NODUP DB_NOORDERCHK DB_PREV_NODUP DB_PR_HEADERS DB_QAMVERSION
+     DB_RDWRMASTER DB_REGISTERED DB_REP_CLIENT DB_REP_MASTER DB_SEQUENTIAL
+     DB_STAT_CLEAR DB_SYSTEM_MEM DB_TXNVERSION DB_TXN_NOSYNC DB_TXN_NOWAIT
+     DB_VERIFY_BAD */
   /* Offset 5 gives the best switch position.  */
   switch (name[5]) {
   case 'A':
@@ -1365,6 +1490,18 @@ constant_13 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_LOCK_TRADE", 13)) {
+    /*                    ^              */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_LOCK_TRADE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     break;
   case 'E':
     if (memEQ(name, "DB_CHECKPOINT", 13)) {
@@ -1545,6 +1682,15 @@ constant_13 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_DIRECT_LOG", 13)) {
+    /*                    ^              */
+#ifdef DB_DIRECT_LOG
+      *iv_return = DB_DIRECT_LOG;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_DIRTY_READ", 13)) {
     /*                    ^              */
 #ifdef DB_DIRTY_READ
@@ -1674,14 +1820,16 @@ static int
 constant_14 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_BTREEOLDVER DB_ENV_APPINIT DB_ENV_DBLOCAL DB_ENV_LOCKING DB_ENV_LOGGING
-     DB_ENV_NOPANIC DB_ENV_PRIVATE DB_FILE_ID_LEN DB_HASHVERSION DB_INVALID_EID
+     DB_AUTO_COMMIT DB_BTREEOLDVER DB_CHKSUM_SHA1 DB_EID_INVALID DB_ENCRYPT_AES
+     DB_ENV_APPINIT DB_ENV_DBLOCAL DB_ENV_LOCKING DB_ENV_LOGGING DB_ENV_NOPANIC
+     DB_ENV_PRIVATE DB_FILE_ID_LEN DB_HANDLE_LOCK DB_HASHVERSION DB_INVALID_EID
      DB_JOIN_NOSORT DB_LOCKVERSION DB_LOCK_EXPIRE DB_LOCK_NOWAIT DB_LOCK_OLDEST
-     DB_LOCK_RANDOM DB_LOCK_RECORD DB_LOCK_SWITCH DB_MAX_RECORDS DB_MPOOL_CLEAN
-     DB_MPOOL_DIRTY DB_NOOVERWRITE DB_NOSERVER_ID DB_ODDFILESIZE DB_OLD_VERSION
-     DB_OPEN_CALLED DB_RECORDCOUNT DB_RECORD_LOCK DB_REGION_ANON DB_REGION_INIT
-     DB_REGION_NAME DB_REP_NEWSITE DB_REP_UNAVAIL DB_REVSPLITOFF DB_RUNRECOVERY
-     DB_SET_TXN_NOW DB_USE_ENVIRON DB_WRITECURSOR DB_XIDDATASIZE */
+     DB_LOCK_RANDOM DB_LOCK_RECORD DB_LOCK_REMOVE DB_LOCK_SWITCH DB_MAX_RECORDS
+     DB_MPOOL_CLEAN DB_MPOOL_DIRTY DB_NOOVERWRITE DB_NOSERVER_ID DB_ODDFILESIZE
+     DB_OLD_VERSION DB_OPEN_CALLED DB_RECORDCOUNT DB_RECORD_LOCK DB_REGION_ANON
+     DB_REGION_INIT DB_REGION_NAME DB_RENAMEMAGIC DB_REP_NEWSITE DB_REP_UNAVAIL
+     DB_REVSPLITOFF DB_RUNRECOVERY DB_SET_TXN_NOW DB_USE_ENVIRON DB_WRITECURSOR
+     DB_XIDDATASIZE */
   /* Offset 9 gives the best switch position.  */
   switch (name[9]) {
   case 'A':
@@ -1799,6 +1947,15 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_LOCK_REMOVE", 14)) {
+    /*                        ^           */
+#ifdef DB_LOCK_REMOVE
+      *iv_return = DB_LOCK_REMOVE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_NOSERVER_ID", 14)) {
     /*                        ^           */
 #ifdef DB_NOSERVER_ID
@@ -1878,6 +2035,17 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'M':
+    if (memEQ(name, "DB_RENAMEMAGIC", 14)) {
+    /*                        ^           */
+#ifdef DB_RENAMEMAGIC
+      *iv_return = DB_RENAMEMAGIC;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'N':
     if (memEQ(name, "DB_SET_TXN_NOW", 14)) {
     /*                        ^           */
@@ -1890,6 +2058,15 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'O':
+    if (memEQ(name, "DB_AUTO_COMMIT", 14)) {
+    /*                        ^           */
+#ifdef DB_AUTO_COMMIT
+      *iv_return = DB_AUTO_COMMIT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_JOIN_NOSORT", 14)) {
     /*                        ^           */
 #ifdef DB_JOIN_NOSORT
@@ -1967,6 +2144,17 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'T':
+    if (memEQ(name, "DB_ENCRYPT_AES", 14)) {
+    /*                        ^           */
+#ifdef DB_ENCRYPT_AES
+      *iv_return = DB_ENCRYPT_AES;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'U':
     if (memEQ(name, "DB_WRITECURSOR", 14)) {
     /*                        ^           */
@@ -1979,6 +2167,15 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'V':
+    if (memEQ(name, "DB_EID_INVALID", 14)) {
+    /*                        ^           */
+#ifdef DB_EID_INVALID
+      *iv_return = DB_EID_INVALID;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_USE_ENVIRON", 14)) {
     /*                        ^           */
 #ifdef DB_USE_ENVIRON
@@ -2030,6 +2227,24 @@ constant_14 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case '_':
+    if (memEQ(name, "DB_CHKSUM_SHA1", 14)) {
+    /*                        ^           */
+#ifdef DB_CHKSUM_SHA1
+      *iv_return = DB_CHKSUM_SHA1;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_HANDLE_LOCK", 14)) {
+    /*                        ^           */
+#ifdef DB_HANDLE_LOCK
+      *iv_return = DB_HANDLE_LOCK;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_RECORD_LOCK", 14)) {
     /*                        ^           */
 #ifdef DB_RECORD_LOCK
@@ -2079,10 +2294,10 @@ constant_15 (pTHX_ const char *name, IV *iv_return) {
      DB_ENV_PANIC_OK DB_ENV_YIELDCPU DB_LOCK_DEFAULT DB_LOCK_INHERIT
      DB_LOCK_NOTHELD DB_LOCK_PUT_ALL DB_LOCK_PUT_OBJ DB_LOCK_TIMEOUT
      DB_LOCK_UPGRADE DB_MPOOL_CREATE DB_MPOOL_EXTENT DB_MULTIPLE_KEY
-     DB_OPFLAGS_MASK DB_ORDERCHKONLY DB_REGION_MAGIC DB_REP_LOGSONLY
-     DB_REP_OUTDATED DB_SURPRISE_KID DB_TEST_POSTLOG DB_TEST_PREOPEN
-     DB_TXN_LOCK_2PL DB_TXN_LOG_MASK DB_TXN_LOG_REDO DB_TXN_LOG_UNDO
-     DB_VERIFY_FATAL */
+     DB_OPFLAGS_MASK DB_ORDERCHKONLY DB_PRIORITY_LOW DB_REGION_MAGIC
+     DB_REP_LOGSONLY DB_REP_OUTDATED DB_SURPRISE_KID DB_TEST_POSTLOG
+     DB_TEST_PREOPEN DB_TXN_GETPGNOS DB_TXN_LOCK_2PL DB_TXN_LOG_MASK
+     DB_TXN_LOG_REDO DB_TXN_LOG_UNDO DB_VERIFY_FATAL */
   /* Offset 10 gives the best switch position.  */
   switch (name[10]) {
   case 'D':
@@ -2255,6 +2470,20 @@ constant_15 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'P':
+    if (memEQ(name, "DB_TXN_GETPGNOS", 15)) {
+    /*                         ^           */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_TXN_GETPGNOS;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case 'R':
     if (memEQ(name, "DB_BTREEVERSION", 15)) {
     /*                         ^           */
@@ -2341,6 +2570,20 @@ constant_15 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'Y':
+    if (memEQ(name, "DB_PRIORITY_LOW", 15)) {
+    /*                         ^           */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_PRIORITY_LOW;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   case '_':
     if (memEQ(name, "DB_CONSUME_WAIT", 15)) {
     /*                         ^           */
@@ -2396,49 +2639,53 @@ static int
 constant_16 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_BROADCAST_EID DB_CACHED_COUNTS DB_ENV_CDB_ALLDB DB_ENV_NOLOCKING
-     DB_ENV_RPCCLIENT DB_FCNTL_LOCKING DB_JAVA_CALLBACK DB_LOCK_CONFLICT
-     DB_LOCK_DEADLOCK DB_LOCK_MAXLOCKS DB_LOCK_MINLOCKS DB_LOCK_MINWRITE
+     DB_BROADCAST_EID DB_CACHED_COUNTS DB_EID_BROADCAST DB_ENV_CDB_ALLDB
+     DB_ENV_DIRECT_DB DB_ENV_NOLOCKING DB_ENV_OVERWRITE DB_ENV_RPCCLIENT
+     DB_FCNTL_LOCKING DB_JAVA_CALLBACK DB_LOCK_CONFLICT DB_LOCK_DEADLOCK
+     DB_LOCK_MAXLOCKS DB_LOCK_MINLOCKS DB_LOCK_MINWRITE DB_LOCK_NOTEXIST
      DB_LOCK_PUT_READ DB_LOCK_YOUNGEST DB_LOGC_BUF_SIZE DB_MPOOL_DISCARD
-     DB_MPOOL_PRIVATE DB_NOSERVER_HOME DB_PAGE_NOTFOUND DB_RECOVER_FATAL
-     DB_REP_DUPMASTER DB_REP_NEWMASTER DB_REP_PERMANENT DB_SECONDARY_BAD
-     DB_TEST_POSTOPEN DB_TEST_POSTSYNC DB_TXN_LOCK_MASK DB_TXN_OPENFILES
-     DB_VERB_CHKPOINT DB_VERB_DEADLOCK DB_VERB_RECOVERY DB_VERB_WAITSFOR
-     DB_VERSION_MAJOR DB_VERSION_MINOR DB_VERSION_PATCH DB_VRFY_FLAGMASK */
-  /* Offset 11 gives the best switch position.  */
-  switch (name[11]) {
+     DB_MPOOL_PRIVATE DB_NOSERVER_HOME DB_PAGE_NOTFOUND DB_PRIORITY_HIGH
+     DB_RECOVER_FATAL DB_REP_DUPMASTER DB_REP_NEWMASTER DB_REP_PERMANENT
+     DB_SECONDARY_BAD DB_TEST_POSTOPEN DB_TEST_POSTSYNC DB_TXN_LOCK_MASK
+     DB_TXN_OPENFILES DB_VERB_CHKPOINT DB_VERB_DEADLOCK DB_VERB_RECOVERY
+     DB_VERB_WAITSFOR DB_VERSION_MAJOR DB_VERSION_MINOR DB_VERSION_PATCH
+     DB_VRFY_FLAGMASK */
+  /* Offset 12 gives the best switch position.  */
+  switch (name[12]) {
   case 'A':
-    if (memEQ(name, "DB_ENV_CDB_ALLDB", 16)) {
-    /*                                    */
-#ifdef DB_ENV_CDB_ALLDB
-      *iv_return = DB_ENV_CDB_ALLDB;
+    if (memEQ(name, "DB_RECOVER_FATAL", 16)) {
+    /*                           ^          */
+#ifdef DB_RECOVER_FATAL
+      *iv_return = DB_RECOVER_FATAL;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_REP_DUPMASTER", 16)) {
-    /*                                    */
-#ifdef DB_REP_DUPMASTER
-      *iv_return = DB_REP_DUPMASTER;
+    if (memEQ(name, "DB_VERSION_MAJOR", 16)) {
+    /*                           ^          */
+#ifdef DB_VERSION_MAJOR
+      *iv_return = DB_VERSION_MAJOR;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_REP_NEWMASTER", 16)) {
-    /*                                    */
-#ifdef DB_REP_NEWMASTER
-      *iv_return = DB_REP_NEWMASTER;
+    if (memEQ(name, "DB_VERSION_PATCH", 16)) {
+    /*                           ^          */
+#ifdef DB_VERSION_PATCH
+      *iv_return = DB_VERSION_PATCH;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_REP_PERMANENT", 16)) {
-    /*                          ^           */
-#ifdef DB_REP_PERMANENT
-      *iv_return = DB_REP_PERMANENT;
+    break;
+  case 'B':
+    if (memEQ(name, "DB_JAVA_CALLBACK", 16)) {
+    /*                           ^          */
+#ifdef DB_JAVA_CALLBACK
+      *iv_return = DB_JAVA_CALLBACK;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2446,75 +2693,71 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'C':
-    if (memEQ(name, "DB_ENV_NOLOCKING", 16)) {
-    /*                                    */
-#ifdef DB_ENV_NOLOCKING
-      *iv_return = DB_ENV_NOLOCKING;
+    if (memEQ(name, "DB_EID_BROADCAST", 16)) {
+    /*                           ^          */
+#ifdef DB_EID_BROADCAST
+      *iv_return = DB_EID_BROADCAST;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_FCNTL_LOCKING", 16)) {
-    /*                                    */
-#ifdef DB_FCNTL_LOCKING
-      *iv_return = DB_FCNTL_LOCKING;
+    if (memEQ(name, "DB_MPOOL_DISCARD", 16)) {
+    /*                           ^          */
+#ifdef DB_MPOOL_DISCARD
+      *iv_return = DB_MPOOL_DISCARD;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'D':
-    if (memEQ(name, "DB_LOCK_DEADLOCK", 16)) {
-    /*                          ^           */
-#ifdef DB_LOCK_DEADLOCK
-      *iv_return = DB_LOCK_DEADLOCK;
-      return PERL_constant_ISIV;
-#else
-      return PERL_constant_NOTDEF;
-#endif
-    }
-    if (memEQ(name, "DB_VERB_DEADLOCK", 16)) {
-    /*                          ^           */
-#ifdef DB_VERB_DEADLOCK
-      *iv_return = DB_VERB_DEADLOCK;
+  case 'G':
+    if (memEQ(name, "DB_LOCK_YOUNGEST", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_YOUNGEST
+      *iv_return = DB_LOCK_YOUNGEST;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'F':
-    if (memEQ(name, "DB_LOCK_CONFLICT", 16)) {
-    /*                                    */
-#ifdef DB_LOCK_CONFLICT
-      *iv_return = DB_LOCK_CONFLICT;
+  case 'H':
+    if (memEQ(name, "DB_NOSERVER_HOME", 16)) {
+    /*                           ^          */
+#ifdef DB_NOSERVER_HOME
+      *iv_return = DB_NOSERVER_HOME;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_PAGE_NOTFOUND", 16)) {
-    /*                          ^           */
-#ifdef DB_PAGE_NOTFOUND
-      *iv_return = DB_PAGE_NOTFOUND;
+    if (memEQ(name, "DB_PRIORITY_HIGH", 16)) {
+    /*                           ^          */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_PRIORITY_HIGH;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_RECOVER_FATAL", 16)) {
-    /*                          ^           */
-#ifdef DB_RECOVER_FATAL
-      *iv_return = DB_RECOVER_FATAL;
+    break;
+  case 'I':
+    if (memEQ(name, "DB_ENV_RPCCLIENT", 16)) {
+    /*                           ^          */
+#ifdef DB_ENV_RPCCLIENT
+      *iv_return = DB_ENV_RPCCLIENT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     if (memEQ(name, "DB_TXN_OPENFILES", 16)) {
-    /*                                    */
+    /*                           ^          */
 #if (DB_VERSION_MAJOR > 3) || \
     (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \
     (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \
@@ -2525,23 +2768,30 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'G':
-    if (memEQ(name, "DB_VRFY_FLAGMASK", 16)) {
-    /*                          ^           */
-#ifdef DB_VRFY_FLAGMASK
-      *iv_return = DB_VRFY_FLAGMASK;
+    if (memEQ(name, "DB_VERSION_MINOR", 16)) {
+    /*                           ^          */
+#ifdef DB_VERSION_MINOR
+      *iv_return = DB_VERSION_MINOR;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'I':
-    if (memEQ(name, "DB_MPOOL_PRIVATE", 16)) {
-    /*                          ^           */
-#ifdef DB_MPOOL_PRIVATE
-      *iv_return = DB_MPOOL_PRIVATE;
+  case 'K':
+    if (memEQ(name, "DB_ENV_NOLOCKING", 16)) {
+    /*                           ^          */
+#ifdef DB_ENV_NOLOCKING
+      *iv_return = DB_ENV_NOLOCKING;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_FCNTL_LOCKING", 16)) {
+    /*                           ^          */
+#ifdef DB_FCNTL_LOCKING
+      *iv_return = DB_FCNTL_LOCKING;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2549,37 +2799,37 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'L':
-    if (memEQ(name, "DB_ENV_RPCCLIENT", 16)) {
-    /*                                    */
-#ifdef DB_ENV_RPCCLIENT
-      *iv_return = DB_ENV_RPCCLIENT;
+    if (memEQ(name, "DB_ENV_CDB_ALLDB", 16)) {
+    /*                           ^          */
+#ifdef DB_ENV_CDB_ALLDB
+      *iv_return = DB_ENV_CDB_ALLDB;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_JAVA_CALLBACK", 16)) {
-    /*                                    */
-#ifdef DB_JAVA_CALLBACK
-      *iv_return = DB_JAVA_CALLBACK;
+    if (memEQ(name, "DB_LOCK_CONFLICT", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_CONFLICT
+      *iv_return = DB_LOCK_CONFLICT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_LOCK_MAXLOCKS", 16)) {
-    /*                                    */
-#ifdef DB_LOCK_MAXLOCKS
-      *iv_return = DB_LOCK_MAXLOCKS;
+    if (memEQ(name, "DB_LOCK_DEADLOCK", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_DEADLOCK
+      *iv_return = DB_LOCK_DEADLOCK;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_LOCK_MINLOCKS", 16)) {
-    /*                                    */
-#ifdef DB_LOCK_MINLOCKS
-      *iv_return = DB_LOCK_MINLOCKS;
+    if (memEQ(name, "DB_VERB_DEADLOCK", 16)) {
+    /*                           ^          */
+#ifdef DB_VERB_DEADLOCK
+      *iv_return = DB_VERB_DEADLOCK;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2587,19 +2837,19 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'M':
-    if (memEQ(name, "DB_VERSION_MAJOR", 16)) {
-    /*                                    */
-#ifdef DB_VERSION_MAJOR
-      *iv_return = DB_VERSION_MAJOR;
+    if (memEQ(name, "DB_TXN_LOCK_MASK", 16)) {
+    /*                           ^          */
+#ifdef DB_TXN_LOCK_MASK
+      *iv_return = DB_TXN_LOCK_MASK;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_VERSION_MINOR", 16)) {
-    /*                                    */
-#ifdef DB_VERSION_MINOR
-      *iv_return = DB_VERSION_MINOR;
+    if (memEQ(name, "DB_VRFY_FLAGMASK", 16)) {
+    /*                           ^          */
+#ifdef DB_VRFY_FLAGMASK
+      *iv_return = DB_VRFY_FLAGMASK;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2607,10 +2857,10 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'N':
-    if (memEQ(name, "DB_LOCK_YOUNGEST", 16)) {
-    /*                                    */
-#ifdef DB_LOCK_YOUNGEST
-      *iv_return = DB_LOCK_YOUNGEST;
+    if (memEQ(name, "DB_REP_PERMANENT", 16)) {
+    /*                           ^          */
+#ifdef DB_REP_PERMANENT
+      *iv_return = DB_REP_PERMANENT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2618,28 +2868,44 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'O':
-    if (memEQ(name, "DB_CACHED_COUNTS", 16)) {
-    /*                                    */
-#ifdef DB_CACHED_COUNTS
-      *iv_return = DB_CACHED_COUNTS;
+    if (memEQ(name, "DB_LOCK_MAXLOCKS", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_MAXLOCKS
+      *iv_return = DB_LOCK_MAXLOCKS;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_VERB_RECOVERY", 16)) {
-    /*                          ^           */
-#ifdef DB_VERB_RECOVERY
-      *iv_return = DB_VERB_RECOVERY;
+    if (memEQ(name, "DB_LOCK_MINLOCKS", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_MINLOCKS
+      *iv_return = DB_LOCK_MINLOCKS;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_PAGE_NOTFOUND", 16)) {
+    /*                           ^          */
+#ifdef DB_PAGE_NOTFOUND
+      *iv_return = DB_PAGE_NOTFOUND;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_TEST_POSTOPEN", 16)) {
+    /*                           ^          */
+#ifdef DB_TEST_POSTOPEN
+      *iv_return = DB_TEST_POSTOPEN;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'P':
     if (memEQ(name, "DB_VERB_CHKPOINT", 16)) {
-    /*                                    */
+    /*                           ^          */
 #ifdef DB_VERB_CHKPOINT
       *iv_return = DB_VERB_CHKPOINT;
       return PERL_constant_ISIV;
@@ -2647,10 +2913,33 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_VERSION_PATCH", 16)) {
-    /*                          ^           */
-#ifdef DB_VERSION_PATCH
-      *iv_return = DB_VERSION_PATCH;
+    break;
+  case 'R':
+    if (memEQ(name, "DB_ENV_OVERWRITE", 16)) {
+    /*                           ^          */
+#ifdef DB_ENV_OVERWRITE
+      *iv_return = DB_ENV_OVERWRITE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_LOCK_MINWRITE", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_MINWRITE
+      *iv_return = DB_LOCK_MINWRITE;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_LOCK_PUT_READ", 16)) {
+    /*                           ^          */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \
+     DB_VERSION_PATCH >= 7)
+      *iv_return = DB_LOCK_PUT_READ;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2658,37 +2947,35 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case 'S':
-    if (memEQ(name, "DB_MPOOL_DISCARD", 16)) {
-    /*                                    */
-#ifdef DB_MPOOL_DISCARD
-      *iv_return = DB_MPOOL_DISCARD;
+    if (memEQ(name, "DB_LOGC_BUF_SIZE", 16)) {
+    /*                           ^          */
+#ifdef DB_LOGC_BUF_SIZE
+      *iv_return = DB_LOGC_BUF_SIZE;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'T':
-    if (memEQ(name, "DB_BROADCAST_EID", 16)) {
-    /*                          ^           */
-#ifdef DB_BROADCAST_EID
-      *iv_return = DB_BROADCAST_EID;
+    if (memEQ(name, "DB_REP_DUPMASTER", 16)) {
+    /*                           ^          */
+#ifdef DB_REP_DUPMASTER
+      *iv_return = DB_REP_DUPMASTER;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_TEST_POSTOPEN", 16)) {
-    /*                                    */
-#ifdef DB_TEST_POSTOPEN
-      *iv_return = DB_TEST_POSTOPEN;
+    if (memEQ(name, "DB_REP_NEWMASTER", 16)) {
+    /*                           ^          */
+#ifdef DB_REP_NEWMASTER
+      *iv_return = DB_REP_NEWMASTER;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     if (memEQ(name, "DB_TEST_POSTSYNC", 16)) {
-    /*                                    */
+    /*                           ^          */
 #ifdef DB_TEST_POSTSYNC
       *iv_return = DB_TEST_POSTSYNC;
       return PERL_constant_ISIV;
@@ -2697,7 +2984,7 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     if (memEQ(name, "DB_VERB_WAITSFOR", 16)) {
-    /*                                    */
+    /*                           ^          */
 #ifdef DB_VERB_WAITSFOR
       *iv_return = DB_VERB_WAITSFOR;
       return PERL_constant_ISIV;
@@ -2706,63 +2993,73 @@ constant_16 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
-  case 'W':
-    if (memEQ(name, "DB_LOCK_MINWRITE", 16)) {
-    /*                                    */
-#ifdef DB_LOCK_MINWRITE
-      *iv_return = DB_LOCK_MINWRITE;
+  case 'T':
+    if (memEQ(name, "DB_ENV_DIRECT_DB", 16)) {
+    /*                           ^          */
+#ifdef DB_ENV_DIRECT_DB
+      *iv_return = DB_ENV_DIRECT_DB;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'Y':
-    if (memEQ(name, "DB_SECONDARY_BAD", 16)) {
-    /*                                    */
-#ifdef DB_SECONDARY_BAD
-      *iv_return = DB_SECONDARY_BAD;
+  case 'U':
+    if (memEQ(name, "DB_CACHED_COUNTS", 16)) {
+    /*                           ^          */
+#ifdef DB_CACHED_COUNTS
+      *iv_return = DB_CACHED_COUNTS;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case '_':
-    if (memEQ(name, "DB_LOCK_PUT_READ", 16)) {
-    /*                          ^           */
-#if (DB_VERSION_MAJOR > 4) || \
-    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \
-    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \
-     DB_VERSION_PATCH >= 7)
-      *iv_return = DB_LOCK_PUT_READ;
+  case 'V':
+    if (memEQ(name, "DB_MPOOL_PRIVATE", 16)) {
+    /*                           ^          */
+#ifdef DB_MPOOL_PRIVATE
+      *iv_return = DB_MPOOL_PRIVATE;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_LOGC_BUF_SIZE", 16)) {
-    /*                                    */
-#ifdef DB_LOGC_BUF_SIZE
-      *iv_return = DB_LOGC_BUF_SIZE;
+    if (memEQ(name, "DB_VERB_RECOVERY", 16)) {
+    /*                           ^          */
+#ifdef DB_VERB_RECOVERY
+      *iv_return = DB_VERB_RECOVERY;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_NOSERVER_HOME", 16)) {
-    /*                          ^           */
-#ifdef DB_NOSERVER_HOME
-      *iv_return = DB_NOSERVER_HOME;
+    break;
+  case 'X':
+    if (memEQ(name, "DB_LOCK_NOTEXIST", 16)) {
+    /*                           ^          */
+#ifdef DB_LOCK_NOTEXIST
+      *iv_return = DB_LOCK_NOTEXIST;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_TXN_LOCK_MASK", 16)) {
-    /*                          ^           */
-#ifdef DB_TXN_LOCK_MASK
-      *iv_return = DB_TXN_LOCK_MASK;
+    break;
+  case '_':
+    if (memEQ(name, "DB_BROADCAST_EID", 16)) {
+    /*                           ^          */
+#ifdef DB_BROADCAST_EID
+      *iv_return = DB_BROADCAST_EID;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_SECONDARY_BAD", 16)) {
+    /*                           ^          */
+#ifdef DB_SECONDARY_BAD
+      *iv_return = DB_SECONDARY_BAD;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -2777,10 +3074,10 @@ static int
 constant_17 (pTHX_ const char *name, IV *iv_return, const char **pv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_ENV_REP_CLIENT DB_ENV_REP_MASTER DB_ENV_STANDALONE DB_ENV_SYSTEM_MEM
-     DB_ENV_TXN_NOSYNC DB_ENV_USER_ALLOC DB_GET_BOTH_RANGE DB_LOG_SILENT_ERR
-     DB_RPC_SERVERPROG DB_RPC_SERVERVERS DB_TEST_PRERENAME DB_TXN_POPENFILES
-     DB_VERSION_STRING */
+     DB_ENV_DIRECT_LOG DB_ENV_REP_CLIENT DB_ENV_REP_MASTER DB_ENV_STANDALONE
+     DB_ENV_SYSTEM_MEM DB_ENV_TXN_NOSYNC DB_ENV_USER_ALLOC DB_GET_BOTH_RANGE
+     DB_LOG_SILENT_ERR DB_RPC_SERVERPROG DB_RPC_SERVERVERS DB_TEST_PRERENAME
+     DB_TXN_POPENFILES DB_VERSION_STRING */
   /* Offset 14 gives the best switch position.  */
   switch (name[14]) {
   case 'A':
@@ -2835,6 +3132,15 @@ constant_17 (pTHX_ const char *name, IV *iv_return, const char **pv_return) {
     }
     break;
   case 'L':
+    if (memEQ(name, "DB_ENV_DIRECT_LOG", 17)) {
+    /*                             ^         */
+#ifdef DB_ENV_DIRECT_LOG
+      *iv_return = DB_ENV_DIRECT_LOG;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
     if (memEQ(name, "DB_ENV_USER_ALLOC", 17)) {
     /*                             ^         */
 #ifdef DB_ENV_USER_ALLOC
@@ -3054,27 +3360,59 @@ constant_19 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
      DB_ENV_REP_LOGSONLY DB_LOCK_FREE_LOCKER DB_LOCK_GET_TIMEOUT
-     DB_LOCK_SET_TIMEOUT DB_REP_HOLDELECTION DB_SET_LOCK_TIMEOUT
-     DB_TEST_POSTDESTROY DB_TEST_POSTEXTOPEN DB_TEST_POSTLOGMETA
-     DB_TXN_FORWARD_ROLL DB_TXN_LOG_UNDOREDO DB_UNRESOLVED_CHILD
-     DB_UPDATE_SECONDARY DB_USE_ENVIRON_ROOT */
-  /* Offset 13 gives the best switch position.  */
-  switch (name[13]) {
-  case 'D':
-    if (memEQ(name, "DB_TXN_FORWARD_ROLL", 19)) {
-    /*                            ^            */
-#if (DB_VERSION_MAJOR > 3) || \
-    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \
-    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \
-     DB_VERSION_PATCH >= 12)
-      *iv_return = DB_TXN_FORWARD_ROLL;
+     DB_LOCK_SET_TIMEOUT DB_PRIORITY_DEFAULT DB_REP_HOLDELECTION
+     DB_SET_LOCK_TIMEOUT DB_TEST_POSTDESTROY DB_TEST_POSTEXTOPEN
+     DB_TEST_POSTLOGMETA DB_TEST_SUBDB_LOCKS DB_TXN_FORWARD_ROLL
+     DB_TXN_LOG_UNDOREDO DB_TXN_WRITE_NOSYNC DB_UNRESOLVED_CHILD
+     DB_UPDATE_SECONDARY DB_USE_ENVIRON_ROOT DB_VERB_REPLICATION */
+  /* Offset 9 gives the best switch position.  */
+  switch (name[9]) {
+  case 'C':
+    if (memEQ(name, "DB_SET_LOCK_TIMEOUT", 19)) {
+    /*                        ^                */
+#ifdef DB_SET_LOCK_TIMEOUT
+      *iv_return = DB_SET_LOCK_TIMEOUT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
+  case 'E':
+    if (memEQ(name, "DB_LOCK_GET_TIMEOUT", 19)) {
+    /*                        ^                */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \
+     DB_VERSION_PATCH >= 7)
+      *iv_return = DB_LOCK_GET_TIMEOUT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
+    if (memEQ(name, "DB_LOCK_SET_TIMEOUT", 19)) {
+    /*                        ^                */
+#ifdef DB_LOCK_SET_TIMEOUT
+      *iv_return = DB_LOCK_SET_TIMEOUT;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    if (memEQ(name, "DB_VERB_REPLICATION", 19)) {
+    /*                        ^                */
+#ifdef DB_VERB_REPLICATION
+      *iv_return = DB_VERB_REPLICATION;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
+  case 'G':
     if (memEQ(name, "DB_TXN_LOG_UNDOREDO", 19)) {
-    /*                            ^            */
+    /*                        ^                */
 #ifdef DB_TXN_LOG_UNDOREDO
       *iv_return = DB_TXN_LOG_UNDOREDO;
       return PERL_constant_ISIV;
@@ -3083,9 +3421,20 @@ constant_19 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
-  case 'E':
+  case 'I':
+    if (memEQ(name, "DB_TXN_WRITE_NOSYNC", 19)) {
+    /*                        ^                */
+#ifdef DB_TXN_WRITE_NOSYNC
+      *iv_return = DB_TXN_WRITE_NOSYNC;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
+  case 'L':
     if (memEQ(name, "DB_REP_HOLDELECTION", 19)) {
-    /*                            ^            */
+    /*                        ^                */
 #ifdef DB_REP_HOLDELECTION
       *iv_return = DB_REP_HOLDELECTION;
       return PERL_constant_ISIV;
@@ -3093,62 +3442,59 @@ constant_19 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_TEST_POSTDESTROY", 19)) {
-    /*                            ^            */
-#ifdef DB_TEST_POSTDESTROY
-      *iv_return = DB_TEST_POSTDESTROY;
+    if (memEQ(name, "DB_UNRESOLVED_CHILD", 19)) {
+    /*                        ^                */
+#ifdef DB_UNRESOLVED_CHILD
+      *iv_return = DB_UNRESOLVED_CHILD;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'G':
-    if (memEQ(name, "DB_ENV_REP_LOGSONLY", 19)) {
-    /*                            ^            */
-#ifdef DB_ENV_REP_LOGSONLY
-      *iv_return = DB_ENV_REP_LOGSONLY;
+  case 'O':
+    if (memEQ(name, "DB_TEST_POSTDESTROY", 19)) {
+    /*                        ^                */
+#ifdef DB_TEST_POSTDESTROY
+      *iv_return = DB_TEST_POSTDESTROY;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'I':
-    if (memEQ(name, "DB_LOCK_GET_TIMEOUT", 19)) {
-    /*                            ^            */
-#if (DB_VERSION_MAJOR > 4) || \
-    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \
-    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \
-     DB_VERSION_PATCH >= 7)
-      *iv_return = DB_LOCK_GET_TIMEOUT;
+    if (memEQ(name, "DB_TEST_POSTEXTOPEN", 19)) {
+    /*                        ^                */
+#ifdef DB_TEST_POSTEXTOPEN
+      *iv_return = DB_TEST_POSTEXTOPEN;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_LOCK_SET_TIMEOUT", 19)) {
-    /*                            ^            */
-#ifdef DB_LOCK_SET_TIMEOUT
-      *iv_return = DB_LOCK_SET_TIMEOUT;
+    if (memEQ(name, "DB_TEST_POSTLOGMETA", 19)) {
+    /*                        ^                */
+#ifdef DB_TEST_POSTLOGMETA
+      *iv_return = DB_TEST_POSTLOGMETA;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_SET_LOCK_TIMEOUT", 19)) {
-    /*                            ^            */
-#ifdef DB_SET_LOCK_TIMEOUT
-      *iv_return = DB_SET_LOCK_TIMEOUT;
+    break;
+  case 'P':
+    if (memEQ(name, "DB_ENV_REP_LOGSONLY", 19)) {
+    /*                        ^                */
+#ifdef DB_ENV_REP_LOGSONLY
+      *iv_return = DB_ENV_REP_LOGSONLY;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'L':
+  case 'R':
     if (memEQ(name, "DB_LOCK_FREE_LOCKER", 19)) {
-    /*                            ^            */
+    /*                        ^                */
 #ifdef DB_LOCK_FREE_LOCKER
       *iv_return = DB_LOCK_FREE_LOCKER;
       return PERL_constant_ISIV;
@@ -3156,43 +3502,49 @@ constant_19 (pTHX_ const char *name, IV *iv_return) {
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'N':
-    if (memEQ(name, "DB_USE_ENVIRON_ROOT", 19)) {
-    /*                            ^            */
-#ifdef DB_USE_ENVIRON_ROOT
-      *iv_return = DB_USE_ENVIRON_ROOT;
+    if (memEQ(name, "DB_TXN_FORWARD_ROLL", 19)) {
+    /*                        ^                */
+#if (DB_VERSION_MAJOR > 3) || \
+    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_TXN_FORWARD_ROLL;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'O':
-    if (memEQ(name, "DB_TEST_POSTLOGMETA", 19)) {
-    /*                            ^            */
-#ifdef DB_TEST_POSTLOGMETA
-      *iv_return = DB_TEST_POSTLOGMETA;
+  case 'T':
+    if (memEQ(name, "DB_PRIORITY_DEFAULT", 19)) {
+    /*                        ^                */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_PRIORITY_DEFAULT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    if (memEQ(name, "DB_UPDATE_SECONDARY", 19)) {
-    /*                            ^            */
-#ifdef DB_UPDATE_SECONDARY
-      *iv_return = DB_UPDATE_SECONDARY;
+    break;
+  case 'U':
+    if (memEQ(name, "DB_TEST_SUBDB_LOCKS", 19)) {
+    /*                        ^                */
+#ifdef DB_TEST_SUBDB_LOCKS
+      *iv_return = DB_TEST_SUBDB_LOCKS;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'X':
-    if (memEQ(name, "DB_TEST_POSTEXTOPEN", 19)) {
-    /*                            ^            */
-#ifdef DB_TEST_POSTEXTOPEN
-      *iv_return = DB_TEST_POSTEXTOPEN;
+  case 'V':
+    if (memEQ(name, "DB_USE_ENVIRON_ROOT", 19)) {
+    /*                        ^                */
+#ifdef DB_USE_ENVIRON_ROOT
+      *iv_return = DB_USE_ENVIRON_ROOT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -3200,10 +3552,10 @@ constant_19 (pTHX_ const char *name, IV *iv_return) {
     }
     break;
   case '_':
-    if (memEQ(name, "DB_UNRESOLVED_CHILD", 19)) {
-    /*                            ^            */
-#ifdef DB_UNRESOLVED_CHILD
-      *iv_return = DB_UNRESOLVED_CHILD;
+    if (memEQ(name, "DB_UPDATE_SECONDARY", 19)) {
+    /*                        ^                */
+#ifdef DB_UPDATE_SECONDARY
+      *iv_return = DB_UPDATE_SECONDARY;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
@@ -3219,60 +3571,58 @@ constant_20 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
      DB_CXX_NO_EXCEPTIONS DB_LOGFILEID_INVALID DB_PANIC_ENVIRONMENT
-     DB_TEST_PREEXTDELETE DB_TEST_PREEXTUNLINK DB_TXN_BACKWARD_ROLL
-     DB_TXN_LOCK_OPTIMIST */
-  /* Offset 19 gives the best switch position.  */
-  switch (name[19]) {
+     DB_PRIORITY_VERY_LOW DB_TEST_PREEXTDELETE DB_TEST_PREEXTUNLINK
+     DB_TXN_BACKWARD_ROLL DB_TXN_LOCK_OPTIMIST */
+  /* Offset 14 gives the best switch position.  */
+  switch (name[14]) {
   case 'D':
-    if (memEQ(name, "DB_LOGFILEID_INVALID", 20)) {
-    /*                                  ^       */
-#ifdef DB_LOGFILEID_INVALID
-      *iv_return = DB_LOGFILEID_INVALID;
+    if (memEQ(name, "DB_TEST_PREEXTDELETE", 20)) {
+    /*                             ^            */
+#ifdef DB_TEST_PREEXTDELETE
+      *iv_return = DB_TEST_PREEXTDELETE;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
-    break;
-  case 'E':
-    if (memEQ(name, "DB_TEST_PREEXTDELETE", 20)) {
-    /*                                  ^       */
-#ifdef DB_TEST_PREEXTDELETE
-      *iv_return = DB_TEST_PREEXTDELETE;
+    if (memEQ(name, "DB_TXN_BACKWARD_ROLL", 20)) {
+    /*                             ^            */
+#if (DB_VERSION_MAJOR > 3) || \
+    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_TXN_BACKWARD_ROLL;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'K':
-    if (memEQ(name, "DB_TEST_PREEXTUNLINK", 20)) {
-    /*                                  ^       */
-#ifdef DB_TEST_PREEXTUNLINK
-      *iv_return = DB_TEST_PREEXTUNLINK;
+  case 'N':
+    if (memEQ(name, "DB_LOGFILEID_INVALID", 20)) {
+    /*                             ^            */
+#ifdef DB_LOGFILEID_INVALID
+      *iv_return = DB_LOGFILEID_INVALID;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'L':
-    if (memEQ(name, "DB_TXN_BACKWARD_ROLL", 20)) {
-    /*                                  ^       */
-#if (DB_VERSION_MAJOR > 3) || \
-    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \
-    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \
-     DB_VERSION_PATCH >= 12)
-      *iv_return = DB_TXN_BACKWARD_ROLL;
+  case 'O':
+    if (memEQ(name, "DB_PANIC_ENVIRONMENT", 20)) {
+    /*                             ^            */
+#ifdef DB_PANIC_ENVIRONMENT
+      *iv_return = DB_PANIC_ENVIRONMENT;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
     break;
-  case 'S':
+  case 'P':
     if (memEQ(name, "DB_CXX_NO_EXCEPTIONS", 20)) {
-    /*                                  ^       */
+    /*                             ^            */
 #ifdef DB_CXX_NO_EXCEPTIONS
       *iv_return = DB_CXX_NO_EXCEPTIONS;
       return PERL_constant_ISIV;
@@ -3281,18 +3631,23 @@ constant_20 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
-  case 'T':
-    if (memEQ(name, "DB_PANIC_ENVIRONMENT", 20)) {
-    /*                                  ^       */
-#ifdef DB_PANIC_ENVIRONMENT
-      *iv_return = DB_PANIC_ENVIRONMENT;
+  case 'R':
+    if (memEQ(name, "DB_PRIORITY_VERY_LOW", 20)) {
+    /*                             ^            */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_PRIORITY_VERY_LOW;
       return PERL_constant_ISIV;
 #else
       return PERL_constant_NOTDEF;
 #endif
     }
+    break;
+  case 'T':
     if (memEQ(name, "DB_TXN_LOCK_OPTIMIST", 20)) {
-    /*                                  ^       */
+    /*                             ^            */
 #ifdef DB_TXN_LOCK_OPTIMIST
       *iv_return = DB_TXN_LOCK_OPTIMIST;
       return PERL_constant_ISIV;
@@ -3301,6 +3656,17 @@ constant_20 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case 'U':
+    if (memEQ(name, "DB_TEST_PREEXTUNLINK", 20)) {
+    /*                             ^            */
+#ifdef DB_TEST_PREEXTUNLINK
+      *iv_return = DB_TEST_PREEXTUNLINK;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   }
   return PERL_constant_NOTFOUND;
 }
@@ -3309,7 +3675,8 @@ static int
 constant_21 (pTHX_ const char *name, IV *iv_return) {
   /* When generated this function returned values for the list of names given
      here.  However, subsequent manual editing may have added or removed some.
-     DB_LOCK_UPGRADE_WRITE DB_TEST_POSTEXTDELETE DB_TEST_POSTEXTUNLINK */
+     DB_LOCK_UPGRADE_WRITE DB_PRIORITY_VERY_HIGH DB_TEST_POSTEXTDELETE
+     DB_TEST_POSTEXTUNLINK */
   /* Offset 16 gives the best switch position.  */
   switch (name[16]) {
   case 'E':
@@ -3348,6 +3715,20 @@ constant_21 (pTHX_ const char *name, IV *iv_return) {
 #endif
     }
     break;
+  case '_':
+    if (memEQ(name, "DB_PRIORITY_VERY_HIGH", 21)) {
+    /*                               ^           */
+#if (DB_VERSION_MAJOR > 4) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \
+    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \
+     DB_VERSION_PATCH >= 12)
+      *iv_return = DB_PRIORITY_VERY_HIGH;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   }
   return PERL_constant_NOTFOUND;
 }
@@ -3365,57 +3746,62 @@ constant (pTHX_ const char *name, STRLEN len, IV *iv_return, const char **pv_ret
      Regenerate these constant functions by feeding this entire source file to
      perl -x
 
-#!bleedperl -w
+#!/home/paul/perl/install/redhat6.1/5.8.0/bin/perl5.8.0 -w
 use ExtUtils::Constant qw (constant_types C_constant XS_constant);
 
 my $types = {map {($_, 1)} qw(IV PV)};
 my @names = (qw(DB_AFTER DB_AGGRESSIVE DB_ALREADY_ABORTED DB_APPEND
               DB_APPLY_LOGREG DB_APP_INIT DB_ARCH_ABS DB_ARCH_DATA DB_ARCH_LOG
-              DB_BEFORE DB_BROADCAST_EID DB_BTREEMAGIC DB_BTREEOLDVER
-              DB_BTREEVERSION DB_CACHED_COUNTS DB_CDB_ALLDB DB_CHECKPOINT
-              DB_CLIENT DB_CL_WRITER DB_COMMIT DB_CONSUME DB_CONSUME_WAIT
-              DB_CREATE DB_CURLSN DB_CURRENT DB_CXX_NO_EXCEPTIONS DB_DELETED
-              DB_DELIMITER DB_DIRTY_READ DB_DONOTINDEX DB_DUP DB_DUPCURSOR
-              DB_DUPSORT DB_ENV_APPINIT DB_ENV_CDB DB_ENV_CDB_ALLDB
-              DB_ENV_CREATE DB_ENV_DBLOCAL DB_ENV_LOCKDOWN DB_ENV_LOCKING
+              DB_AUTO_COMMIT DB_BEFORE DB_BROADCAST_EID DB_BTREEMAGIC
+              DB_BTREEOLDVER DB_BTREEVERSION DB_CACHED_COUNTS DB_CDB_ALLDB
+              DB_CHECKPOINT DB_CHKSUM_SHA1 DB_CLIENT DB_CL_WRITER DB_COMMIT
+              DB_CONSUME DB_CONSUME_WAIT DB_CREATE DB_CURLSN DB_CURRENT
+              DB_CXX_NO_EXCEPTIONS DB_DELETED DB_DELIMITER DB_DIRECT
+              DB_DIRECT_DB DB_DIRECT_LOG DB_DIRTY_READ DB_DONOTINDEX DB_DUP
+              DB_DUPCURSOR DB_DUPSORT DB_EID_BROADCAST DB_EID_INVALID
+              DB_ENCRYPT DB_ENCRYPT_AES DB_ENV_APPINIT DB_ENV_CDB
+              DB_ENV_CDB_ALLDB DB_ENV_CREATE DB_ENV_DBLOCAL DB_ENV_DIRECT_DB
+              DB_ENV_DIRECT_LOG DB_ENV_FATAL DB_ENV_LOCKDOWN DB_ENV_LOCKING
               DB_ENV_LOGGING DB_ENV_NOLOCKING DB_ENV_NOMMAP DB_ENV_NOPANIC
-              DB_ENV_OPEN_CALLED DB_ENV_PANIC_OK DB_ENV_PRIVATE
-              DB_ENV_REGION_INIT DB_ENV_REP_CLIENT DB_ENV_REP_LOGSONLY
-              DB_ENV_REP_MASTER DB_ENV_RPCCLIENT DB_ENV_RPCCLIENT_GIVEN
-              DB_ENV_STANDALONE DB_ENV_SYSTEM_MEM DB_ENV_THREAD DB_ENV_TXN
-              DB_ENV_TXN_NOSYNC DB_ENV_USER_ALLOC DB_ENV_YIELDCPU DB_EXCL
-              DB_EXTENT DB_FAST_STAT DB_FCNTL_LOCKING DB_FILE_ID_LEN DB_FIRST
-              DB_FIXEDLEN DB_FLUSH DB_FORCE DB_GETREC DB_GET_BOTH DB_GET_BOTHC
-              DB_GET_BOTH_RANGE DB_GET_RECNO DB_HASHMAGIC DB_HASHOLDVER
-              DB_HASHVERSION DB_INCOMPLETE DB_INIT_CDB DB_INIT_LOCK
-              DB_INIT_LOG DB_INIT_MPOOL DB_INIT_TXN DB_INVALID_EID
-              DB_JAVA_CALLBACK DB_JOINENV DB_JOIN_ITEM DB_JOIN_NOSORT
-              DB_KEYEMPTY DB_KEYEXIST DB_KEYFIRST DB_KEYLAST DB_LAST
-              DB_LOCKDOWN DB_LOCKMAGIC DB_LOCKVERSION DB_LOCK_CONFLICT
+              DB_ENV_OPEN_CALLED DB_ENV_OVERWRITE DB_ENV_PANIC_OK
+              DB_ENV_PRIVATE DB_ENV_REGION_INIT DB_ENV_REP_CLIENT
+              DB_ENV_REP_LOGSONLY DB_ENV_REP_MASTER DB_ENV_RPCCLIENT
+              DB_ENV_RPCCLIENT_GIVEN DB_ENV_STANDALONE DB_ENV_SYSTEM_MEM
+              DB_ENV_THREAD DB_ENV_TXN DB_ENV_TXN_NOSYNC
+              DB_ENV_TXN_WRITE_NOSYNC DB_ENV_USER_ALLOC DB_ENV_YIELDCPU
+              DB_EXCL DB_EXTENT DB_FAST_STAT DB_FCNTL_LOCKING DB_FILE_ID_LEN
+              DB_FIRST DB_FIXEDLEN DB_FLUSH DB_FORCE DB_GETREC DB_GET_BOTH
+              DB_GET_BOTHC DB_GET_BOTH_RANGE DB_GET_RECNO DB_HANDLE_LOCK
+              DB_HASHMAGIC DB_HASHOLDVER DB_HASHVERSION DB_INCOMPLETE
+              DB_INIT_CDB DB_INIT_LOCK DB_INIT_LOG DB_INIT_MPOOL DB_INIT_TXN
+              DB_INVALID_EID DB_JAVA_CALLBACK DB_JOINENV DB_JOIN_ITEM
+              DB_JOIN_NOSORT DB_KEYEMPTY DB_KEYEXIST DB_KEYFIRST DB_KEYLAST
+              DB_LAST DB_LOCKDOWN DB_LOCKMAGIC DB_LOCKVERSION DB_LOCK_CONFLICT
               DB_LOCK_DEADLOCK DB_LOCK_DEFAULT DB_LOCK_EXPIRE
               DB_LOCK_FREE_LOCKER DB_LOCK_MAXLOCKS DB_LOCK_MINLOCKS
-              DB_LOCK_MINWRITE DB_LOCK_NORUN DB_LOCK_NOTGRANTED
-              DB_LOCK_NOTHELD DB_LOCK_NOWAIT DB_LOCK_OLDEST DB_LOCK_RANDOM
-              DB_LOCK_RECORD DB_LOCK_RIW_N DB_LOCK_RW_N DB_LOCK_SET_TIMEOUT
-              DB_LOCK_SWITCH DB_LOCK_UPGRADE DB_LOCK_YOUNGEST DB_LOGC_BUF_SIZE
-              DB_LOGFILEID_INVALID DB_LOGMAGIC DB_LOGOLDVER DB_LOGVERSION
-              DB_LOG_DISK DB_LOG_LOCKED DB_LOG_SILENT_ERR DB_MAX_PAGES
-              DB_MAX_RECORDS DB_MPOOL_CLEAN DB_MPOOL_CREATE DB_MPOOL_DIRTY
-              DB_MPOOL_DISCARD DB_MPOOL_EXTENT DB_MPOOL_LAST DB_MPOOL_NEW
-              DB_MPOOL_NEW_GROUP DB_MPOOL_PRIVATE DB_MULTIPLE DB_MULTIPLE_KEY
-              DB_MUTEXDEBUG DB_MUTEXLOCKS DB_NEEDSPLIT DB_NEXT DB_NEXT_DUP
-              DB_NEXT_NODUP DB_NODUPDATA DB_NOLOCKING DB_NOMMAP DB_NOORDERCHK
-              DB_NOOVERWRITE DB_NOPANIC DB_NORECURSE DB_NOSERVER
-              DB_NOSERVER_HOME DB_NOSERVER_ID DB_NOSYNC DB_NOTFOUND
-              DB_ODDFILESIZE DB_OK_BTREE DB_OK_HASH DB_OK_QUEUE DB_OK_RECNO
-              DB_OLD_VERSION DB_OPEN_CALLED DB_OPFLAGS_MASK DB_ORDERCHKONLY
-              DB_PAD DB_PAGEYIELD DB_PAGE_LOCK DB_PAGE_NOTFOUND
-              DB_PANIC_ENVIRONMENT DB_POSITION DB_POSITIONI DB_PREV
-              DB_PREV_NODUP DB_PRIVATE DB_PR_HEADERS DB_PR_PAGE
-              DB_PR_RECOVERYTEST DB_QAMMAGIC DB_QAMOLDVER DB_QAMVERSION
-              DB_RDONLY DB_RDWRMASTER DB_RECNUM DB_RECORDCOUNT DB_RECORD_LOCK
-              DB_RECOVER DB_RECOVER_FATAL DB_REGION_ANON DB_REGION_INIT
-              DB_REGION_MAGIC DB_REGION_NAME DB_REGISTERED DB_RENUMBER
+              DB_LOCK_MINWRITE DB_LOCK_NORUN DB_LOCK_NOTEXIST
+              DB_LOCK_NOTGRANTED DB_LOCK_NOTHELD DB_LOCK_NOWAIT DB_LOCK_OLDEST
+              DB_LOCK_RANDOM DB_LOCK_RECORD DB_LOCK_REMOVE DB_LOCK_RIW_N
+              DB_LOCK_RW_N DB_LOCK_SET_TIMEOUT DB_LOCK_SWITCH DB_LOCK_UPGRADE
+              DB_LOCK_YOUNGEST DB_LOGC_BUF_SIZE DB_LOGFILEID_INVALID
+              DB_LOGMAGIC DB_LOGOLDVER DB_LOGVERSION DB_LOG_DISK DB_LOG_LOCKED
+              DB_LOG_SILENT_ERR DB_MAX_PAGES DB_MAX_RECORDS DB_MPOOL_CLEAN
+              DB_MPOOL_CREATE DB_MPOOL_DIRTY DB_MPOOL_DISCARD DB_MPOOL_EXTENT
+              DB_MPOOL_LAST DB_MPOOL_NEW DB_MPOOL_NEW_GROUP DB_MPOOL_PRIVATE
+              DB_MULTIPLE DB_MULTIPLE_KEY DB_MUTEXDEBUG DB_MUTEXLOCKS
+              DB_NEEDSPLIT DB_NEXT DB_NEXT_DUP DB_NEXT_NODUP DB_NOCOPY
+              DB_NODUPDATA DB_NOLOCKING DB_NOMMAP DB_NOORDERCHK DB_NOOVERWRITE
+              DB_NOPANIC DB_NORECURSE DB_NOSERVER DB_NOSERVER_HOME
+              DB_NOSERVER_ID DB_NOSYNC DB_NOTFOUND DB_ODDFILESIZE DB_OK_BTREE
+              DB_OK_HASH DB_OK_QUEUE DB_OK_RECNO DB_OLD_VERSION DB_OPEN_CALLED
+              DB_OPFLAGS_MASK DB_ORDERCHKONLY DB_OVERWRITE DB_PAD DB_PAGEYIELD
+              DB_PAGE_LOCK DB_PAGE_NOTFOUND DB_PANIC_ENVIRONMENT DB_PERMANENT
+              DB_POSITION DB_POSITIONI DB_PREV DB_PREV_NODUP DB_PRINTABLE
+              DB_PRIVATE DB_PR_HEADERS DB_PR_PAGE DB_PR_RECOVERYTEST
+              DB_QAMMAGIC DB_QAMOLDVER DB_QAMVERSION DB_RDONLY DB_RDWRMASTER
+              DB_RECNUM DB_RECORDCOUNT DB_RECORD_LOCK DB_RECOVER
+              DB_RECOVER_FATAL DB_REGION_ANON DB_REGION_INIT DB_REGION_MAGIC
+              DB_REGION_NAME DB_REGISTERED DB_RENAMEMAGIC DB_RENUMBER
               DB_REP_CLIENT DB_REP_DUPMASTER DB_REP_HOLDELECTION
               DB_REP_LOGSONLY DB_REP_MASTER DB_REP_NEWMASTER DB_REP_NEWSITE
               DB_REP_OUTDATED DB_REP_PERMANENT DB_REP_UNAVAIL DB_REVSPLITOFF
@@ -3428,17 +3814,19 @@ my @names = (qw(DB_AFTER DB_AGGRESSIVE DB_ALREADY_ABORTED DB_APPEND
               DB_TEST_POSTLOG DB_TEST_POSTLOGMETA DB_TEST_POSTOPEN
               DB_TEST_POSTRENAME DB_TEST_POSTSYNC DB_TEST_PREDESTROY
               DB_TEST_PREEXTDELETE DB_TEST_PREEXTOPEN DB_TEST_PREEXTUNLINK
-              DB_TEST_PREOPEN DB_TEST_PRERENAME DB_THREAD DB_TIMEOUT
-              DB_TRUNCATE DB_TXNMAGIC DB_TXNVERSION DB_TXN_CKP DB_TXN_LOCK_2PL
-              DB_TXN_LOCK_MASK DB_TXN_LOCK_OPTIMIST DB_TXN_LOCK_OPTIMISTIC
-              DB_TXN_LOG_MASK DB_TXN_LOG_REDO DB_TXN_LOG_UNDO
-              DB_TXN_LOG_UNDOREDO DB_TXN_NOSYNC DB_TXN_NOWAIT DB_TXN_REDO
-              DB_TXN_SYNC DB_TXN_UNDO DB_UNRESOLVED_CHILD DB_UPDATE_SECONDARY
+              DB_TEST_PREOPEN DB_TEST_PRERENAME DB_TEST_SUBDB_LOCKS DB_THREAD
+              DB_TIMEOUT DB_TRUNCATE DB_TXNMAGIC DB_TXNVERSION DB_TXN_CKP
+              DB_TXN_LOCK DB_TXN_LOCK_2PL DB_TXN_LOCK_MASK
+              DB_TXN_LOCK_OPTIMIST DB_TXN_LOCK_OPTIMISTIC DB_TXN_LOG_MASK
+              DB_TXN_LOG_REDO DB_TXN_LOG_UNDO DB_TXN_LOG_UNDOREDO
+              DB_TXN_NOSYNC DB_TXN_NOWAIT DB_TXN_REDO DB_TXN_SYNC DB_TXN_UNDO
+              DB_TXN_WRITE_NOSYNC DB_UNRESOLVED_CHILD DB_UPDATE_SECONDARY
               DB_UPGRADE DB_USE_ENVIRON DB_USE_ENVIRON_ROOT DB_VERB_CHKPOINT
-              DB_VERB_DEADLOCK DB_VERB_RECOVERY DB_VERB_WAITSFOR DB_VERIFY
-              DB_VERIFY_BAD DB_VERIFY_FATAL DB_VERSION_MAJOR DB_VERSION_MINOR
-              DB_VERSION_PATCH DB_VRFY_FLAGMASK DB_WRITECURSOR DB_WRITELOCK
-              DB_XA_CREATE DB_XIDDATASIZE DB_YIELDCPU),
+              DB_VERB_DEADLOCK DB_VERB_RECOVERY DB_VERB_REPLICATION
+              DB_VERB_WAITSFOR DB_VERIFY DB_VERIFY_BAD DB_VERIFY_FATAL
+              DB_VERSION_MAJOR DB_VERSION_MINOR DB_VERSION_PATCH
+              DB_VRFY_FLAGMASK DB_WRITECURSOR DB_WRITELOCK DB_WRITEOPEN
+              DB_WRNOSYNC DB_XA_CREATE DB_XIDDATASIZE DB_YIELDCPU),
             {name=>"DB_BTREE", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
             {name=>"DB_HASH", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
             {name=>"DB_LOCK_DUMP", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
@@ -3450,15 +3838,23 @@ my @names = (qw(DB_AFTER DB_AGGRESSIVE DB_ALREADY_ABORTED DB_APPEND
             {name=>"DB_LOCK_PUT_OBJ", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
             {name=>"DB_LOCK_PUT_READ", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 7)\n", "#endif\n"]},
             {name=>"DB_LOCK_TIMEOUT", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 7)\n", "#endif\n"]},
+            {name=>"DB_LOCK_TRADE", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_LOCK_UPGRADE_WRITE", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && \\\n     DB_VERSION_PATCH >= 4)\n", "#endif\n"]},
+            {name=>"DB_PRIORITY_DEFAULT", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
+            {name=>"DB_PRIORITY_HIGH", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
+            {name=>"DB_PRIORITY_LOW", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
+            {name=>"DB_PRIORITY_VERY_HIGH", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
+            {name=>"DB_PRIORITY_VERY_LOW", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_QUEUE", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 55)\n", "#endif\n"]},
             {name=>"DB_RECNO", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
             {name=>"DB_TXN_ABORT", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_TXN_APPLY", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 7)\n", "#endif\n"]},
             {name=>"DB_TXN_BACKWARD_ROLL", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_TXN_FORWARD_ROLL", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
+            {name=>"DB_TXN_GETPGNOS", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_TXN_OPENFILES", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_TXN_POPENFILES", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 3) || \\\n    (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && \\\n     DB_VERSION_PATCH >= 4)\n", "#endif\n"]},
+            {name=>"DB_TXN_PRINT", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 4) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 1) || \\\n    (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR == 1 && \\\n     DB_VERSION_PATCH >= 12)\n", "#endif\n"]},
             {name=>"DB_UNKNOWN", type=>"IV", macro=>["#if (DB_VERSION_MAJOR > 2) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR > 0) || \\\n    (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR == 0 && \\\n     DB_VERSION_PATCH >= 0)\n", "#endif\n"]},
             {name=>"DB_VERSION_STRING", type=>"PV"});
 
@@ -3549,6 +3945,16 @@ __END__
       break;
     }
     break;
+  case 23:
+    if (memEQ(name, "DB_ENV_TXN_WRITE_NOSYNC", 23)) {
+#ifdef DB_ENV_TXN_WRITE_NOSYNC
+      *iv_return = DB_ENV_TXN_WRITE_NOSYNC;
+      return PERL_constant_ISIV;
+#else
+      return PERL_constant_NOTDEF;
+#endif
+    }
+    break;
   }
   return PERL_constant_NOTFOUND;
 }
index 415411a..af2c45f 100755 (executable)
@@ -7,7 +7,7 @@
 # Version:     1.03 
 # Date         17th September 2000
 #
-#     Copyright (c) 1998-2001 Paul Marquess. All rights reserved.
+#     Copyright (c) 1998-2002 Paul Marquess. All rights reserved.
 #     This program is free software; you can redistribute it and/or
 #     modify it under the same terms as Perl itself.
 
@@ -29,7 +29,8 @@ my %Data =
                                  5     => "2.0.0 -> 2.3.0",
                                  6     => "2.3.1 -> 2.7.7",
                                  7     => "3.0.x",
-                                 8     => "3.1.x or greater",
+                                 8     => "3.1.x -> 4.0.x",
+                                 9     => "4.1.x or greater",
                                }
                        },
        0x061561 =>     {
@@ -42,7 +43,8 @@ my %Data =
                                  4     => "2.0.0 -> 2.1.0",
                                  5     => "2.2.6 -> 2.7.7",
                                  6     => "3.0.x",
-                                 7     => "3.1.x or greater",
+                                 7     => "3.1.x -> 4.0.x",
+                                 8     => "4.1.x or greater",
                                }
                        },
        0x042253 =>     {
@@ -51,7 +53,8 @@ my %Data =
                                {
                                  1     => "3.0.x",
                                  2     => "3.1.x",
-                                 3     => "3.2.x or greater",
+                                 3     => "3.2.x -> 4.0.x",
+                                 4     => "4.1.x or greater",
                                }
                        },
        ) ;
index dc90ea9..8f19466 100644 (file)
@@ -597,6 +597,78 @@ use constant IGNORE => 'ignore' ;
        # enum db_status_t
        DB_LSTAT_EXPIRED           => IGNORE, # 4.0.7
 
+       #########
+       # 4.0.14
+       #########
+
+       DB_EID_BROADCAST           => DEFINE,
+       DB_EID_INVALID             => DEFINE,
+       DB_VERB_REPLICATION        => DEFINE,
+
+       #########
+       # 4.1.12
+       #########
+
+       DBC_OWN_LID                => IGNORE,
+       DB_AM_CHKSUM               => IGNORE,
+       DB_AM_CL_WRITER            => IGNORE,
+       DB_AM_COMPENSATE           => IGNORE,
+       DB_AM_CREATED              => IGNORE,
+       DB_AM_CREATED_MSTR         => IGNORE,
+       DB_AM_DBM_ERROR            => IGNORE,
+       DB_AM_DELIMITER            => IGNORE,
+       DB_AM_ENCRYPT              => IGNORE,
+       DB_AM_FIXEDLEN             => IGNORE,
+       DB_AM_IN_RENAME            => IGNORE,
+       DB_AM_OPEN_CALLED          => IGNORE,
+       DB_AM_PAD                  => IGNORE,
+       DB_AM_RECNUM               => IGNORE,
+       DB_AM_RENUMBER             => IGNORE,
+       DB_AM_REVSPLITOFF          => IGNORE,
+       DB_AM_SNAPSHOT             => IGNORE,
+       DB_AUTO_COMMIT             => DEFINE,
+       DB_CHKSUM_SHA1             => DEFINE,
+       DB_DIRECT                  => DEFINE,
+       DB_DIRECT_DB               => DEFINE,
+       DB_DIRECT_LOG              => DEFINE,
+       DB_ENCRYPT                 => DEFINE,
+       DB_ENCRYPT_AES             => DEFINE,
+       DB_ENV_DIRECT_DB           => DEFINE,
+       DB_ENV_DIRECT_LOG          => DEFINE,
+       DB_ENV_FATAL               => DEFINE,
+       DB_ENV_OVERWRITE           => DEFINE,
+       DB_ENV_TXN_WRITE_NOSYNC    => DEFINE,
+       DB_HANDLE_LOCK             => DEFINE,
+       DB_LOCK_NOTEXIST           => DEFINE,
+       DB_LOCK_REMOVE             => DEFINE,
+       DB_NOCOPY                  => DEFINE,
+       DB_OVERWRITE               => DEFINE,
+       DB_PERMANENT               => DEFINE,
+       DB_PRINTABLE               => DEFINE,
+       DB_RENAMEMAGIC             => DEFINE,
+       DB_TEST_SUBDB_LOCKS        => DEFINE,
+       DB_TXN_LOCK                => DEFINE,
+       DB_TXN_WRITE_NOSYNC        => DEFINE,
+       DB_WRITEOPEN               => DEFINE,
+       DB_WRNOSYNC                => DEFINE,
+       _DB_EXT_PROT_IN_           => IGNORE,
+
+       # enum db_lockop_t
+       DB_LOCK_TRADE              => '4.1.12',
+
+       # enum db_status_t
+       DB_LSTAT_NOTEXIST          => IGNORE, # 4.1.12
+
+       # enum DB_CACHE_PRIORITY
+       DB_PRIORITY_VERY_LOW       => '4.1.12',
+       DB_PRIORITY_LOW            => '4.1.12',
+       DB_PRIORITY_DEFAULT        => '4.1.12',
+       DB_PRIORITY_HIGH           => '4.1.12',
+       DB_PRIORITY_VERY_HIGH      => '4.1.12',
+
+       # enum db_recops
+       DB_TXN_GETPGNOS            => '4.1.12',
+       DB_TXN_PRINT               => '4.1.12',
        ) ;
 
 sub enum_Macro
@@ -632,6 +704,7 @@ sub OutputXS
           { push @names, { name => $key, macro => [enum_Macro($val), "#endif\n"] } }
     }
 
+    warn "Updating constants.xs & constants.h...\n";
     WriteConstants(
               NAME    => BerkeleyDB,
               NAMES   => \@names,
@@ -642,37 +715,47 @@ sub OutputXS
 
 sub OutputPM
 {
+    my $filename = 'BerkeleyDB.pm';
+    warn "Updating $filename...\n";
+    open IN, "<$filename" || die "Cannot open $filename: $!\n";
+    open OUT, ">$filename.tmp" || die "Cannot open $filename.tmp: $!\n";
+
     my $START = '@EXPORT = qw(' ;
     my $START_re = quotemeta $START ;
     my $END = ');';
     my $END_re = quotemeta $END ;
 
     # skip to the @EXPORT declaration
-    OUTER: while (<>)
+    OUTER: while (<IN>)
     {
         if ( /^\s*$START_re/ )
         {
             # skip to the end marker.
-            while (<>) 
+            while (<IN>) 
                 { last OUTER if /^\s*$END_re/ }
         }
-        print ;
+        print OUT ;
     }
     
-    print "$START\n";
+    print OUT "$START\n";
     foreach my $key (sort keys %constants)
     {
         next if $constants{$key} eq IGNORE;
-       print "\t$key\n";
+       print OUT "\t$key\n";
     }
-    print "\t$END\n";
+    print OUT "\t$END\n";
     
-    while (<>)
+    while (<IN>)
     {
-        print ;
+        print OUT ;
     }
+
+    close IN;
+    close OUT;
+
+    rename $filename, "$filename.bak" || die "Cannot rename $filename: $!\n" ;
+    rename "$filename.tmp", $filename || die "Cannot rename $filename.tmp: $!\n" ;
 }
 
-my $opt = shift ;
-OutputXS() if $opt =~ /^xs/i ;
-OutputPM() if $opt =~ /^pm/i ;
+OutputXS() ;
+OutputPM() ;
index b0068fe..0922227 100644 (file)
 
    * Added "clean" attribute to Makefile.PL
  
+1.802 6th January 2002
+
+   * The message about some test failing in db-recno.t had the wrong test
+     numbers. Fixed.
+
+   * merged core patch 13942.
+
+1.803 1st March 2002
+
+   * Fixed a problem with db-btree.t where it complained about an "our"
+     variable redeclaation.
+
+   * FETCH, STORE & DELETE don't map the flags parameter into the
+     equivalent Berkeley DB function anymore.
+
+1.804 2nd June 2002
+
+   * Perl core patch 14939 added a new warning to "splice". This broke the
+     db-recno test harness. Fixed.
+
+   * merged core patches 16502 & 16540.
index b83877f..ff3c059 100644 (file)
@@ -1,10 +1,10 @@
 # DB_File.pm -- Perl 5 interface to Berkeley DB 
 #
 # written by Paul Marquess (Paul.Marquess@btinternet.com)
-# last modified 26th Nov 2001
-# version 1.801
+# last modified 2nd June 2002
+# version 1.804
 #
-#     Copyright (c) 1995-2001 Paul Marquess. All rights reserved.
+#     Copyright (c) 1995-2002 Paul Marquess. All rights reserved.
 #     This program is free software; you can redistribute it and/or
 #     modify it under the same terms as Perl itself.
 
@@ -146,11 +146,18 @@ package DB_File ;
 use warnings;
 use strict;
 our ($VERSION, @ISA, @EXPORT, $AUTOLOAD, $DB_BTREE, $DB_HASH, $DB_RECNO);
-our ($db_version, $use_XSLoader);
+our ($db_version, $use_XSLoader, $splice_end_array);
 use Carp;
 
 
-$VERSION = "1.801" ;
+$VERSION = "1.804" ;
+
+{
+    local $SIG{__WARN__} = sub {$splice_end_array = "@_";};
+    my @a =(1); splice(@a, 3);
+    $splice_end_array = 
+        ($splice_end_array =~ /^splice\(\) offset past end of array at /);
+}      
 
 #typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
 $DB_BTREE = new DB_File::BTREEINFO ;
@@ -303,7 +310,7 @@ sub SPLICE
     my $self = shift;
     my $offset = shift;
     if (not defined $offset) {
-       carp 'Use of uninitialized value in splice';
+       warnings::warnif('uninitialized', 'Use of uninitialized value in splice');
        $offset = 0;
     }
 
@@ -328,15 +335,17 @@ sub SPLICE
        $offset = $new_offset;
     }
 
-    if ($offset > $size) {
-       $offset = $size;
-    }
-
     if (not defined $length) {
-       carp 'Use of uninitialized value in splice';
+       warnings::warnif('uninitialized', 'Use of uninitialized value in splice');
        $length = 0;
     }
 
+    if ($offset > $size) {
+       $offset = $size;
+       warnings::warnif('misc', 'splice() offset past end of array')
+            if $splice_end_array;
+    }
+
     # 'If LENGTH is omitted, removes everything from OFFSET onward.'
     if (not defined $length) {
        $length = $size - $offset;
@@ -978,7 +987,7 @@ code:
     use strict ;
     use DB_File ;
 
-    our ($filename, %h) ;
+    my ($filename, %h) ;
 
     $filename = "tree" ;
     unlink $filename ;
@@ -1033,7 +1042,7 @@ Here is the script above rewritten using the C<seq> API method.
     use strict ;
     use DB_File ;
 
-    our ($filename, $x, %h, $status, $key, $value) ;
+    my ($filename, $x, %h, $status, $key, $value) ;
 
     $filename = "tree" ;
     unlink $filename ;
@@ -1105,7 +1114,7 @@ this:
     use strict ;
     use DB_File ;
 
-    our ($filename, $x, %h) ;
+    my ($filename, $x, %h) ;
 
     $filename = "tree" ;
 
@@ -1155,7 +1164,7 @@ Assuming the database from the previous example:
     use strict ;
     use DB_File ;
 
-    our ($filename, $x, %h, $found) ;
+    my ($filename, $x, %h, $found) ;
 
     $filename = "tree" ;
 
@@ -1194,7 +1203,7 @@ Again assuming the existence of the C<tree> database
     use strict ;
     use DB_File ;
 
-    our ($filename, $x, %h, $found) ;
+    my ($filename, $x, %h, $found) ;
 
     $filename = "tree" ;
 
@@ -1240,7 +1249,7 @@ and print the first matching key/value pair given a partial key.
     use DB_File ;
     use Fcntl ;
 
-    our ($filename, $x, %h, $st, $key, $value) ;
+    my ($filename, $x, %h, $st, $key, $value) ;
 
     sub match
     {
@@ -1439,7 +1448,7 @@ L<THE API INTERFACE>).
 
     use warnings ;
     use strict ;
-    our (@h, $H, $file, $i) ;
+    my (@h, $H, $file, $i) ;
     use DB_File ;
     use Fcntl ;
 
@@ -2004,7 +2013,7 @@ F<authors/id/TOMC/scripts/nshist.gz>).
     use DB_File ;
     use Fcntl ;
 
-    our ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ;
+    my ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ;
     $dotdir = $ENV{HOME} || $ENV{LOGNAME};
 
     $HISTORY = "$dotdir/.netscape/history.db";
@@ -2225,7 +2234,7 @@ compile properly on IRIX 5.3.
 
 =head1 COPYRIGHT
 
-Copyright (c) 1995-2001 Paul Marquess. All rights reserved. This program
+Copyright (c) 1995-2002 Paul Marquess. All rights reserved. This program
 is free software; you can redistribute it and/or modify it under the
 same terms as Perl itself.
 
index c788b98..6882491 100644 (file)
@@ -3,12 +3,12 @@
  DB_File.xs -- Perl 5 interface to Berkeley DB 
 
  written by Paul Marquess <Paul.Marquess@btinternet.com>
- last modified 26th Nov 2001
- version 1.801
+ last modified 2nd June 2002
+ version 1.804
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1995-2001 Paul Marquess. All rights reserved.
+     Copyright (c) 1995-2002 Paul Marquess. All rights reserved.
      This program is free software; you can redistribute it and/or
      modify it under the same terms as Perl itself.
 
@@ -98,7 +98,9 @@
         1.800 - Moved backward compatability code into ppport.h.
                 Use the new constants code.
         1.801 - No change to DB_File.xs
-
+        1.802 - No change to DB_File.xs
+        1.803 - FETCH, STORE & DELETE don't map the flags parameter
+                into the equivalent Berkeley DB function anymore.
 */
 
 #define PERL_NO_GET_CONTEXT
 #    undef __attribute__
 #endif
 
-
-
 #ifdef COMPAT185
 #    include <db_185.h>
 #else
@@ -326,9 +326,9 @@ typedef union INFO {
 
 
 
-#define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, flags)
-#define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, flags)
-#define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
+#define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, 0)
+#define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, 0)
+#define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, 0)
 
 #define db_sync(db, flags)              ((db->dbp)->sync)(db->dbp, flags)
 #define db_get(db, key, value, flags)   ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
index 7f45372..d38a42e 100644 (file)
@@ -41,7 +41,7 @@ $OS2 = "-DOS2" if $Config{'osname'} eq 'os2' ;
 WriteMakefile(
        NAME            => 'DB_File',
        LIBS            => ["-L${LIB_DIR} $LIBS"],
-        MAN3PODS        => ' ',         # Pods will be built by installman.
+        MAN3PODS        => {},         # Pods will be built by installman.
        INC             => "-I$INC_DIR",
        VERSION_FROM    => 'DB_File.pm',
        XSPROTOARG      => '-noprototypes',
@@ -254,16 +254,29 @@ sub UpDowngrade
     if ($] < 5.006001) {
         # From: use|no warnings "blah"
         # To:   local ($^W) = 1; # use|no warnings "blah"
+        #
+        # and
+        #
+        # From: warnings::warnif(x,y);
+        # To:   $^W && carp(y); # warnif -- x
         $warn_sub = sub {
            s/^(\s*)(no\s+warnings)/${1}local (\$^W) = 0; #$2/ ;
            s/^(\s*)(use\s+warnings)/${1}local (\$^W) = 1; #$2/ ;
+
+           s/^(\s*)warnings::warnif\s*\((.*?)\s*,\s*(.*?)\)\s*;/${1}\$^W && carp($3); # warnif - $2/ ;
           };
     }
     else {
         # From: local ($^W) = 1; # use|no warnings "blah"
         # To:   use|no warnings "blah"
+        #
+        # and
+        #
+        # From: $^W && carp(y); # warnif -- x
+        # To:   warnings::warnif(x,y);
         $warn_sub = sub {
            s/^(\s*)local\s*\(\$\^W\)\s*=\s*\d+\s*;\s*#\s*((no|use)\s+warnings.*)/$1$2/ ;
+           s/^(\s*)\$\^W\s+\&\&\s*carp\s*\((.*?)\)\s*;\s*#\s*warnif\s*-\s*(.*)/${1}warnings::warnif($3, $2);/ ;
           };
     }
 
index b3eaf26..1505f73 100644 (file)
@@ -1,10 +1,10 @@
                                      DB_File
 
-                                  Version 1.801
+                                  Version 1.804
 
-                                  26th Nov 2001
+                                  2nd June 2002
 
-       Copyright (c) 1995-2001 Paul Marquess. All rights reserved. This
+       Copyright (c) 1995-2002 Paul Marquess. All rights reserved. This
        program is free software; you can redistribute it and/or modify
        it under the same terms as Perl itself.
 
@@ -22,7 +22,7 @@ DESCRIPTION
 
 DB_File is a module which allows Perl programs to make use of the
 facilities provided by Berkeley DB version 1. (DB_File can be built
-version 2,i 3 or 4 of Berkeley DB, but it will only support the 1.x
+version 2, 3 or 4 of Berkeley DB, but it will only support the 1.x
 features),
 
 If you want to make use of the new features available in Berkeley DB
@@ -298,8 +298,8 @@ To find out if you have the patch installed, the command "showrev -p"
 will display the patches that are currently installed on your system.
 
 
-HP-UX Notes
------------
+HP-UX 10 Notes
+--------------
 
 Some people running HP-UX 10 have reported getting an error like this
 when building DB_File with the native HP-UX compiler.
@@ -324,6 +324,22 @@ following steps should do the trick:
 
   3: Build and install the Berkeley DB distribution as usual.
 
+HP-UX 11 Notes
+--------------
+
+Some people running the combination of HP-UX 11 and Berkeley DB 2.7.7 have
+reported getting this error when the run the test harness for DB_File
+
+    ...
+    lib/db-btree.........Can't call method "DELETE" on an undefined value at lib/db-btree.t line 216.
+    FAILED at test 26
+    lib/db-hash..........Can't call method "DELETE" on an undefined value at lib/db-hash.t line 183.
+    FAILED at test 22
+    ...
+
+The fix for this is to rebuild and install Berkeley DB with the bigfile
+option disabled.
+
 
 IRIX NOTES
 ----------
@@ -338,21 +354,23 @@ FEEDBACK
 
 How to report a problem with DB_File.
 
-To help me help you, I need the following information:
+When reporting any problem, I need the information requested below. 
+
+ 1. The *complete* output from running this
 
- 1. The version of Perl and the operating system name and version you
-    are running. The *complete* output from running "perl -V" will
-    tell me all I need to know. Don't edit the output in any way. Note,
-    I want you to run "perl -V" and NOT "perl -v".
+        perl -V
 
-    If your perl does not understand the "-V" option it is too old. DB_File
-    needs Perl version 5.004 or better.
+    Do not edit the output in any way. 
+    Note, I want you to run "perl -V" and NOT "perl -v".
+
+    If your perl does not understand the "-V" option it is too
+    old. DB_File needs Perl version 5.00405 or better.
 
  2. The version of DB_File you have.
     If you have successfully installed DB_File, this one-liner will
     tell you:
 
-       perl -e 'use DB_File; print "DB_File ver $DB_File::VERSION\n"'
+       perl -e 'use DB_File; print qq{DB_File ver $DB_File::VERSION\n}'
 
     If you haven't installed DB_File then search DB_File.pm for a line
     like this:
@@ -367,12 +385,27 @@ To help me help you, I need the following information:
     If you have successfully installed DB_File, this command will display
     the version of Berkeley DB it was built with:
 
-       perl -e 'use DB_File; print "Berkeley DB ver $DB_File::db_ver\n"'
+       perl -e 'use DB_File; print qq{Berkeley DB ver $DB_File::db_ver\n}'
+
+ 4. A copy the file config.in from the DB_File main source directory.
+
+ 5. A listing of directories where Berkeley DB is installed.
+    For example, if Berkeley DB is installed in /usr/BerkeleDB/lib and
+    /usr/BerkeleyDB/include, I need the output from running this
+
+        ls -l /usr/BerkeleyDB/lib
+        ls -l /usr/BerkeleyDB/include
+
+ 6. If you are having problems building DB_File, send me a complete log
+    of what happened. Start by unpacking the DB_File module into a fresh
+    directory and keep a log of all the steps
 
- 4. If you are having problems building DB_File, send me a complete log
-    of what happened.
+        [edit config.in, if necessary]
+        perl Makefile.PL
+        make 
+        make test TEST_VERBOSE=1
 
5. Now the difficult one. If you think you have found a bug in DB_File
7. Now the difficult one. If you think you have found a bug in DB_File
     and you want me to fix it, you will *greatly* enhance the chances
     of me being able to track it down by sending me a small
     self-contained Perl script that illustrates the problem you are
index dfd46bc..127b810 100644 (file)
@@ -12,7 +12,8 @@
 INCLUDE        = /usr/local/BerkeleyDB/include
 #INCLUDE       = /usr/local/include
 #INCLUDE       = /usr/include
-#INCLUDE       = ./libraries/3.2.9
+#INCLUDE       = ./libraries/4.0.14/include
+#INCLUDE       = ./libraries/2.7.7/include
 
 # 2. Where is libdb?
 #
@@ -22,7 +23,8 @@ INCLUDE       = /usr/local/BerkeleyDB/include
 LIB    = /usr/local/BerkeleyDB/lib
 #LIB   = /usr/local/lib
 #LIB   = /usr/lib
-#LIB   = ./libraries/3.2.9
+#LIB   = ./libraries/4.0.14/lib
+#LIB   = ./libraries/2.7.7/lib
 
 # 3. What version of Berkely DB have you got?
 #
index 5a4df15..d349d07 100644 (file)
@@ -7,7 +7,7 @@
 # Version:     1.03 
 # Date         17th September 2000
 #
-#     Copyright (c) 1998-2000 Paul Marquess. All rights reserved.
+#     Copyright (c) 1998-2002 Paul Marquess. All rights reserved.
 #     This program is free software; you can redistribute it and/or
 #     modify it under the same terms as Perl itself.
 
index 326b8d9..16ee276 100644 (file)
@@ -1,8 +1,5 @@
 #!./perl -w
 
-use warnings;
-use strict;
-
 BEGIN {
     unless(grep /blib/, @INC) {
         chdir 't' if -d 't';
@@ -10,21 +7,34 @@ BEGIN {
     }
 }
  
+use warnings;
+use strict;
 use Config;
  
 BEGIN {
     if(-d "lib" && -f "TEST") {
         if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
-            print "1..157\n";
+            print "1..0 # Skip: DB_File was not built\n";
             exit 0;
         }
     }
+    if ($^O eq 'darwin'
+       && $Config{db_version_major} == 1
+       && $Config{db_version_minor} == 0
+       && $Config{db_version_patch} == 0) {
+       warn <<EOM;
+#
+# This test is known to crash in Mac OS X versions 10.1.4 (or earlier)
+# because of the buggy Berkeley DB version included with the OS.
+#
+EOM
+    }
 }
 
 use DB_File; 
 use Fcntl;
 
-print "1..157\n";
+print "1..163\n";
 
 sub ok
 {
@@ -75,24 +85,32 @@ sub lexical
 sub docat
 { 
     my $file = shift;
-    #local $/ = undef unless wantarray ;
+    local $/ = undef ;
     open(CAT,$file) || die "Cannot open $file: $!";
-    my @result = <CAT>;
+    my $result = <CAT>;
     close(CAT);
-    wantarray ? @result : join("", @result) ;
+    $result = normalise($result) ;
+    return $result ;
 }   
 
 sub docat_del
 { 
     my $file = shift;
-    #local $/ = undef unless wantarray ;
-    open(CAT,$file) || die "Cannot open $file: $!";
-    my @result = <CAT>;
-    close(CAT);
+    my $result = docat($file);
     unlink $file ;
-    wantarray ? @result : join("", @result) ;
+    return $result ;
 }   
 
+sub normalise
+{
+    my $data = shift ;
+    $data =~ s#\r\n#\n#g 
+        if $^O eq 'cygwin' ;
+
+    return $data ;
+}
+
+
 
 my $db185mode =  ($DB_File::db_version == 1 && ! $DB_File::db_185_compat) ;
 my $null_keys_allowed = ($DB_File::db_ver < 2.004010 
@@ -149,11 +167,15 @@ ok(18, $@ =~ /^DB_File::BTREEINFO::FETCH - Unknown element 'fred' at/ ) ;
 
 my ($X, %h) ;
 ok(19, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE )) ;
+die "Could not tie: $!" unless $X;
 
 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
    $blksize,$blocks) = stat($Dfile);
+
+my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
+
 ok(20, ($mode & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640)
-   || $^O eq 'amigaos' || $^O eq 'MSWin32' || $^O eq 'NetWare');
+   || $noMode{$^O} );
 
 my ($key, $value, $i);
 while (($key,$value) = each(%h)) {
@@ -515,9 +537,9 @@ $dbh3->{compare} = sub { length $_[0] <=> length $_[1] } ;
  
  
 my (%g, %k);
-tie(%h, 'DB_File',$Dfile1, O_RDWR|O_CREAT, 0640, $dbh1 ) 
-tie(%g, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) ;
-tie(%k, 'DB_File',$Dfile3, O_RDWR|O_CREAT, 0640, $dbh3 ) ;
+tie(%h, 'DB_File',$Dfile1, O_RDWR|O_CREAT, 0640, $dbh1 ) or die $!;
+tie(%g, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) or die $!;
+tie(%k, 'DB_File',$Dfile3, O_RDWR|O_CREAT, 0640, $dbh3 ) or die $!;
  
 my @Keys = qw( 0123 12 -1234 9 987654321 def  ) ;
 my (@srt_1, @srt_2, @srt_3);
@@ -609,7 +631,7 @@ unlink $Dfile1 ;
 
    use warnings ;
    use strict ;
-   use vars qw( @ISA @EXPORT) ;
+   our (@ISA, @EXPORT);
 
    require Exporter ;
    use DB_File;
@@ -947,7 +969,7 @@ EOM
     use strict ;
     use DB_File ;
 
-    use vars qw($filename %h ) ;
+    my ($filename, %h);
 
     $filename = "tree" ;
     unlink $filename ;
@@ -999,7 +1021,7 @@ EOM
     use strict ;
     use DB_File ;
  
-    use vars qw($filename $x %h $status $key $value) ;
+    my ($filename, $x, %h, $status, $key, $value);
 
     $filename = "tree" ;
     unlink $filename ;
@@ -1055,7 +1077,7 @@ EOM
     use strict ;
     use DB_File ;
  
-    use vars qw($filename $x %h ) ;
+    my ($filename, $x, %h);
 
     $filename = "tree" ;
  
@@ -1104,9 +1126,9 @@ EOM
     use strict ;
     use DB_File ;
  
-    use vars qw($filename $x %h $found) ;
+    my ($filename, $x, %h, $found);
 
-    my $filename = "tree" ;
+    $filename = "tree" ;
  
     # Enable duplicate records
     $DB_BTREE->{'flags'} = R_DUP ;
@@ -1139,9 +1161,9 @@ EOM
     use strict ;
     use DB_File ;
  
-    use vars qw($filename $x %h $found) ;
+    my ($filename, $x, %h, $found);
 
-    my $filename = "tree" ;
+    $filename = "tree" ;
  
     # Enable duplicate records
     $DB_BTREE->{'flags'} = R_DUP ;
@@ -1175,7 +1197,7 @@ EOM
     use DB_File ;
     use Fcntl ;
 
-    use vars qw($filename $x %h $st $key $value) ;
+    my ($filename, $x, %h, $st, $key, $value);
 
     sub match
     {
@@ -1304,4 +1326,46 @@ EOM
     unlink $Dfile;
 }
 
+{
+    # When iterating over a tied hash using "each", the key passed to FETCH
+    # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
+    # key in FETCH via a filter_fetch_key method we need to check that the
+    # modified key doesn't get passed to NEXTKEY.
+    # Also Test "keys" & "values" while we are at it.
+
+    use warnings ;
+    use strict ;
+    use DB_File ;
+
+    unlink $Dfile;
+    my $bad_key = 0 ;
+    my %h = () ;
+    my $db ;
+    ok(158, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
+    $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_}) ;
+    $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/ ; $_ =~ s/^Alpha_/Beta_/}) ;
+
+    $h{'Alpha_ABC'} = 2 ;
+    $h{'Alpha_DEF'} = 5 ;
+
+    ok(159, $h{'Alpha_ABC'} == 2);
+    ok(160, $h{'Alpha_DEF'} == 5);
+
+    my ($k, $v) = ("","");
+    while (($k, $v) = each %h) {}
+    ok(161, $bad_key == 0);
+
+    $bad_key = 0 ;
+    foreach $k (keys %h) {}
+    ok(162, $bad_key == 0);
+
+    $bad_key = 0 ;
+    foreach $v (values %h) {}
+    ok(163, $bad_key == 0);
+
+    undef $db ;
+    untie %h ;
+    unlink $Dfile;
+}
+
 exit ;
index daf0ea8..931b03c 100644 (file)
@@ -1,8 +1,5 @@
 #!./perl 
 
-use warnings ;
-use strict ;
-
 BEGIN {
     unless(grep /blib/, @INC) {
         chdir 't' if -d 't';
@@ -10,23 +7,23 @@ BEGIN {
     }
 }
  
+use warnings;
+use strict;
 use Config;
  
 BEGIN {
     if(-d "lib" && -f "TEST") {
         if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
-            print "1..111\n";
+            print "1..0 # Skip: DB_File was not built\n";
             exit 0;
         }
     }
 }
 
-use strict;
-use warnings;
 use DB_File; 
 use Fcntl;
 
-print "1..111\n";
+print "1..117\n";
 
 sub ok
 {
@@ -66,10 +63,21 @@ sub docat_del
     open(CAT,$file) || die "Cannot open $file: $!";
     my $result = <CAT>;
     close(CAT);
+    $result = normalise($result) ;
     unlink $file ;
     return $result;
 }   
 
+sub normalise
+{
+    my $data = shift ;
+    $data =~ s#\r\n#\n#g 
+        if $^O eq 'cygwin' ;
+    return $data ;
+}
+
+
+
 my $Dfile = "dbhash.tmp";
 my $null_keys_allowed = ($DB_File::db_ver < 2.004010 
                                || $DB_File::db_ver >= 3.1 );
@@ -117,11 +125,15 @@ ok(14, $@ =~ /^DB_File::HASHINFO::FETCH - Unknown element 'fred' at/ );
 # Now check the interface to HASH
 my ($X, %h);
 ok(15, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
+die "Could not tie: $!" unless $X;
 
 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
    $blksize,$blocks) = stat($Dfile);
+
+my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
+
 ok(16, ($mode & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640) ||
-   $^O eq 'amigaos' || $^O eq 'MSWin32' || $^O eq 'NetWare');
+   $noMode{$^O} );
 
 my ($key, $value, $i);
 while (($key,$value) = each(%h)) {
@@ -396,7 +408,7 @@ untie %h ;
 
    use warnings ;
    use strict ;
-   use vars qw( @ISA @EXPORT) ;
+   our (@ISA, @EXPORT);
 
    require Exporter ;
    use DB_File;
@@ -676,7 +688,7 @@ EOM
     use warnings FATAL => qw(all);
     use strict ;
     use DB_File ;
-    use vars qw( %h $k $v ) ;
+    our (%h, $k, $v);
 
     unlink "fruit" ;
     tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH 
@@ -753,4 +765,46 @@ EOM
     unlink $Dfile;
 }
 
+{
+    # When iterating over a tied hash using "each", the key passed to FETCH
+    # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
+    # key in FETCH via a filter_fetch_key method we need to check that the
+    # modified key doesn't get passed to NEXTKEY.
+    # Also Test "keys" & "values" while we are at it.
+
+    use warnings ;
+    use strict ;
+    use DB_File ;
+
+    unlink $Dfile;
+    my $bad_key = 0 ;
+    my %h = () ;
+    my $db ;
+    ok(112, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
+    $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_}) ;
+    $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/ ; $_ =~ s/^Alpha_/Beta_/}) ;
+
+    $h{'Alpha_ABC'} = 2 ;
+    $h{'Alpha_DEF'} = 5 ;
+
+    ok(113, $h{'Alpha_ABC'} == 2);
+    ok(114, $h{'Alpha_DEF'} == 5);
+
+    my ($k, $v) = ("","");
+    while (($k, $v) = each %h) {}
+    ok(115, $bad_key == 0);
+
+    $bad_key = 0 ;
+    foreach $k (keys %h) {}
+    ok(116, $bad_key == 0);
+
+    $bad_key = 0 ;
+    foreach $v (values %h) {}
+    ok(117, $bad_key == 0);
+
+    undef $db ;
+    untie %h ;
+    unlink $Dfile;
+}
+
 exit ;
index f029915..8576b30 100644 (file)
@@ -1,8 +1,5 @@
 #!./perl -w
 
-use warnings;
-use strict ;
-
 BEGIN {
     unless(grep /blib/, @INC) {
         chdir 't' if -d 't';
@@ -10,12 +7,14 @@ BEGIN {
     }
 }
  
+use warnings;
+use strict;
 use Config;
  
 BEGIN {
     if(-d "lib" && -f "TEST") {
         if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
-            print "1..138\n";
+            print "1..0 # Skip: DB_File was not built\n";
             exit 0;
         }
     }
@@ -23,7 +22,7 @@ BEGIN {
 
 use DB_File; 
 use Fcntl;
-use vars qw($dbh $Dfile $bad_ones $FA) ;
+our ($dbh, $Dfile, $bad_ones, $FA);
 
 # full tied array support started in Perl 5.004_57
 # Double check to see if it is available.
@@ -78,26 +77,38 @@ sub docat
     open(CAT,$file) || die "Cannot open $file:$!";
     my $result = <CAT>;
     close(CAT);
+    normalise($result) ;
     return $result;
 }
 
 sub docat_del
 { 
     my $file = shift;
-    local $/ = undef;
-    open(CAT,$file) || die "Cannot open $file: $!";
-    my $result = <CAT>;
-    close(CAT);
+    my $result = docat($file);
     unlink $file ;
     return $result;
 }   
 
 sub bad_one
 {
-    print STDERR <<EOM unless $bad_ones++ ;
+    unless ($bad_ones++) {
+       print STDERR <<EOM ;
+#
+# Some older versions of Berkeley DB version 1 will fail db-recno
+# tests 61, 63 and 65.
+EOM
+        if ($^O eq 'darwin'
+           && $Config{db_version_major} == 1
+           && $Config{db_version_minor} == 0
+           && $Config{db_version_patch} == 0) {
+           print STDERR <<EOM ;
 #
-# Some older versions of Berkeley DB version 1 will fail tests 51,
-# 53 and 55.
+# For example Mac OS X 10.1.4 (or earlier) has such an old
+# version of Berkeley DB.
+EOM
+       }
+
+       print STDERR <<EOM ;
 #
 # You can safely ignore the errors if you're never going to use the
 # broken functionality (recno databases with a modified bval). 
@@ -108,21 +119,41 @@ sub bad_one
 # being updated -- Check out http://www.sleepycat.com/ for more details.
 #
 EOM
+    }
+}
+
+sub normalise
+{
+    return unless $^O eq 'cygwin' ;
+    foreach (@_)
+      { s#\r\n#\n#g }     
+}
+
+BEGIN 
+{ 
+    { 
+        local $SIG{__DIE__} ; 
+        eval { require Data::Dumper ; import Data::Dumper } ; 
+    }
+    if ($@) {
+        *Dumper = sub { my $a = shift; return "[ @{ $a } ]" } ;
+    }          
 }
 
-my $splice_tests = 10 + 1; # ten regressions, plus the randoms
+my $splice_tests = 10 + 11 + 1; # ten regressions, 11 warnings, plus the randoms
 my $total_tests = 138 ;
 $total_tests += $splice_tests if $FA ;
 print "1..$total_tests\n";   
 
-my $Dfile = "recno.tmp";
+$Dfile = "recno.tmp";
 unlink $Dfile ;
 
 umask(0);
 
 # Check the interface to RECNOINFO
 
-my $dbh = new DB_File::RECNOINFO ;
+$dbh = new DB_File::RECNOINFO ;
 ok(1, ! defined $dbh->{bval}) ;
 ok(2, ! defined $dbh->{cachesize}) ;
 ok(3, ! defined $dbh->{psize}) ;
@@ -165,8 +196,10 @@ my $X  ;
 my @h ;
 ok(17, $X = tie @h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_RECNO ) ;
 
+my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
+
 ok(18, ((stat($Dfile))[2] & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640)
-       ||  $^O eq 'MSWin32' ||  $^O eq 'NetWare' || $^O eq 'amigaos') ;
+       ||  $noMode{$^O} );
 
 #my $l = @h ;
 my $l = $X->length ;
@@ -382,7 +415,7 @@ unlink $Dfile;
 
    use warnings ;
    use strict ;
-   use vars qw( @ISA @EXPORT) ;
+   our (@ISA, @EXPORT);
 
    require Exporter ;
    use DB_File;
@@ -426,7 +459,7 @@ unlink $Dfile;
    1 ;
 EOM
 
-    close FILE ;
+    close FILE  or die "Could not close: $!";
 
     BEGIN { push @INC, '.'; } 
     eval 'use SubDB ; ';
@@ -436,6 +469,7 @@ EOM
     eval '
        $X = tie(@h, "SubDB","recno.tmp", O_RDWR|O_CREAT, 0640, $DB_RECNO );
        ' ;
+    die "Could not tie: $!" unless $X;
 
     main::ok(68, $@ eq "") ;
 
@@ -774,7 +808,7 @@ EOM
 
     use warnings FATAL => qw(all);
     use strict ;
-    use vars qw(@h $H $file $i) ;
+    our (@h, $H, $file, $i);
     use DB_File ;
     use Fcntl ;
     
@@ -921,6 +955,81 @@ EOM
 exit unless $FA ;
 
 # Test SPLICE
+
+{
+    # check that the splice warnings are under the same lexical control
+    # as their non-tied counterparts.
+
+    use warnings;
+    use strict;
+
+    my $a = '';
+    my @a = (1);
+    local $SIG{__WARN__} = sub {$a = $_[0]} ;
+
+    unlink $Dfile;
+    my @tied ;
+    
+    tie @tied, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_RECNO 
+       or die "Can't open file: $!\n" ;
+
+    # uninitialized offset
+    use warnings;
+    my $offset ;
+    $a = '';
+    splice(@a, $offset);
+    ok(139, $a =~ /^Use of uninitialized value /);
+    $a = '';
+    splice(@tied, $offset);
+    ok(140, $a =~ /^Use of uninitialized value in splice/);
+
+    no warnings 'uninitialized';
+    $a = '';
+    splice(@a, $offset);
+    ok(141, $a eq '');
+    $a = '';
+    splice(@tied, $offset);
+    ok(142, $a eq '');
+
+    # uninitialized length
+    use warnings;
+    my $length ;
+    $a = '';
+    splice(@a, 0, $length);
+    ok(143, $a =~ /^Use of uninitialized value /);
+    $a = '';
+    splice(@tied, 0, $length);
+    ok(144, $a =~ /^Use of uninitialized value in splice/);
+
+    no warnings 'uninitialized';
+    $a = '';
+    splice(@a, 0, $length);
+    ok(145, $a eq '');
+    $a = '';
+    splice(@tied, 0, $length);
+    ok(146, $a eq '');
+
+    # offset past end of array
+    use warnings;
+    $a = '';
+    splice(@a, 3);
+    my $splice_end_array = ($a =~ /^splice\(\) offset past end of array/);
+    $a = '';
+    splice(@tied, 3);
+    ok(147, !$splice_end_array || $a =~ /^splice\(\) offset past end of array/);
+
+    no warnings 'misc';
+    $a = '';
+    splice(@a, 3);
+    ok(148, $a eq '');
+    $a = '';
+    splice(@tied, 3);
+    ok(149, $a eq '');
+
+    untie @tied;
+    unlink $Dfile;
+}
+
 # 
 # These are a few regression tests: bundles of five arguments to pass
 # to test_splice().  The first four arguments correspond to those
@@ -978,15 +1087,14 @@ my @tests = ([ [ 'falsely', 'dinosaur', 'remedy', 'commotion',
               'void' ],
            );
 
-my $testnum = 139;
+my $testnum = 150;
 my $failed = 0;
 require POSIX; my $tmp = POSIX::tmpnam();
 foreach my $test (@tests) {
     my $err = test_splice(@$test);
     if (defined $err) {
-       require Data::Dumper;
-       print STDERR "failed: ", Data::Dumper::Dumper($test);
-       print STDERR "error: $err\n";
+       print STDERR "# failed: ", Dumper($test);
+       print STDERR "# error: $err\n";
        $failed = 1;
        ok($testnum++, 0);
     }
@@ -995,7 +1103,7 @@ foreach my $test (@tests) {
 
 if ($failed) {
     # Not worth running the random ones
-    print STDERR 'skipping ', $testnum++, "\n";
+    print STDERR 'skipping ', $testnum++, "\n";
 }
 else {
     # A thousand randomly-generated tests
@@ -1005,11 +1113,10 @@ else {
        my $test = rand_test();
        my $err = test_splice(@$test);
        if (defined $err) {
-           require Data::Dumper;
-           print STDERR "failed: ", Data::Dumper::Dumper($test);
-           print STDERR "error: $err\n";
+           print STDERR "# failed: ", Dumper($test);
+           print STDERR "# error: $err\n";
            $failed = 1;
-           print STDERR "skipping any remaining random tests\n";
+           print STDERR "skipping any remaining random tests\n";
            last;
        }
     }
@@ -1045,13 +1152,14 @@ sub test_splice {
     my @array = @$array;
     my @list = @$list;
 
-    open(TEXT, ">$tmp") or die "cannot write to $tmp: $!";
-    foreach (@array) { print TEXT "$_\n" }
-    close TEXT or die "cannot close $tmp: $!";
+    unlink $tmp;
     
     my @h;
-    my $H = tie @h, 'DB_File', $tmp, O_RDWR, 0644, $DB_RECNO
+    my $H = tie @h, 'DB_File', $tmp, O_CREAT|O_RDWR, 0644, $DB_RECNO
       or die "cannot open $tmp: $!";
+
+    my $i = 0;
+    foreach ( @array ) { $h[$i++] = $_ }
     
     return "basic DB_File sanity check failed"
       if list_diff(\@array, \@h);
@@ -1132,7 +1240,7 @@ sub test_splice {
 
     foreach ($ms_error, @ms_warnings) {
        chomp;
-       s/ at \S+ line \d+\.?$//;
+       s/ at \S+ line \d+\.?.*//s;
     }
 
     return "different errors: '$s_error' vs '$ms_error'"
@@ -1169,7 +1277,7 @@ sub test_splice {
     untie @h;
     
     open(TEXT, $tmp) or die "cannot open $tmp: $!";
-    @h = <TEXT>; chomp @h;
+    @h = <TEXT>; normalise @h; chomp @h;
     close TEXT or die "cannot close $tmp: $!";
     return('list is different when re-read from disk: '
           . Dumper(\@array) . ' vs ' . Dumper(\@h))
index 0997db1..03b17c1 100644 (file)
@@ -3,12 +3,12 @@
  version.c -- Perl 5 interface to Berkeley DB 
 
  written by Paul Marquess <Paul.Marquess@btinternet.com>
- last modified 22nd Oct 2001
- version 1.79
+ last modified 2nd Jan 2002
+ version 1.802
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1995-2001 Paul Marquess. All rights reserved.
+     Copyright (c) 1995-2002 Paul Marquess. All rights reserved.
      This program is free software; you can redistribute it and/or
      modify it under the same terms as Perl itself.
 
index 3b8bfac..f605ccd 100644 (file)
@@ -1,40 +1,52 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2001
+ * Copyright (c) 2001-2002
  *     Sleepycat Software.  All rights reserved.
  */
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "Id: rep_method.c,v 1.37 2001/11/16 16:29:10 bostic Exp ";
+static const char revid[] = "Id: rep_method.c,v 1.69 2002/08/06 04:50:36 bostic Exp ";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
+#ifdef HAVE_RPC
+#include <rpc/rpc.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #endif
 
-#ifdef  HAVE_RPC
-#include "db_server.h"
-#endif
-
 #include "db_int.h"
-#include "log.h"
-#include "rep.h"
+#include "dbinc/db_page.h"
+#include "dbinc/db_am.h"
+#include "dbinc/log.h"
+#include "dbinc/rep.h"
+#include "dbinc/txn.h"
 
 #ifdef HAVE_RPC
-#include "rpc_client_ext.h"
+#include "dbinc_auto/db_server.h"
+#include "dbinc_auto/rpc_client_ext.h"
 #endif
 
+static int __rep_abort_prepared __P((DB_ENV *));
+static int __rep_bt_cmp __P((DB *, const DBT *, const DBT *));
+static int __rep_client_dbinit __P((DB_ENV *, int));
 static int __rep_elect __P((DB_ENV *, int, int, u_int32_t, int *));
-static int __rep_elect_init __P((DB_ENV *, DB_LSN *, int, int, int *));
+static int __rep_elect_init __P((DB_ENV *, DB_LSN *, int, int, int, int *));
+static int __rep_flush __P((DB_ENV *));
+static int __rep_restore_prepared __P((DB_ENV *));
+static int __rep_set_limit __P((DB_ENV *, u_int32_t, u_int32_t));
+static int __rep_set_request __P((DB_ENV *, u_int32_t, u_int32_t));
 static int __rep_set_rep_transport __P((DB_ENV *, int,
     int (*)(DB_ENV *, const DBT *, const DBT *, int, u_int32_t)));
 static int __rep_start __P((DB_ENV *, DBT *, u_int32_t));
+static int __rep_stat __P((DB_ENV *, DB_REP_STAT **, u_int32_t));
 static int __rep_wait __P((DB_ENV *, u_int32_t, int *, u_int32_t));
 
 /*
@@ -50,33 +62,43 @@ __rep_dbenv_create(dbenv)
        DB_REP *db_rep;
        int ret;
 
-       /*
-        * !!!
-        * Our caller has not yet had the opportunity to reset the panic
-        * state or turn off mutex locking, and so we can neither check
-        * the panic state or acquire a mutex in the DB_ENV create path.
-        */
-
-       if ((ret = __os_calloc(dbenv, 1, sizeof(DB_REP), &db_rep)) != 0)
-               return (ret);
-       dbenv->rep_handle = db_rep;
-
-       /* Initialize the per-process replication structure. */
-       db_rep->rep_send = NULL;
-
 #ifdef HAVE_RPC
        if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
+               COMPQUIET(db_rep, NULL);
+               COMPQUIET(ret, 0);
                dbenv->rep_elect = __dbcl_rep_elect;
-               dbenv->rep_start = __dbcl_rep_start;
+               dbenv->rep_flush = __dbcl_rep_flush;
                dbenv->rep_process_message = __dbcl_rep_process_message;
+               dbenv->rep_start = __dbcl_rep_start;
+               dbenv->rep_stat = __dbcl_rep_stat;
+               dbenv->set_rep_limit = __dbcl_rep_set_limit;
+               dbenv->set_rep_request = __dbcl_rep_set_request;
                dbenv->set_rep_transport = __dbcl_rep_set_rep_transport;
+
        } else
 #endif
        {
                dbenv->rep_elect = __rep_elect;
+               dbenv->rep_flush = __rep_flush;
                dbenv->rep_process_message = __rep_process_message;
                dbenv->rep_start = __rep_start;
+               dbenv->rep_stat = __rep_stat;
+               dbenv->set_rep_limit = __rep_set_limit;
+               dbenv->set_rep_request = __rep_set_request;
                dbenv->set_rep_transport = __rep_set_rep_transport;
+               /*
+                * !!!
+                * Our caller has not yet had the opportunity to reset the panic
+                * state or turn off mutex locking, and so we can neither check
+                * the panic state or acquire a mutex in the DB_ENV create path.
+                */
+
+               if ((ret = __os_calloc(dbenv, 1, sizeof(DB_REP), &db_rep)) != 0)
+                       return (ret);
+               dbenv->rep_handle = db_rep;
+
+               /* Initialize the per-process replication structure. */
+               db_rep->rep_send = NULL;
        }
 
        return (0);
@@ -98,10 +120,11 @@ __rep_start(dbenv, dbt, flags)
        DB_LSN lsn;
        DB_REP *db_rep;
        REP *rep;
-       int announce, init_db, ret;
+       int announce, init_db, redo_prepared, ret;
 
-       ENV_ILLEGAL_BEFORE_OPEN(dbenv, "rep_start");
        PANIC_CHECK(dbenv);
+       ENV_ILLEGAL_BEFORE_OPEN(dbenv, "rep_start");
+       ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "rep_stat", DB_INIT_TXN);
 
        db_rep = dbenv->rep_handle;
        rep = db_rep->region;
@@ -114,9 +137,9 @@ __rep_start(dbenv, dbt, flags)
        if ((ret = __db_fcchk(dbenv,
            "DB_ENV->rep_start", flags, DB_REP_CLIENT, DB_REP_MASTER)) != 0)
                return (ret);
-       if (!LF_ISSET(DB_REP_CLIENT | DB_REP_MASTER)) {
+       if (!LF_ISSET(DB_REP_CLIENT | DB_REP_MASTER | DB_REP_LOGSONLY)) {
                __db_err(dbenv,
-       "DB_ENV->rep_start: either DB_CLIENT or DB_MASTER must be specified.");
+       "DB_ENV->rep_start: replication mode must be specified");
                return (EINVAL);
        }
 
@@ -132,25 +155,39 @@ __rep_start(dbenv, dbt, flags)
                return (EINVAL);
        }
 
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        if (rep->eid == DB_EID_INVALID)
                rep->eid = dbenv->rep_eid;
 
        if (LF_ISSET(DB_REP_MASTER)) {
-               if (db_rep->rep_db != NULL) {
-                       ret = db_rep->rep_db->close(db_rep->rep_db, DB_NOSYNC);
-                       db_rep->rep_db = NULL;
-               }
+               if (F_ISSET(dbenv, DB_ENV_REP_CLIENT))
+                       /*
+                        * If we're upgrading from having been a client,
+                        * preclose, so that we close our temporary database.
+                        *
+                        * Do not close files that we may have opened while
+                        * doing a rep_apply;  they'll get closed when we
+                        * finally close the environment, but for now, leave
+                        * them open, as we don't want to recycle their
+                        * fileids, and we may need the handles again if
+                        * we become a client and the original master
+                        * that opened them becomes a master again.
+                        */
+                       if ((ret = __rep_preclose(dbenv, 0)) != 0)
+                               return (ret);
 
                F_CLR(dbenv, DB_ENV_REP_CLIENT);
+               redo_prepared = 0;
                if (!F_ISSET(rep, REP_F_MASTER)) {
                        /* Master is not yet set. */
                        if (F_ISSET(rep, REP_ISCLIENT)) {
                                F_CLR(rep, REP_ISCLIENT);
                                rep->gen = ++rep->w_gen;
+                               redo_prepared = 1;
                        } else if (rep->gen == 0)
                                rep->gen = 1;
                }
+
                F_SET(rep, REP_F_MASTER);
                F_SET(dbenv, DB_ENV_REP_MASTER);
                MUTEX_UNLOCK(dbenv, db_rep->mutexp);
@@ -158,8 +195,15 @@ __rep_start(dbenv, dbt, flags)
                R_LOCK(dbenv, &dblp->reginfo);
                lsn = ((LOG *)dblp->reginfo.primary)->lsn;
                R_UNLOCK(dbenv, &dblp->reginfo);
-               ret = __rep_send_message(dbenv,
-                   DB_EID_BROADCAST, REP_NEWMASTER, &lsn, NULL, 0);
+
+               /*
+                * Send the NEWMASTER message, then restore prepared txns
+                * if and only if we just upgraded from being a client.
+                */
+               if ((ret = __rep_send_message(dbenv,
+                   DB_EID_BROADCAST, REP_NEWMASTER, &lsn, NULL, 0)) == 0 &&
+                   redo_prepared)
+                       ret = __rep_restore_prepared(dbenv);
        } else {
                F_CLR(dbenv, DB_ENV_REP_MASTER);
                F_SET(dbenv, DB_ENV_REP_CLIENT);
@@ -188,6 +232,17 @@ __rep_start(dbenv, dbt, flags)
                }
                MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
+               /*
+                * Abort any prepared transactions that were restored
+                * by recovery.  We won't be able to create any txns of
+                * our own until they're resolved, but we can't resolve
+                * them ourselves;  the master has to.  If any get
+                * resolved as commits, we'll redo them when commit
+                * records come in.  Aborts will simply be ignored.
+                */
+               if ((ret = __rep_abort_prepared(dbenv)) != 0)
+                       return (ret);
+
                if ((ret = __rep_client_dbinit(dbenv, init_db)) != 0)
                        return (ret);
 
@@ -207,6 +262,435 @@ __rep_start(dbenv, dbt, flags)
 }
 
 /*
+ * __rep_client_dbinit --
+ *
+ * Initialize the LSN database on the client side.  This is called from the
+ * client initialization code.  The startup flag value indicates if
+ * this is the first thread/process starting up and therefore should create
+ * the LSN database.  This routine must be called once by each process acting
+ * as a client.
+ */
+static int
+__rep_client_dbinit(dbenv, startup)
+       DB_ENV *dbenv;
+       int startup;
+{
+       DB_REP *db_rep;
+       DB *rep_db;
+       int ret, t_ret;
+       u_int32_t flags;
+
+       PANIC_CHECK(dbenv);
+       db_rep = dbenv->rep_handle;
+       rep_db = NULL;
+
+#define        REPDBNAME       "__db.rep.db"
+
+       /* Check if this has already been called on this environment. */
+       if (db_rep->rep_db != NULL)
+               return (0);
+
+       MUTEX_LOCK(dbenv, db_rep->db_mutexp);
+
+       if (startup) {
+               if ((ret = db_create(&rep_db, dbenv, 0)) != 0)
+                       goto err;
+               /*
+                * Ignore errors, because if the file doesn't exist, this
+                * is perfectly OK.
+                */
+               (void)rep_db->remove(rep_db, REPDBNAME, NULL, 0);
+       }
+
+       if ((ret = db_create(&rep_db, dbenv, 0)) != 0)
+               goto err;
+       if ((ret = rep_db->set_bt_compare(rep_db, __rep_bt_cmp)) != 0)
+               goto err;
+
+       /* Allow writes to this database on a client. */
+       F_SET(rep_db, DB_AM_CL_WRITER);
+
+       flags = (F_ISSET(dbenv, DB_ENV_THREAD) ? DB_THREAD : 0) |
+           (startup ? DB_CREATE : 0);
+       if ((ret = rep_db->open(rep_db, NULL,
+           "__db.rep.db", NULL, DB_BTREE, flags, 0)) != 0)
+               goto err;
+
+       db_rep->rep_db = rep_db;
+
+       if (0) {
+err:           if (rep_db != NULL &&
+                   (t_ret = rep_db->close(rep_db, DB_NOSYNC)) != 0 && ret == 0)
+                       ret = t_ret;
+               db_rep->rep_db = NULL;
+       }
+
+       MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+
+       return (ret);
+}
+
+/*
+ * __rep_bt_cmp --
+ *
+ * Comparison function for the LSN table.  We use the entire control
+ * structure as a key (for simplicity, so we don't have to merge the
+ * other fields in the control with the data field), but really only
+ * care about the LSNs.
+ */
+static int
+__rep_bt_cmp(dbp, dbt1, dbt2)
+       DB *dbp;
+       const DBT *dbt1, *dbt2;
+{
+       DB_LSN lsn1, lsn2;
+       REP_CONTROL *rp1, *rp2;
+
+       COMPQUIET(dbp, NULL);
+
+       rp1 = dbt1->data;
+       rp2 = dbt2->data;
+
+       __ua_memcpy(&lsn1, &rp1->lsn, sizeof(DB_LSN));
+       __ua_memcpy(&lsn2, &rp2->lsn, sizeof(DB_LSN));
+
+       if (lsn1.file > lsn2.file)
+               return (1);
+
+       if (lsn1.file < lsn2.file)
+               return (-1);
+
+       if (lsn1.offset > lsn2.offset)
+               return (1);
+
+       if (lsn1.offset < lsn2.offset)
+               return (-1);
+
+       return (0);
+}
+
+/*
+ * __rep_abort_prepared --
+ *     Abort any prepared transactions that recovery restored.
+ *
+ *     This is used by clients that have just run recovery, since
+ * they cannot/should not call txn_recover and handle prepared transactions
+ * themselves.
+ */
+static int
+__rep_abort_prepared(dbenv)
+       DB_ENV *dbenv;
+{
+#define        PREPLISTSIZE    50
+       DB_PREPLIST prep[PREPLISTSIZE], *p;
+       DB_TXNMGR *mgr;
+       DB_TXNREGION *region;
+       int do_aborts, ret;
+       long count, i;
+       u_int32_t op;
+
+       mgr = dbenv->tx_handle;
+       region = mgr->reginfo.primary;
+
+       do_aborts = 0;
+       R_LOCK(dbenv, &mgr->reginfo);
+       if (region->stat.st_nrestores != 0)
+               do_aborts = 1;
+       R_UNLOCK(dbenv, &mgr->reginfo);
+
+       if (do_aborts) {
+               op = DB_FIRST;
+               do {
+                       if ((ret = dbenv->txn_recover(dbenv,
+                           prep, PREPLISTSIZE, &count, op)) != 0)
+                               return (ret);
+                       for (i = 0; i < count; i++) {
+                               p = &prep[i];
+                               if ((ret = p->txn->abort(p->txn)) != 0)
+                                       return (ret);
+                       }
+                       op = DB_NEXT;
+               } while (count == PREPLISTSIZE);
+       }
+
+       return (0);
+}
+
+/*
+ * __rep_restore_prepared --
+ *     Restore to a prepared state any prepared but not yet committed
+ * transactions.
+ *
+ *     This performs, in effect, a "mini-recovery";  it is called from
+ * __rep_start by newly upgraded masters.  There may be transactions that an
+ * old master prepared but did not resolve, which we need to restore to an
+ * active state.
+ */
+static int
+__rep_restore_prepared(dbenv)
+       DB_ENV *dbenv;
+{
+       DB_LOGC *logc;
+       DB_LSN ckp_lsn, lsn;
+       DBT rec;
+       __txn_ckp_args *ckp_args;
+       __txn_regop_args *regop_args;
+       __txn_xa_regop_args *prep_args;
+       int ret, t_ret;
+       u_int32_t hi_txn, low_txn, rectype;
+       void *txninfo;
+
+       txninfo = NULL;
+       ckp_args = NULL;
+       prep_args = NULL;
+       regop_args = NULL;
+       ZERO_LSN(ckp_lsn);
+       ZERO_LSN(lsn);
+
+       if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
+               return (ret);
+
+       /*
+        * We need to consider the set of records between the most recent
+        * checkpoint LSN and the end of the log;  any txn in that
+        * range, and only txns in that range, could still have been
+        * active, and thus prepared but not yet committed (PBNYC),
+        * when the old master died.
+        *
+        * Find the most recent checkpoint LSN, and get the record there.
+        * If there is no checkpoint in the log, start off by getting
+        * the very first record in the log instead.
+        */
+       memset(&rec, 0, sizeof(DBT));
+       if ((ret = __txn_getckp(dbenv, &lsn)) == 0) {
+               if ((ret = logc->get(logc, &lsn, &rec, DB_SET)) != 0)  {
+                       __db_err(dbenv,
+                           "Checkpoint record at LSN [%ld][%ld] not found",
+                           (u_long)lsn.file, (u_long)lsn.offset);
+                       goto err;
+               }
+
+               if ((ret = __txn_ckp_read(dbenv, rec.data, &ckp_args)) != 0) {
+                       __db_err(dbenv,
+                           "Invalid checkpoint record at [%ld][%ld]",
+                           (u_long)lsn.file, (u_long)lsn.offset);
+                       goto err;
+               }
+
+               ckp_lsn = ckp_args->ckp_lsn;
+
+               if ((ret = logc->get(logc, &ckp_lsn, &rec, DB_SET)) != 0) {
+                       __db_err(dbenv,
+                           "Checkpoint LSN record [%ld][%ld] not found",
+                           (u_long)ckp_lsn.file, (u_long)ckp_lsn.offset);
+                       goto err;
+               }
+       } else if ((ret = logc->get(logc, &lsn, &rec, DB_FIRST)) != 0) {
+               if (ret == DB_NOTFOUND) {
+                       /* An empty log means no PBNYC txns. */
+                       ret = 0;
+                       goto done;
+               }
+               __db_err(dbenv, "Attempt to get first log record failed");
+               goto err;
+       }
+
+       /*
+        * We use the same txnlist infrastructure that recovery does;
+        * it demands an estimate of the high and low txnids for
+        * initialization.
+        *
+        * First, the low txnid.
+        */
+       do {
+               /* txnid is after rectype, which is a u_int32. */
+               memcpy(&low_txn,
+                   (u_int8_t *)rec.data + sizeof(u_int32_t), sizeof(low_txn));
+               if (low_txn != 0)
+                       break;
+       } while ((ret = logc->get(logc, &lsn, &rec, DB_NEXT)) == 0);
+
+       /* If there are no txns, there are no PBNYC txns. */
+       if (ret == DB_NOTFOUND) {
+               ret = 0;
+               goto done;
+       } else if (ret != 0)
+               goto err;
+
+       /* Now, the high txnid. */
+       if ((ret = logc->get(logc, &lsn, &rec, DB_LAST)) != 0) {
+               /*
+                * Note that DB_NOTFOUND is unacceptable here because we
+                * had to have looked at some log record to get this far.
+                */
+               __db_err(dbenv, "Final log record not found");
+               goto err;
+       }
+       do {
+               /* txnid is after rectype, which is a u_int32. */
+               memcpy(&hi_txn,
+                   (u_int8_t *)rec.data + sizeof(u_int32_t), sizeof(hi_txn));
+               if (hi_txn != 0)
+                       break;
+       } while ((ret = logc->get(logc, &lsn, &rec, DB_PREV)) == 0);
+       if (ret == DB_NOTFOUND) {
+               ret = 0;
+               goto done;
+       } else if (ret != 0)
+               goto err;
+
+       /* We have a high and low txnid.  Initialise the txn list. */
+       if ((ret =
+           __db_txnlist_init(dbenv, low_txn, hi_txn, NULL, &txninfo)) != 0)
+               goto err;
+
+       /*
+        * Now, walk backward from the end of the log to ckp_lsn.  Any
+        * prepares that we hit without first hitting a commit or
+        * abort belong to PBNYC txns, and we need to apply them and
+        * restore them to a prepared state.
+        *
+        * Note that we wind up applying transactions out of order.
+        * Since all PBNYC txns still held locks on the old master and
+        * were isolated, this should be safe.
+        */
+       for (ret = logc->get(logc, &lsn, &rec, DB_LAST);
+           ret == 0 && log_compare(&lsn, &ckp_lsn) > 0;
+           ret = logc->get(logc, &lsn, &rec, DB_PREV)) {
+               memcpy(&rectype, rec.data, sizeof(rectype));
+               switch (rectype) {
+               case DB___txn_regop:
+                       /*
+                        * It's a commit or abort--but we don't care
+                        * which!  Just add it to the list of txns
+                        * that are resolved.
+                        */
+                       if ((ret = __txn_regop_read(dbenv, rec.data,
+                           &regop_args)) != 0)
+                               goto err;
+
+                       ret = __db_txnlist_find(dbenv,
+                           txninfo, regop_args->txnid->txnid);
+                       if (ret == DB_NOTFOUND)
+                               ret = __db_txnlist_add(dbenv, txninfo,
+                                   regop_args->txnid->txnid,
+                                   regop_args->opcode, &lsn);
+                       break;
+               case DB___txn_xa_regop:
+                       /*
+                        * It's a prepare.  If we haven't put the
+                        * txn on our list yet, it hasn't been
+                        * resolved, so apply and restore it.
+                        */
+                       if ((ret = __txn_xa_regop_read(dbenv, rec.data,
+                           &prep_args)) != 0)
+                               goto err;
+                       ret = __db_txnlist_find(dbenv, txninfo,
+                           prep_args->txnid->txnid);
+                       if (ret == DB_NOTFOUND)
+                               if ((ret = __rep_process_txn(dbenv, &rec)) == 0)
+                                       ret = __txn_restore_txn(dbenv,
+                                           &lsn, prep_args);
+                       break;
+               default:
+                       continue;
+               }
+       }
+
+       /* It's not an error to have hit the beginning of the log. */
+       if (ret == DB_NOTFOUND)
+               ret = 0;
+
+done:
+err:   t_ret = logc->close(logc, 0);
+
+       if (txninfo != NULL)
+               __db_txnlist_end(dbenv, txninfo);
+       if (ckp_args != NULL)
+               __os_free(dbenv, ckp_args);
+       if (prep_args != NULL)
+               __os_free(dbenv, prep_args);
+       if (regop_args != NULL)
+               __os_free(dbenv, regop_args);
+
+       return (ret == 0 ? t_ret : ret);
+}
+
+/*
+ * __rep_set_limit --
+ *     Set a limit on the amount of data that will be sent during a single
+ * invocation of __rep_process_message.
+ */
+static int
+__rep_set_limit(dbenv, gbytes, bytes)
+       DB_ENV *dbenv;
+       u_int32_t gbytes;
+       u_int32_t bytes;
+{
+       DB_REP *db_rep;
+       REP *rep;
+
+       PANIC_CHECK(dbenv);
+
+       if ((db_rep = dbenv->rep_handle) == NULL) {
+               __db_err(dbenv,
+    "DB_ENV->set_rep_limit: database environment not properly initialized");
+               return (__db_panic(dbenv, EINVAL));
+       }
+       rep = db_rep->region;
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
+       if (bytes > GIGABYTE) {
+               gbytes += bytes / GIGABYTE;
+               bytes = bytes % GIGABYTE;
+       }
+       rep->gbytes = gbytes;
+       rep->bytes = bytes;
+       MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+
+       return (0);
+}
+
+/*
+ * __rep_set_request --
+ *     Set the minimum and maximum number of log records that we wait
+ * before retransmitting.
+ * UNDOCUMENTED.
+ */
+static int
+__rep_set_request(dbenv, min, max)
+       DB_ENV *dbenv;
+       u_int32_t min;
+       u_int32_t max;
+{
+       LOG *lp;
+       DB_LOG *dblp;
+       DB_REP *db_rep;
+       REP *rep;
+
+       PANIC_CHECK(dbenv);
+
+       if ((db_rep = dbenv->rep_handle) == NULL) {
+               __db_err(dbenv,
+    "DB_ENV->set_rep_request: database environment not properly initialized");
+               return (__db_panic(dbenv, EINVAL));
+       }
+       rep = db_rep->region;
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
+       rep->request_gap = min;
+       rep->max_gap = max;
+       MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+       dblp = dbenv->lg_handle;
+       if (dblp != NULL && (lp = dblp->reginfo.primary) != NULL) {
+               R_LOCK(dbenv, &dblp->reginfo);
+               lp->wait_recs = 0;
+               lp->rcvd_recs = 0;
+               R_UNLOCK(dbenv, &dblp->reginfo);
+       }
+
+       return (0);
+}
+
+/*
  * __rep_set_transport --
  *     Set the transport function for replication.
  */
@@ -218,10 +702,12 @@ __rep_set_rep_transport(dbenv, eid, f_send)
 {
        DB_REP *db_rep;
 
+       PANIC_CHECK(dbenv);
+
        if ((db_rep = dbenv->rep_handle) == NULL) {
                __db_err(dbenv,
     "DB_ENV->set_rep_transport: database environment not properly initialized");
-               return (DB_RUNRECOVERY);
+               return (__db_panic(dbenv, EINVAL));
        }
 
        if (f_send == NULL) {
@@ -258,7 +744,11 @@ __rep_elect(dbenv, nsites, priority, timeout, eidp)
        DB_LSN lsn;
        DB_REP *db_rep;
        REP *rep;
-       int in_progress, ret, send_vote;
+       int in_progress, ret, send_vote, tiebreaker;
+       u_int32_t pid, sec, usec;
+
+       PANIC_CHECK(dbenv);
+       ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "rep_elect", DB_INIT_TXN);
 
        /* Error checking. */
        if (nsites <= 0) {
@@ -272,15 +762,22 @@ __rep_elect(dbenv, nsites, priority, timeout, eidp)
                return (EINVAL);
        }
 
+       db_rep = dbenv->rep_handle;
+       rep = db_rep->region;
        dblp = dbenv->lg_handle;
+
        R_LOCK(dbenv, &dblp->reginfo);
        lsn = ((LOG *)dblp->reginfo.primary)->lsn;
        R_UNLOCK(dbenv, &dblp->reginfo);
 
-       db_rep = dbenv->rep_handle;
-       rep = db_rep->region;
+       /* Generate a randomized tiebreaker value. */
+       __os_id(&pid);
+       if ((ret = __os_clock(dbenv, &sec, &usec)) != 0)
+               return (ret);
+       tiebreaker = (int)pid ^ (int)sec ^ (int)usec ^ rand() ^ (int)&pid;
+
        if ((ret = __rep_elect_init(dbenv,
-           &lsn, nsites, priority, &in_progress)) != 0) {
+           &lsn, nsites, priority, tiebreaker, &in_progress)) != 0) {
                if (ret == DB_REP_NEWMASTER) {
                        ret = 0;
                        *eidp = dbenv->rep_eid;
@@ -296,13 +793,17 @@ __rep_elect(dbenv, nsites, priority, timeout, eidp)
                if ((ret = __rep_send_message(dbenv,
                    DB_EID_BROADCAST, REP_ELECT, NULL, NULL, 0)) != 0)
                        goto err;
+               DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTSEND, ret, NULL);
        }
 
        /* Now send vote */
-       if ((ret = __rep_send_vote(dbenv, &lsn, nsites, priority)) != 0)
+       if ((ret =
+           __rep_send_vote(dbenv, &lsn, nsites, priority, tiebreaker)) != 0)
                goto err;
+       DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTVOTE1, ret, NULL);
 
        ret = __rep_wait(dbenv, timeout, eidp, REP_F_EPHASE1);
+       DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTWAIT1, ret, NULL);
        switch (ret) {
                case 0:
                        /* Check if election complete or phase complete. */
@@ -320,7 +821,7 @@ __rep_elect(dbenv, nsites, priority, timeout, eidp)
         * votes to pick a winner and if so, to send out a vote to
         * the winner.
         */
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        send_vote = DB_EID_INVALID;
        if (rep->sites > rep->nsites / 2) {
                /* We think we've seen enough to cast a vote. */
@@ -352,8 +853,10 @@ __rep_elect(dbenv, nsites, priority, timeout, eidp)
        if (send_vote != rep->eid && (ret = __rep_send_message(dbenv,
            send_vote, REP_VOTE2, NULL, NULL, 0)) != 0)
                goto err;
+       DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTVOTE2, ret, NULL);
 
 phase2:        ret = __rep_wait(dbenv, timeout, eidp, REP_F_EPHASE2);
+       DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTWAIT2, ret, NULL);
        switch (ret) {
                case 0:
                        return (0);
@@ -364,7 +867,8 @@ phase2:     ret = __rep_wait(dbenv, timeout, eidp, REP_F_EPHASE2);
                        goto err;
        }
 
-err:   MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+DB_TEST_RECOVERY_LABEL
+err:   MUTEX_LOCK(dbenv, db_rep->mutexp);
        ELECTION_DONE(rep);
        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
@@ -381,10 +885,10 @@ err:      MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
  * already in progress; makes it 0 otherwise.
  */
 static int
-__rep_elect_init(dbenv, lsnp, nsites, priority, beginp)
+__rep_elect_init(dbenv, lsnp, nsites, priority, tiebreaker, beginp)
        DB_ENV *dbenv;
        DB_LSN *lsnp;
-       int nsites, priority, *beginp;
+       int nsites, priority, tiebreaker, *beginp;
 {
        DB_REP *db_rep;
        REP *rep;
@@ -395,14 +899,18 @@ __rep_elect_init(dbenv, lsnp, nsites, priority, beginp)
 
        ret = 0;
 
+       /* We may miscount, as we don't hold the replication mutex here. */
+       rep->stat.st_elections++;
+
        /* If we are already a master; simply broadcast that fact and return. */
        if (F_ISSET(dbenv, DB_ENV_REP_MASTER)) {
-               ret = __rep_send_message(dbenv,
+               (void)__rep_send_message(dbenv,
                    DB_EID_BROADCAST, REP_NEWMASTER, lsnp, NULL, 0);
+               rep->stat.st_elections_won++;
                return (DB_REP_NEWMASTER);
        }
 
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        *beginp = IN_ELECTION(rep);
        if (!*beginp) {
                F_SET(rep, REP_F_EPHASE1);
@@ -410,6 +918,7 @@ __rep_elect_init(dbenv, lsnp, nsites, priority, beginp)
                if (nsites > rep->asites &&
                    (ret = __rep_grow_sites(dbenv, nsites)) != 0)
                        goto err;
+               DB_ENV_TEST_RECOVERY(dbenv, DB_TEST_ELECTINIT, ret, NULL);
                rep->nsites = nsites;
                rep->priority = priority;
                rep->votes = 0;
@@ -425,13 +934,16 @@ __rep_elect_init(dbenv, lsnp, nsites, priority, beginp)
                        rep->w_priority = priority;
                        rep->w_gen = rep->gen;
                        rep->w_lsn = *lsnp;
+                       rep->w_tiebreaker = tiebreaker;
                } else {
                        rep->winner = DB_EID_INVALID;
                        rep->w_priority = 0;
                        rep->w_gen = 0;
                        ZERO_LSN(rep->w_lsn);
+                       rep->w_tiebreaker = 0;
                }
        }
+DB_TEST_RECOVERY_LABEL
 err:   MUTEX_UNLOCK(dbenv, db_rep->mutexp);
        return (ret);
 }
@@ -458,10 +970,12 @@ __rep_wait(dbenv, timeout, eidp, flags)
         * Sleep repeatedly for the smaller of .5s and timeout/10.
         */
        sleeptime = (timeout > 5000000) ? 500000 : timeout / 10;
+       if (sleeptime == 0)
+               sleeptime++;
        while (timeout > 0) {
                if ((ret = __os_sleep(dbenv, 0, sleeptime)) != 0)
                        return (ret);
-               MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+               MUTEX_LOCK(dbenv, db_rep->mutexp);
                done = !F_ISSET(rep, flags) && rep->master_id != DB_EID_INVALID;
 
                *eidp = rep->master_id;
@@ -477,3 +991,136 @@ __rep_wait(dbenv, timeout, eidp, flags)
        }
        return (DB_TIMEOUT);
 }
+
+/*
+ * __rep_flush --
+ *     Re-push the last log record to all clients, in case they've lost
+ * messages and don't know it.
+ */
+static int
+__rep_flush(dbenv)
+       DB_ENV *dbenv;
+{
+       DBT rec;
+       DB_LOGC *logc;
+       DB_LSN lsn;
+       int ret, t_ret;
+
+       PANIC_CHECK(dbenv);
+       ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "rep_stat", DB_INIT_TXN);
+
+       if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
+               return (ret);
+
+       memset(&rec, 0, sizeof(rec));
+       memset(&lsn, 0, sizeof(lsn));
+
+       if ((ret = logc->get(logc, &lsn, &rec, DB_LAST)) != 0)
+               goto err;
+
+       ret = __rep_send_message(dbenv,
+           DB_EID_BROADCAST, REP_LOG, &lsn, &rec, 0);
+
+err:   if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
+               ret = t_ret;
+       return (ret);
+}
+
+/*
+ * __rep_stat --
+ *     Fetch replication statistics.
+ */
+static int
+__rep_stat(dbenv, statp, flags)
+       DB_ENV *dbenv;
+       DB_REP_STAT **statp;
+       u_int32_t flags;
+{
+       DB_LOG *dblp;
+       DB_REP *db_rep;
+       DB_REP_STAT *stats;
+       LOG *lp;
+       REP *rep;
+       u_int32_t queued;
+       int ret;
+
+       PANIC_CHECK(dbenv);
+       ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "rep_stat", DB_INIT_TXN);
+
+       db_rep = dbenv->rep_handle;
+       rep = db_rep->region;
+       dblp = dbenv->lg_handle;
+       lp = dblp->reginfo.primary;
+
+       *statp = NULL;
+       if ((ret = __db_fchk(dbenv,
+           "DB_ENV->rep_stat", flags, DB_STAT_CLEAR)) != 0)
+               return (ret);
+
+       /* Allocate a stat struct to return to the user. */
+       if ((ret = __os_umalloc(dbenv, sizeof(DB_REP_STAT), &stats)) != 0)
+               return (ret);
+
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
+       memcpy(stats, &rep->stat, sizeof(*stats));
+
+       /* Copy out election stats. */
+       if (IN_ELECTION(rep)) {
+               if (F_ISSET(rep, REP_F_EPHASE1))
+                       stats->st_election_status = 1;
+               else if (F_ISSET(rep, REP_F_EPHASE2))
+                       stats->st_election_status = 2;
+
+               stats->st_election_nsites = rep->sites;
+               stats->st_election_cur_winner = rep->winner;
+               stats->st_election_priority = rep->w_priority;
+               stats->st_election_gen = rep->w_gen;
+               stats->st_election_lsn = rep->w_lsn;
+               stats->st_election_votes = rep->votes;
+               stats->st_election_tiebreaker = rep->w_tiebreaker;
+       }
+
+       /* Copy out other info that's protected by the rep mutex. */
+       stats->st_env_id = rep->eid;
+       stats->st_env_priority = rep->priority;
+       stats->st_nsites = rep->nsites;
+       stats->st_master = rep->master_id;
+       stats->st_gen = rep->gen;
+
+       if (F_ISSET(rep, REP_F_MASTER))
+               stats->st_status = DB_REP_MASTER;
+       else if (F_ISSET(rep, REP_F_LOGSONLY))
+               stats->st_status = DB_REP_LOGSONLY;
+       else if (F_ISSET(rep, REP_F_UPGRADE))
+               stats->st_status = DB_REP_CLIENT;
+       else
+               stats->st_status = 0;
+
+       if (LF_ISSET(DB_STAT_CLEAR)) {
+               queued = rep->stat.st_log_queued;
+               memset(&rep->stat, 0, sizeof(rep->stat));
+               rep->stat.st_log_queued = rep->stat.st_log_queued_total =
+                   rep->stat.st_log_queued_max = queued;
+       }
+       MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+
+       /*
+        * Log-related replication info is stored in the log system and
+        * protected by the log region lock.
+        */
+       R_LOCK(dbenv, &dblp->reginfo);
+       if (F_ISSET(rep, REP_ISCLIENT)) {
+               stats->st_next_lsn = lp->ready_lsn;
+               stats->st_waiting_lsn = lp->waiting_lsn;
+       } else {
+               if (F_ISSET(rep, REP_F_MASTER))
+                       stats->st_next_lsn = lp->lsn;
+               else
+                       ZERO_LSN(stats->st_next_lsn);
+               ZERO_LSN(stats->st_waiting_lsn);
+       }
+       R_UNLOCK(dbenv, &dblp->reginfo);
+
+       *statp = stats;
+       return (0);
+}
index dd4d870..f2b6b7e 100644 (file)
@@ -1,67 +1,35 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2001
+ * Copyright (c) 2001-2002
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "Id: rep_record.c,v 1.64 2001/11/16 16:29:10 bostic Exp ";
+static const char revid[] = "Id: rep_record.c,v 1.108 2002/08/09 02:17:41 margo Exp ";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
+#include <stdlib.h>
 #include <string.h>
 #endif
 
 #include "db_int.h"
-#include "log.h"
-#include "txn.h"
-#include "rep.h"
-#include "db_page.h"
-#include "db_am.h"
-#include "db_shash.h"
-#include "lock.h"
+#include "dbinc/db_page.h"
+#include "dbinc/db_am.h"
+#include "dbinc/log.h"
+#include "dbinc/rep.h"
+#include "dbinc/txn.h"
 
 static int __rep_apply __P((DB_ENV *, REP_CONTROL *, DBT *));
-static int __rep_bt_cmp __P((DB *, const DBT *, const DBT *));
-static int __rep_process_txn __P((DB_ENV *, DBT *));
+static int __rep_collect_txn __P((DB_ENV *, DB_LSN *, LSN_COLLECTION *));
+static int __rep_lsn_cmp __P((const void *, const void *));
+static int __rep_newfile __P((DB_ENV *, REP_CONTROL *, DBT *, DB_LSN *));
 
-#define        IS_SIMPLE(R)    \
-       ((R) != DB_txn_regop && (R) != DB_txn_ckp && (R) != DB_log_register)
-
-/*
- * This is a bit of a hack.  If we set the offset to be the sizeof the
- * persistent log structure, then we'll match the correct LSN on the
- * next log write.
- *
- * If lp->ready_lsn is [1][0], we need to "change" to the first log
- * file (we currently have none).  However, in this situation, we
- * don't want to wind up at LSN [2][whatever], we want to wind up at
- * LSN [1][whatever], so don't set LOG_NEWFILE.  The guts of the log
- * system will take care of actually writing the persistent header,
- * since we're doing a log_put to an empty log.
- *
- * If lp->ready_lsn is [m-1][n] for some m > 1, n > 0, we really do need to
- * change to the first log file.  Not only do we need to jump to lsn
- * [m][0], we need to write out a persistent header there, so set
- * LOG_NEWFILE so the right stuff happens in the bowels of log_put.
- * Note that we could dispense with LOG_NEWFILE by simply relying upon
- * the log system to decide to switch files at the same time the
- * master did--lg_max should be the same in both places--but this is
- * scary.
- */
-#define        CHANGE_FILES do {                                               \
-       if (!(lp->ready_lsn.file == 1 && lp->ready_lsn.offset == 0)) {  \
-               lp->ready_lsn.file++;                                   \
-               F_SET(lp, LOG_NEWFILE);                                 \
-       }                                                               \
-       lp->ready_lsn.offset = sizeof(struct __log_persist) +           \
-           sizeof(struct __hdr);                                       \
-       /* Make this evaluate to a simple rectype. */                   \
-       rectype = 0;                                                    \
-} while (0)
+#define        IS_SIMPLE(R)    ((R) != DB___txn_regop && \
+    (R) != DB___txn_ckp && (R) != DB___dbreg_register)
 
 /*
  * __rep_process_message --
@@ -82,19 +50,21 @@ __rep_process_message(dbenv, control, rec, eidp)
        DBT *control, *rec;
        int *eidp;
 {
-       DBT *d, data_dbt, lsndbt, mylog;
        DB_LOG *dblp;
        DB_LOGC *logc;
-       DB_LSN lsn, newfilelsn, oldfilelsn;
+       DB_LSN init_lsn, lsn, newfilelsn, oldfilelsn;
        DB_REP *db_rep;
+       DBT *d, data_dbt, lsndbt, mylog;
        LOG *lp;
        REP *rep;
        REP_CONTROL *rp;
        REP_VOTE_INFO *vi;
-       u_int32_t gen, type;
-       int done, i, master, old, recovering, ret, t_ret, *tally;
+       u_int32_t bytes, gen, gbytes, type, unused;
+       int check_limit, cmp, done, do_req, i;
+       int master, old, recovering, ret, t_ret, *tally;
 
        PANIC_CHECK(dbenv);
+       ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "rep_stat", DB_INIT_TXN);
 
        /* Control argument must be non-Null. */
        if (control == NULL || control->size == 0) {
@@ -109,17 +79,19 @@ __rep_process_message(dbenv, control, rec, eidp)
        dblp = dbenv->lg_handle;
        lp = dblp->reginfo.primary;
 
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        gen = rep->gen;
        recovering = F_ISSET(rep, REP_F_RECOVER);
+
+       rep->stat.st_msgs_processed++;
        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
-       /*
-        * dbenv->rep_db is the handle for the repository used for applying log
-        * records.
-        */
        rp = (REP_CONTROL *)control->data;
 
+#if 0
+       __rep_print_message(rep->eid, rp, "rep_process_message");
+#endif
+
        /* Complain if we see an improper version number. */
        if (rp->rep_version != DB_REPVERSION) {
                __db_err(dbenv,
@@ -136,13 +108,17 @@ __rep_process_message(dbenv, control, rec, eidp)
 
        /*
         * Check for generation number matching.  Ignore any old messages
-        * except requests for ALIVE since the sender needs those to
-        * sync back up.  If the message is newer, then we are out of
-        * sync and need to catch up with the rest of the system.
+        * except requests that are indicative of a new client that needs
+        * to get in sync.
         */
        if (rp->gen < gen && rp->rectype != REP_ALIVE_REQ &&
-           rp->rectype != REP_NEWCLIENT)
+           rp->rectype != REP_NEWCLIENT && rp->rectype != REP_MASTER_REQ) {
+               /*
+                * We don't hold the rep mutex, and could miscount if we race.
+                */
+               rep->stat.st_msgs_badgen++;
                return (0);
+       }
        if (rp->gen > gen && rp->rectype != REP_ALIVE &&
            rp->rectype != REP_NEWMASTER)
                return (__rep_send_message(dbenv,
@@ -163,11 +139,39 @@ __rep_process_message(dbenv, control, rec, eidp)
                        case REP_NEWMASTER:
                        case REP_NEWSITE:
                        case REP_VERIFY:
+                               R_LOCK(dbenv, &dblp->reginfo);
+                               cmp = log_compare(&lp->verify_lsn, &rp->lsn);
+                               R_UNLOCK(dbenv, &dblp->reginfo);
+                               if (cmp != 0)
+                                       goto skip;
+                               /* FALLTHROUGH */
                        case REP_VOTE1:
                        case REP_VOTE2:
                                break;
                        default:
-                               return (0);
+skip:                          /*
+                                * We don't hold the rep mutex, and could
+                                * miscount if we race.
+                                */
+                               rep->stat.st_msgs_recover++;
+
+                               /* Check for need to retransmit. */
+                               R_LOCK(dbenv, &dblp->reginfo);
+                               do_req = *eidp == rep->master_id &&
+                                   ++lp->rcvd_recs >= lp->wait_recs;
+                               if (do_req) {
+                                       lp->wait_recs *= 2;
+                                       if (lp->wait_recs + rep->max_gap)
+                                               lp->wait_recs = rep->max_gap;
+                                       lp->rcvd_recs = 0;
+                                       lsn = lp->verify_lsn;
+                               }
+                               R_UNLOCK(dbenv, &dblp->reginfo);
+                               if (do_req)
+                                       ret = __rep_send_message(dbenv, *eidp,
+                                           REP_VERIFY_REQ, &lsn, NULL, 0);
+
+                               return (ret);
                }
 
        switch(rp->rectype) {
@@ -187,12 +191,19 @@ __rep_process_message(dbenv, control, rec, eidp)
                    F_ISSET(dbenv, DB_ENV_REP_MASTER) ? 1 : 0));
        case REP_ALL_REQ:
                MASTER_ONLY(dbenv);
+               gbytes  = bytes = 0;
+               MUTEX_LOCK(dbenv, db_rep->mutexp);
+               gbytes = rep->gbytes;
+               bytes = rep->bytes;
+               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+               check_limit = gbytes != 0 || bytes != 0;
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
-                       goto err;
+                       return (ret);
                memset(&data_dbt, 0, sizeof(data_dbt));
                oldfilelsn = lsn = rp->lsn;
+               type = REP_LOG;
                for (ret = logc->get(logc, &rp->lsn, &data_dbt, DB_SET);
-                   ret == 0;
+                   ret == 0 && type == REP_LOG;
                    ret = logc->get(logc, &lsn, &data_dbt, DB_NEXT)) {
                        /*
                         * lsn.offset will only be 0 if this is the
@@ -226,8 +237,35 @@ __rep_process_message(dbenv, control, rec, eidp)
                                            &lsndbt, 0)) != 0)
                                                break;
                                }
-                               ret = __rep_send_message(dbenv, *eidp,
-                                   REP_LOG, &lsn, &data_dbt, 0);
+                               if (check_limit) {
+                                       /*
+                                        * data_dbt.size is only the size of
+                                        * the log record;  it doesn't count
+                                        * the size of the control structure.
+                                        * Factor that in as well so we're
+                                        * not off by a lot if our log
+                                        * records are small.
+                                        */
+                                       while (bytes < data_dbt.size +
+                                           sizeof(REP_CONTROL)) {
+                                               if (gbytes > 0) {
+                                                       bytes += GIGABYTE;
+                                                       --gbytes;
+                                                       continue;
+                                               }
+                                               /*
+                                                * We don't hold the rep mutex,
+                                                * and may miscount.
+                                                */
+                                               rep->stat.st_nthrottles++;
+                                               type = REP_LOG_MORE;
+                                               goto send;
+                                       }
+                                       bytes -= (data_dbt.size +
+                                           sizeof(REP_CONTROL));
+                               }
+send:                          ret = __rep_send_message(dbenv, *eidp,
+                                   type, &lsn, &data_dbt, 0);
                        }
 
                        /*
@@ -250,7 +288,7 @@ __rep_process_message(dbenv, control, rec, eidp)
                        return (__rep_send_message(dbenv,
                            *eidp, REP_NEWMASTER, &lsn, NULL, 0));
                }
-               MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+               MUTEX_LOCK(dbenv, db_rep->mutexp);
                ret = IN_ELECTION(rep) ? 0 : DB_REP_HOLDELECTION;
                MUTEX_UNLOCK(dbenv, db_rep->mutexp);
                return (ret);
@@ -264,33 +302,55 @@ __rep_process_message(dbenv, control, rec, eidp)
                break;
 #endif
        case REP_LOG:
+       case REP_LOG_MORE:
                CLIENT_ONLY(dbenv);
-               return (__rep_apply(dbenv, rp, rec));
+               if ((ret = __rep_apply(dbenv, rp, rec)) != 0)
+                       return (ret);
+               if (rp->rectype == REP_LOG_MORE) {
+                       MUTEX_LOCK(dbenv, db_rep->db_mutexp);
+                       master = rep->master_id;
+                       MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+                       R_LOCK(dbenv, &dblp->reginfo);
+                       lsn = lp->lsn;
+                       R_UNLOCK(dbenv, &dblp->reginfo);
+                       ret = __rep_send_message(dbenv, master,
+                           REP_ALL_REQ, &lsn, NULL, 0);
+               }
+               return (ret);
        case REP_LOG_REQ:
                MASTER_ONLY(dbenv);
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
-                       goto err;
+                       return (ret);
                memset(&data_dbt, 0, sizeof(data_dbt));
                lsn = rp->lsn;
-               if ((ret = logc->get(logc, &rp->lsn, &data_dbt, DB_SET)) == 0) {
-                       /*
-                        * If the log file has changed, we may get back a
-                        * log record with a later LSN than we requested.
-                        * This most likely means that the log file
-                        * changed, so we need to send a NEWFILE message.
-                        */
-                       if (log_compare(&lsn, &rp->lsn) < 0 &&
-                           rp->lsn.offset == 0)
-                               ret = __rep_send_message(dbenv, *eidp,
-                                   REP_NEWFILE, &lsn, NULL, 0);
-                       else
-                               ret = __rep_send_message(dbenv, *eidp,
+
+               /*
+                * There are three different cases here.
+                * 1. We asked for a particular LSN and got it.
+                * 2. We asked for an LSN of X,0 which is invalid and got the
+                *      first log record in a particular file.
+                * 3. We asked for an LSN and it's not found because it is
+                *      beyond the end of a log file and we need a NEWFILE msg.
+                */
+               ret = logc->get(logc, &rp->lsn, &data_dbt, DB_SET);
+               cmp = log_compare(&lsn, &rp->lsn);
+
+               if (ret == 0 && cmp == 0) /* Case 1 */
+                       ret = __rep_send_message(dbenv, *eidp,
                                    REP_LOG, &rp->lsn, &data_dbt, 0);
-               }
+               else if (ret == DB_NOTFOUND ||
+                   (ret == 0 && cmp < 0 && rp->lsn.offset == 0))
+                       /* Cases 2 and 3: Send a NEWFILE message. */
+                       ret = __rep_send_message(dbenv, *eidp,
+                           REP_NEWFILE, &lsn, NULL, 0);
+
                if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        ret = t_ret;
                return (ret);
        case REP_NEWSITE:
+               /* We don't hold the rep mutex, and may miscount. */
+               rep->stat.st_newsites++;
+
                /* This is a rebroadcast; simply tell the application. */
                if (F_ISSET(dbenv, DB_ENV_REP_MASTER)) {
                        dblp = dbenv->lg_handle;
@@ -312,14 +372,16 @@ __rep_process_message(dbenv, control, rec, eidp)
                 */
                if ((ret = __rep_send_message(dbenv,
                    DB_EID_BROADCAST, REP_NEWSITE, &rp->lsn, rec, 0)) != 0)
-                       goto err;
+                       return (ret);
 
                if (F_ISSET(dbenv, DB_ENV_REP_CLIENT))
                        return (0);
 
                 /* FALLTHROUGH */
        case REP_MASTER_REQ:
-               MASTER_ONLY(dbenv);
+               ANYSITE(dbenv);
+               if (F_ISSET(dbenv, DB_ENV_REP_CLIENT))
+                       return (0);
                dblp = dbenv->lg_handle;
                lp = dblp->reginfo.primary;
                R_LOCK(dbenv, &dblp->reginfo);
@@ -333,8 +395,11 @@ __rep_process_message(dbenv, control, rec, eidp)
        case REP_NEWMASTER:
                ANYSITE(dbenv);
                if (F_ISSET(dbenv, DB_ENV_REP_MASTER) &&
-                   *eidp != dbenv->rep_eid)
+                   *eidp != dbenv->rep_eid) {
+                       /* We don't hold the rep mutex, and may miscount. */
+                       rep->stat.st_dupmasters++;
                        return (DB_REP_DUPMASTER);
+               }
                return (__rep_new_master(dbenv, rp, *eidp));
        case REP_PAGE: /* TODO */
                CLIENT_ONLY(dbenv);
@@ -350,36 +415,109 @@ __rep_process_message(dbenv, control, rec, eidp)
                break;
        case REP_VERIFY:
                CLIENT_ONLY(dbenv);
+               DB_ASSERT((F_ISSET(rep, REP_F_RECOVER) &&
+                   !IS_ZERO_LSN(lp->verify_lsn)) ||
+                   (!F_ISSET(rep, REP_F_RECOVER) &&
+                   IS_ZERO_LSN(lp->verify_lsn)));
+               if (IS_ZERO_LSN(lp->verify_lsn))
+                       return (0);
+
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
-                       goto err;
+                       return (ret);
                memset(&mylog, 0, sizeof(mylog));
                if ((ret = logc->get(logc, &rp->lsn, &mylog, DB_SET)) != 0)
                        goto rep_verify_err;
-               db_rep = dbenv->rep_handle;
-               rep = db_rep->region;
                if (mylog.size == rec->size &&
                    memcmp(mylog.data, rec->data, rec->size) == 0) {
-                       ret = __db_apprec(dbenv, &rp->lsn, 0);
-                       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+                       /*
+                        * If we're a logs-only client, we can simply truncate
+                        * the log to the point where it last agreed with the
+                        * master's;  otherwise, recover to that point.
+                        */
+                       R_LOCK(dbenv, &dblp->reginfo);
+                       ZERO_LSN(lp->verify_lsn);
+                       R_UNLOCK(dbenv, &dblp->reginfo);
+                       if (F_ISSET(dbenv, DB_ENV_REP_LOGSONLY)) {
+                               INIT_LSN(init_lsn);
+                               if ((ret = dbenv->log_flush(dbenv,
+                                   &rp->lsn)) != 0 ||
+                                   (ret = __log_vtruncate(dbenv,
+                                   &rp->lsn, &init_lsn)) != 0)
+                                       goto rep_verify_err;
+                       } else if ((ret = __db_apprec(dbenv, &rp->lsn, 0)) != 0)
+                               goto rep_verify_err;
+
+                       /*
+                        * The log has been truncated (either by __db_apprec or
+                        * directly).  We want to make sure we're waiting for
+                        * the LSN at the new end-of-log, not some later point.
+                        */
+                       R_LOCK(dbenv, &dblp->reginfo);
+                       lp->ready_lsn = lp->lsn;
+                       ZERO_LSN(lp->waiting_lsn);
+                       R_UNLOCK(dbenv, &dblp->reginfo);
+
+                       /*
+                        * Discard any log records we have queued;  we're
+                        * about to re-request them, and can't trust the
+                        * ones in the queue.
+                        */
+                       MUTEX_LOCK(dbenv, db_rep->db_mutexp);
+                       if ((ret = db_rep->rep_db->truncate(db_rep->rep_db,
+                           NULL, &unused, 0)) != 0) {
+                               MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+                               goto rep_verify_err;
+                       }
+                       rep->stat.st_log_queued = 0;
+                       MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+
+                       MUTEX_LOCK(dbenv, db_rep->mutexp);
                        F_CLR(rep, REP_F_RECOVER);
-                       MUTEX_UNLOCK(dbenv, db_rep->mutexp);
-                       ret = __rep_send_message(dbenv, rep->master_id,
-                           REP_ALL_REQ, &rp->lsn, NULL, 0);
-               } else if ((ret = logc->get(logc, &lsn, &mylog, DB_PREV)) == 0)
+
+                       /*
+                        * If the master_id is invalid, this means that since
+                        * the last record was sent, somebody declared an
+                        * election and we may not have a master to request
+                        * things of.
+                        *
+                        * This is not an error;  when we find a new master,
+                        * we'll re-negotiate where the end of the log is and
+                        * try to bring ourselves up to date again anyway.
+                        */
+                       if ((master = rep->master_id) == DB_EID_INVALID) {
+                               DB_ASSERT(IN_ELECTION(rep));
+                               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+                               ret = 0;
+                       } else {
+                               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+                               ret = __rep_send_message(dbenv, master,
+                                   REP_ALL_REQ, &rp->lsn, NULL, 0);
+                       }
+               } else if ((ret =
+                   logc->get(logc, &lsn, &mylog, DB_PREV)) == 0) {
+                       R_LOCK(dbenv, &dblp->reginfo);
+                       lp->verify_lsn = lsn;
+                       lp->rcvd_recs = 0;
+                       lp->wait_recs = rep->request_gap;
+                       R_UNLOCK(dbenv, &dblp->reginfo);
                        ret = __rep_send_message(dbenv,
                            *eidp, REP_VERIFY_REQ, &lsn, NULL, 0);
+               }
+
 rep_verify_err:        if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        ret = t_ret;
-               goto err;
+               return (ret);
        case REP_VERIFY_FAIL:
+               rep->stat.st_outdated++;
                return (DB_REP_OUTDATED);
        case REP_VERIFY_REQ:
                MASTER_ONLY(dbenv);
                type = REP_VERIFY;
                if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
-                       goto err;
+                       return (ret);
                d = &data_dbt;
                memset(d, 0, sizeof(data_dbt));
+               F_SET(logc, DB_LOG_SILENT_ERR);
                ret = logc->get(logc, &rp->lsn, d, DB_SET);
                /*
                 * If the LSN was invalid, then we might get a not
@@ -400,7 +538,7 @@ rep_verify_err:     if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                ret = __rep_send_message(dbenv, *eidp, type, &rp->lsn, d, 0);
                if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        ret = t_ret;
-               goto err;
+               return (ret);
        case REP_VOTE1:
                if (F_ISSET(dbenv, DB_ENV_REP_MASTER)) {
 #ifdef DIAGNOSTIC
@@ -415,7 +553,7 @@ rep_verify_err:     if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                }
 
                vi = (REP_VOTE_INFO *)rec->data;
-               MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+               MUTEX_LOCK(dbenv, db_rep->mutexp);
 
                /*
                 * If you get a vote and you're not in an election, simply
@@ -462,7 +600,8 @@ rep_verify_err:     if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
 
                /*
                 * Change winners if the incoming record has a higher
-                * priority, or an equal priority but a larger LSN.
+                * priority, or an equal priority but a larger LSN, or
+                * an equal priority and LSN but higher "tiebreaker" value.
                 */
 #ifdef DIAGNOSTIC
                if (FLD_ISSET(dbenv->verbose, DB_VERB_REPLICATION)) {
@@ -476,10 +615,12 @@ rep_verify_err:   if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                            rp->lsn.offset);
                }
 #endif
+               cmp = log_compare(&rp->lsn, &rep->w_lsn);
                if (vi->priority > rep->w_priority ||
                    (vi->priority != 0 && vi->priority == rep->w_priority &&
-                   log_compare(&rp->lsn, &rep->w_lsn) > 0)) {
-#ifdef DIABNOSTIC
+                   (cmp > 0 ||
+                   (cmp == 0 && vi->tiebreaker > rep->w_tiebreaker)))) {
+#ifdef DIAGNOSTIC
                        if (FLD_ISSET(dbenv->verbose, DB_VERB_REPLICATION))
                                __db_err(dbenv, "Accepting new vote");
 #endif
@@ -528,11 +669,12 @@ rep_verify_err:   if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        R_LOCK(dbenv, &dblp->reginfo);
                        lsn = lp->lsn;
                        R_UNLOCK(dbenv, &dblp->reginfo);
+                       rep->stat.st_elections_won++;
                        return (__rep_send_message(dbenv,
                            *eidp, REP_NEWMASTER, &lsn, NULL, 0));
                }
 
-               MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+               MUTEX_LOCK(dbenv, db_rep->mutexp);
 
                /* If we have priority 0, we should never get a vote. */
                DB_ASSERT(rep->priority != 0);
@@ -573,6 +715,7 @@ rep_verify_err:     if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        if (FLD_ISSET(dbenv->verbose, DB_VERB_REPLICATION))
                                __db_err(dbenv, "I won, sending NEWMASTER");
 #endif
+                       rep->stat.st_elections_won++;
                        if ((ret = __rep_send_message(dbenv, DB_EID_BROADCAST,
                            REP_NEWMASTER, &lsn, NULL, 0)) != 0)
                                break;
@@ -589,7 +732,7 @@ rep_verify_err:     if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
        return (0);
 
 unlock:        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
-err:   return (ret);
+       return (ret);
 }
 
 /*
@@ -606,24 +749,27 @@ __rep_apply(dbenv, rp, rec)
        REP_CONTROL *rp;
        DBT *rec;
 {
+       __dbreg_register_args dbreg_args;
        __txn_ckp_args ckp_args;
        DB_REP *db_rep;
-       DBT data_dbt, key_dbt;
+       DBT control_dbt, key_dbt, lsn_dbt, nextrec_dbt, rec_dbt;
        DB *dbp;
        DBC *dbc;
        DB_LOG *dblp;
-       DB_LSN ckp_lsn, lsn, next_lsn;
+       DB_LSN ckp_lsn, lsn, newfile_lsn, next_lsn, waiting_lsn;
        LOG *lp;
-       int cmp, eid, ret, retry_count, t_ret;
-       u_int32_t rectype;
+       REP *rep;
+       REP_CONTROL lsn_rc;
+       u_int32_t rectype, txnid;
+       int cmp, do_req, eid, have_mutex, newfile, ret, t_ret;
 
        db_rep = dbenv->rep_handle;
+       rep = db_rep->region;
        dbp = db_rep->rep_db;
        dbc = NULL;
-       ret = 0;
-       retry_count = 0;
-       memset(&key_dbt, 0, sizeof(key_dbt));
-       memset(&data_dbt, 0, sizeof(data_dbt));
+       have_mutex = newfile = ret = 0;
+       memset(&control_dbt, 0, sizeof(control_dbt));
+       memset(&rec_dbt, 0, sizeof(rec_dbt));
 
        /*
         * If this is a log record and it's the next one in line, simply
@@ -651,12 +797,23 @@ __rep_apply(dbenv, rp, rec)
         * log mutex, so the synchronization here is tricky.
         */
        if (cmp == 0) {
+               /* We got the log record that we are expecting. */
                if (rp->rectype == REP_NEWFILE) {
-newfile:               CHANGE_FILES;
+newfile:               ret = __rep_newfile(dbenv, rp, rec, &lp->ready_lsn);
+
+                       /* Make this evaluate to a simple rectype. */
+                       rectype = 0;
                } else {
-                       ret = __log_put_int(dbenv, &rp->lsn, rec, rp->flags);
+                       DB_ASSERT(log_compare(&rp->lsn, &lp->lsn) == 0);
+                       ret = __log_rep_put(dbenv, &rp->lsn, rec);
                        lp->ready_lsn = lp->lsn;
                        memcpy(&rectype, rec->data, sizeof(rectype));
+                       if (ret == 0)
+                               /*
+                                * We may miscount if we race, since we
+                                * don't currently hold the rep mutex.
+                                */
+                               rep->stat.st_log_records++;
                }
                while (ret == 0 && IS_SIMPLE(rectype) &&
                    log_compare(&lp->ready_lsn, &lp->waiting_lsn) == 0) {
@@ -664,14 +821,26 @@ newfile:          CHANGE_FILES;
                         * We just filled in a gap in the log record stream.
                         * Write subsequent records to the log.
                         */
-gap_check:             R_UNLOCK(dbenv, &dblp->reginfo);
-                       if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
+gap_check:             lp->wait_recs = 0;
+                       lp->rcvd_recs = 0;
+                       R_UNLOCK(dbenv, &dblp->reginfo);
+                       if (have_mutex == 0) {
+                               MUTEX_LOCK(dbenv, db_rep->db_mutexp);
+                               have_mutex = 1;
+                       }
+                       if (dbc == NULL &&
+                           (ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
                                goto err;
+
+                       /* The DBTs need to persist through another call. */
+                       F_SET(&control_dbt, DB_DBT_REALLOC);
+                       F_SET(&rec_dbt, DB_DBT_REALLOC);
                        if ((ret = dbc->c_get(dbc,
-                           &key_dbt, &data_dbt, DB_RMW | DB_FIRST)) != 0)
+                           &control_dbt, &rec_dbt, DB_RMW | DB_FIRST)) != 0)
                                goto err;
-                       rp = (REP_CONTROL *)key_dbt.data;
-                       rec = &data_dbt;
+
+                       rp = (REP_CONTROL *)control_dbt.data;
+                       rec = &rec_dbt;
                        memcpy(&rectype, rec->data, sizeof(rectype));
                        R_LOCK(dbenv, &dblp->reginfo);
                        /*
@@ -681,41 +850,195 @@ gap_check:               R_UNLOCK(dbenv, &dblp->reginfo);
                         */
                        if (log_compare(&lp->ready_lsn, &rp->lsn) == 0) {
                                if (rp->rectype != REP_NEWFILE) {
-                                       ret = __log_put_int(dbenv,
-                                           &rp->lsn, &data_dbt, rp->flags);
+                                       DB_ASSERT(log_compare
+                                           (&rp->lsn, &lp->lsn) == 0);
+                                       ret = __log_rep_put(dbenv,
+                                           &rp->lsn, rec);
                                        lp->ready_lsn = lp->lsn;
-                               } else
-                                       CHANGE_FILES;
+
+                                       /*
+                                        * We may miscount if we race, since we
+                                        * don't currently hold the rep mutex.
+                                        */
+                                       if (ret == 0)
+                                               rep->stat.st_log_records++;
+                               } else {
+                                       ret = __rep_newfile(dbenv,
+                                           rp, rec, &lp->ready_lsn);
+                                       rectype = 0;
+                               }
+                               waiting_lsn = lp->waiting_lsn;
                                R_UNLOCK(dbenv, &dblp->reginfo);
                                if ((ret = dbc->c_del(dbc, 0)) != 0)
                                        goto err;
 
                                /*
-                                * If the current rectype is simple, we're
-                                * ready for another record;  otherwise,
-                                * don't get one, because we need to
-                                * process the current one now.
+                                * We may miscount, as we don't hold the rep
+                                * mutex.
                                 */
-                               if (IS_SIMPLE(rectype)) {
-                                       ret = dbc->c_get(dbc,
-                                           &key_dbt, &data_dbt, DB_NEXT);
-                                       if (ret != DB_NOTFOUND && ret != 0)
-                                               goto err;
-                                       lsn =
-                                           ((REP_CONTROL *)key_dbt.data)->lsn;
-                                       if ((ret = dbc->c_close(dbc)) != 0)
-                                               goto err;
-                                       R_LOCK(dbenv, &dblp->reginfo);
-                                       if (ret == DB_NOTFOUND) {
-                                               ZERO_LSN(lp->waiting_lsn);
-                                               break;
-                                       } else
-                                               lp->waiting_lsn = lsn;
-                               } else {
-                                       R_LOCK(dbenv, &dblp->reginfo);
-                                       lp->waiting_lsn = lp->ready_lsn;
+                               --rep->stat.st_log_queued;
+
+                               /*
+                                * Update waiting_lsn.  We need to move it
+                                * forward to the LSN of the next record
+                                * in the queue.
+                                */
+                               memset(&lsn_dbt, 0, sizeof(lsn_dbt));
+                               F_SET(&lsn_dbt, DB_DBT_USERMEM);
+                               lsn_dbt.data = &lsn_rc;
+                               lsn_dbt.ulen = sizeof(lsn_rc);
+                               memset(&lsn_rc, 0, sizeof(lsn_rc));
+
+                               /*
+                                * If the next item in the database is a log
+                                * record--the common case--we're not
+                                * interested in its contents, just in its LSN.
+                                * If it's a newfile message, though, the
+                                * data field may be the LSN of the last
+                                * record in the old file, and we need to use
+                                * that to determine whether or not there's
+                                * a gap.
+                                *
+                                * Optimize both these cases by doing a partial
+                                * get of the data item.  If it's a newfile
+                                * record, we'll get the whole LSN, and if
+                                * it's not, we won't waste time allocating.
+                                */
+                               memset(&nextrec_dbt, 0, sizeof(nextrec_dbt));
+                               F_SET(&nextrec_dbt,
+                                   DB_DBT_USERMEM | DB_DBT_PARTIAL);
+                               nextrec_dbt.ulen =
+                                   nextrec_dbt.dlen = sizeof(newfile_lsn);
+                               ZERO_LSN(newfile_lsn);
+                               nextrec_dbt.data = &newfile_lsn;
+
+                               ret = dbc->c_get(dbc,
+                                   &lsn_dbt, &nextrec_dbt, DB_NEXT);
+                               if (ret != DB_NOTFOUND && ret != 0)
+                                       goto err;
+
+                               R_LOCK(dbenv, &dblp->reginfo);
+                               if (ret == DB_NOTFOUND) {
+                                       /*
+                                        * Do a quick double-check to make
+                                        * sure waiting_lsn hasn't changed.
+                                        * It's possible that between the
+                                        * DB_NOTFOUND return and the R_LOCK,
+                                        * some record was added to the
+                                        * database, and we don't want to lose
+                                        * sight of the fact that it's there.
+                                        */
+                                       if (log_compare(&waiting_lsn,
+                                           &lp->waiting_lsn) == 0)
+                                               ZERO_LSN(
+                                                   lp->waiting_lsn);
+
+                                       /*
+                                        * Whether or not the current record is
+                                        * simple, there's no next one, and
+                                        * therefore we haven't got anything
+                                        * else to do right now.  Break out.
+                                        */
                                        break;
                                }
+
+                               DB_ASSERT(lsn_dbt.size == sizeof(lsn_rc));
+
+                               /*
+                                * NEWFILE records have somewhat convoluted
+                                * semantics, so there are five cases
+                                * pertaining to what the newly-gotten record
+                                * is and what we want to do about it.
+                                *
+                                * 1) This isn't a NEWFILE record.  Advance
+                                *    waiting_lsn and proceed.
+                                *
+                                * 2) NEWFILE, no LSN stored as the datum,
+                                *    lsn_rc.lsn == ready_lsn.  The NEWFILE
+                                *    record is next, so set waiting_lsn =
+                                *    ready_lsn.
+                                *
+                                * 3) NEWFILE, no LSN stored as the datum, but
+                                *    lsn_rc.lsn > ready_lsn.  There's still a
+                                *    gap; set waiting_lsn = lsn_rc.lsn.
+                                *
+                                * 4) NEWFILE, newfile_lsn in datum, and it's <
+                                *    ready_lsn. (If the datum is non-empty,
+                                *    it's the LSN of the last record in a log
+                                *    file, not the end of the log, and
+                                *    lsn_rc.lsn is the LSN of the start of
+                                *    the new file--we didn't have the end of
+                                *    the old log handy when we sent the
+                                *    record.)  No gap--we're ready to
+                                *    proceed.  Set both waiting and ready_lsn
+                                *    to lsn_rc.lsn.
+                                *
+                                * 5) NEWFILE, newfile_lsn in datum, and it's >=
+                                *    ready_lsn.  We're still missing at
+                                *    least one record;  set waiting_lsn,
+                                *    but not ready_lsn, to lsn_rc.lsn.
+                                */
+                               if (lsn_rc.rectype == REP_NEWFILE &&
+                                   nextrec_dbt.size > 0 && log_compare(
+                                   &newfile_lsn, &lp->ready_lsn) < 0)
+                                       /* Case 4. */
+                                       lp->ready_lsn =
+                                           lp->waiting_lsn = lsn_rc.lsn;
+                               else {
+                                       /* Cases 1, 2, 3, and 5. */
+                                       DB_ASSERT(log_compare(&lsn_rc.lsn,
+                                           &lp->ready_lsn) >= 0);
+                                       lp->waiting_lsn = lsn_rc.lsn;
+                               }
+
+                               /*
+                                * If the current rectype is simple, we're
+                                * done with it, and we should check and see
+                                * whether the next record queued is the next
+                                * one we're ready for.  This is just the loop
+                                * condition, so we continue.
+                                *
+                                * Otherwise, we need to break out of this loop
+                                * and process this record first.
+                                */
+                               if (!IS_SIMPLE(rectype))
+                                       break;
+                       }
+               }
+
+               /*
+                * Check if we're at a gap in the table and if so, whether we
+                * need to ask for any records.
+                */
+               do_req = 0;
+               if (!IS_ZERO_LSN(lp->waiting_lsn) &&
+                   log_compare(&lp->ready_lsn, &lp->waiting_lsn) != 0) {
+                       next_lsn = lp->ready_lsn;
+                       do_req = ++lp->rcvd_recs >= lp->wait_recs;
+                       if (do_req) {
+                               lp->wait_recs = rep->request_gap;
+                               lp->rcvd_recs = 0;
+                       }
+               }
+
+               R_UNLOCK(dbenv, &dblp->reginfo);
+               if (dbc != NULL) {
+                       if ((ret = dbc->c_close(dbc)) != 0)
+                               goto err;
+                       MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+                       have_mutex = 0;
+               }
+               dbc = NULL;
+
+               if (do_req) {
+                       MUTEX_LOCK(dbenv, db_rep->mutexp);
+                       eid = db_rep->region->master_id;
+                       MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+                       if (eid != DB_EID_INVALID) {
+                               rep->stat.st_log_requested++;
+                               if ((ret = __rep_send_message(dbenv,
+                                   eid, REP_LOG_REQ, &next_lsn, NULL, 0)) != 0)
+                                       goto err;
                        }
                }
        } else if (cmp > 0) {
@@ -749,61 +1072,143 @@ gap_check:              R_UNLOCK(dbenv, &dblp->reginfo);
                 * This record isn't in sequence; add it to the table and
                 * update waiting_lsn if necessary.
                 */
+               memset(&key_dbt, 0, sizeof(key_dbt));
                key_dbt.data = rp;
                key_dbt.size = sizeof(*rp);
                next_lsn = lp->lsn;
+               do_req = 0;
+               if (lp->wait_recs == 0) {
+                       /*
+                        * This is a new gap. Initialize the number of
+                        * records that we should wait before requesting
+                        * that it be resent.  We grab the limits out of
+                        * the rep without the mutex.
+                        */
+                       lp->wait_recs = rep->request_gap;
+                       lp->rcvd_recs = 0;
+               }
+
+               if (++lp->rcvd_recs >= lp->wait_recs) {
+                       /*
+                        * If we've waited long enough, request the record
+                        * and double the wait interval.
+                        */
+                       do_req = 1;
+                       lp->wait_recs <<= 1;
+                       lp->rcvd_recs = 0;
+                       if (lp->wait_recs > rep->max_gap)
+                               lp->wait_recs = rep->max_gap;
+               }
                R_UNLOCK(dbenv, &dblp->reginfo);
+
+               MUTEX_LOCK(dbenv, db_rep->db_mutexp);
                ret = dbp->put(dbp, NULL, &key_dbt, rec, 0);
+               rep->stat.st_log_queued++;
+               rep->stat.st_log_queued_total++;
+               if (rep->stat.st_log_queued_max < rep->stat.st_log_queued)
+                       rep->stat.st_log_queued_max = rep->stat.st_log_queued;
+               MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+
+               if (ret != 0)
+                       return (ret);
 
-               /* Request the LSN we are still waiting for. */
-               MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
-               eid = db_rep->region->master_id;
-               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
-               ret = __rep_send_message(dbenv, eid, REP_LOG_REQ,
-                   &next_lsn, NULL, 0);
                R_LOCK(dbenv, &dblp->reginfo);
-               if (ret == 0)
-                       if (IS_ZERO_LSN(lp->waiting_lsn) ||
-                           log_compare(&rp->lsn, &lp->waiting_lsn) < 0)
-                               lp->waiting_lsn = rp->lsn;
+               if (IS_ZERO_LSN(lp->waiting_lsn) ||
+                   log_compare(&rp->lsn, &lp->waiting_lsn) < 0)
+                       lp->waiting_lsn = rp->lsn;
                R_UNLOCK(dbenv, &dblp->reginfo);
+
+               if (do_req) {
+                       /* Request the LSN we are still waiting for. */
+                       MUTEX_LOCK(dbenv, db_rep->mutexp);
+
+                       /* May as well do this after we grab the mutex. */
+                       eid = db_rep->region->master_id;
+
+                       /*
+                        * If the master_id is invalid, this means that since
+                        * the last record was sent, somebody declared an
+                        * election and we may not have a master to request
+                        * things of.
+                        *
+                        * This is not an error;  when we find a new master,
+                        * we'll re-negotiate where the end of the log is and
+                        * try to to bring ourselves up to date again anyway.
+                        */
+                       if (eid != DB_EID_INVALID) {
+                               rep->stat.st_log_requested++;
+                               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+                               ret = __rep_send_message(dbenv,
+                                   eid, REP_LOG_REQ, &next_lsn, NULL, 0);
+                       } else
+                               MUTEX_UNLOCK(dbenv, db_rep->mutexp);
+               }
                return (ret);
+       } else {
+               R_UNLOCK(dbenv, &dblp->reginfo);
+
+               /*
+                * We may miscount if we race, since we
+                * don't currently hold the rep mutex.
+                */
+               rep->stat.st_log_duplicated++;
        }
-       R_UNLOCK(dbenv, &dblp->reginfo);
-       if (ret != 0 || cmp < 0 || (cmp == 0 &&  IS_SIMPLE(rectype)))
-               return (ret);
+       if (ret != 0 || cmp < 0 || (cmp == 0 && IS_SIMPLE(rectype)))
+               goto done;
 
        /*
         * If we got here, then we've got a log record in rp and rec that
         * we need to process.
         */
        switch(rectype) {
-       case DB_txn_ckp:
-               /* Sync the memory pool and write the log record. */
+       case DB___dbreg_register:
+               /*
+                * DB opens occur in the context of a transaction, so we can
+                * simply handle them when we process the transaction.  Closes,
+                * however, are not transaction-protected, so we have to
+                * handle them here.
+                *
+                * Note that it should be unsafe for the master to do a close
+                * of a file that was opened in an active transaction, so we
+                * should be guaranteed to get the ordering right.
+                */
+               memcpy(&txnid, (u_int8_t *)rec->data +
+                   ((u_int8_t *)&dbreg_args.txnid - (u_int8_t *)&dbreg_args),
+                   sizeof(u_int32_t));
+               if (txnid == TXN_INVALID &&
+                   !F_ISSET(dbenv, DB_ENV_REP_LOGSONLY))
+                       ret = __db_dispatch(dbenv, dbenv->recover_dtab,
+                           dbenv->recover_dtab_size, rec, &rp->lsn,
+                           DB_TXN_APPLY, NULL);
+               break;
+       case DB___txn_ckp:
+               /* Sync the memory pool. */
                memcpy(&ckp_lsn, (u_int8_t *)rec->data +
                    ((u_int8_t *)&ckp_args.ckp_lsn - (u_int8_t *)&ckp_args),
                    sizeof(DB_LSN));
-retry:         if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY)) {
-                       ret = dbenv->memp_sync(dbenv, &ckp_lsn);
-                       if (ret == DB_INCOMPLETE && retry_count < 4) {
-                               (void)__os_sleep(dbenv, 1 << retry_count, 0);
-                               retry_count++;
-                               goto retry;
-                       }
-               }
-               if (ret == 0) {
-                       ret = dbenv->log_put(dbenv, &lsn, rec, rp->flags);
-               }
-               break;
-       case DB_log_register:
-               /* Simply redo the operation. */
                if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY))
-                       ret = __db_dispatch(dbenv,
-                           NULL, rec, &rp->lsn, DB_TXN_APPLY, NULL);
+                       ret = dbenv->memp_sync(dbenv, &ckp_lsn);
+               else
+                       /*
+                        * We ought to make sure the logs on a logs-only
+                        * replica get flushed now and again.
+                        */
+                       ret = dbenv->log_flush(dbenv, &ckp_lsn);
                break;
-       case DB_txn_regop:
+       case DB___txn_regop:
                if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY))
-                       ret = __rep_process_txn(dbenv, rec);
+                       do {
+                               /*
+                                * If an application is doing app-specific
+                                * recovery and acquires locks while applying
+                                * a transaction, it can deadlock.  Any other
+                                * locks held by this thread should have been
+                                * discarded in the __rep_process_txn error
+                                * path, so if we simply retry, we should
+                                * eventually succeed.
+                                */
+                               ret = __rep_process_txn(dbenv, rec);
+                       } while (ret == DB_LOCK_DEADLOCK);
                break;
        default:
                goto err;
@@ -817,8 +1222,16 @@ retry:            if (!F_ISSET(dbenv, DB_ENV_REP_LOGSONLY)) {
                R_UNLOCK(dbenv, &dblp->reginfo);
        }
 
+done:
 err:   if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
                ret = t_ret;
+       if (have_mutex)
+               MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
+
+       if (control_dbt.data != NULL)
+               __os_ufree(dbenv, control_dbt.data);
+       if (rec_dbt.data != NULL)
+               __os_ufree(dbenv, rec_dbt.data);
 
        return (ret);
 }
@@ -828,196 +1241,266 @@ err:   if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  *
  * This is the routine that actually gets a transaction ready for
  * processing.
+ *
+ * PUBLIC: int __rep_process_txn __P((DB_ENV *, DBT *));
  */
-static int
-__rep_process_txn(dbenv, commit_rec)
+int
+__rep_process_txn(dbenv, rec)
        DB_ENV *dbenv;
-       DBT *commit_rec;
+       DBT *rec;
 {
        DBT data_dbt;
        DB_LOCKREQ req, *lvp;
        DB_LOGC *logc;
-       DB_LSN prev_lsn;
-       LSN_PAGE *ap;
-       TXN_RECS recs;
+       DB_LSN prev_lsn, *lsnp;
+       DB_REP *db_rep;
+       LSN_COLLECTION lc;
+       REP *rep;
        __txn_regop_args *txn_args;
-       u_int32_t op;
+       __txn_xa_regop_args *prep_args;
+       u_int32_t lockid, op, rectype;
        int i, ret, t_ret;
        int (**dtab)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
        size_t dtabsize;
+       void *txninfo;
+
+       db_rep = dbenv->rep_handle;
+       rep = db_rep->region;
+
+       logc = NULL;
+       txninfo = NULL;
+       memset(&data_dbt, 0, sizeof(data_dbt));
+       if (F_ISSET(dbenv, DB_ENV_THREAD))
+               F_SET(&data_dbt, DB_DBT_REALLOC);
 
        /*
-        * There are three phases:  First, we have to traverse
+        * There are two phases:  First, we have to traverse
         * backwards through the log records gathering the list
-        * of all the pages accessed.  Once we have this information
-        * we can acquire all the locks we need.  Finally, we apply
-        * all the records in the transaction and release the locks.
+        * of all LSNs in the transaction.  Once we have this information,
+        * we can loop through, acquire the locks we need for each record,
+        * and then apply it.
         */
        dtab = NULL;
 
-       /* Make sure this is really a commit and not an abort! */
-       if ((ret = __txn_regop_read(dbenv, commit_rec->data, &txn_args)) != 0)
-               return (ret);
-       op = txn_args->opcode;
-       prev_lsn = txn_args->prev_lsn;
-       __os_free(dbenv, txn_args, 0);
-       if (op != TXN_COMMIT)
-               return (0);
+       /*
+        * We may be passed a prepare (if we're restoring a prepare
+        * on upgrade) instead of a commit (the common case).
+        * Check which and behave appropriately.
+        */
+       memcpy(&rectype, rec->data, sizeof(rectype));
+       memset(&lc, 0, sizeof(lc));
+       if (rectype == DB___txn_regop) {
+               /*
+                * We're the end of a transaction.  Make sure this is
+                * really a commit and not an abort!
+                */
+               if ((ret = __txn_regop_read(dbenv, rec->data, &txn_args)) != 0)
+                       return (ret);
+               op = txn_args->opcode;
+               prev_lsn = txn_args->prev_lsn;
+               __os_free(dbenv, txn_args);
+               if (op != TXN_COMMIT)
+                       return (0);
+       } else {
+               /* We're a prepare. */
+               DB_ASSERT(rectype == DB___txn_xa_regop);
+
+               if ((ret =
+                   __txn_xa_regop_read(dbenv, rec->data, &prep_args)) != 0)
+                       return (ret);
+               prev_lsn = prep_args->prev_lsn;
+               __os_free(dbenv, prep_args);
+       }
 
-       memset(&recs, 0, sizeof(recs));
-       recs.txnid = txn_args->txnid->txnid;
-       if ((ret = dbenv->lock_id(dbenv, &recs.lockid)) != 0)
+       /* Phase 1.  Get a list of the LSNs in this transaction, and sort it. */
+       if ((ret = __rep_collect_txn(dbenv, &prev_lsn, &lc)) != 0)
                return (ret);
+       qsort(lc.array, lc.nlsns, sizeof(DB_LSN), __rep_lsn_cmp);
+
+       if ((ret = dbenv->lock_id(dbenv, &lockid)) != 0)
+               goto err;
 
        /* Initialize the getpgno dispatch table. */
        if ((ret = __rep_lockpgno_init(dbenv, &dtab, &dtabsize)) != 0)
                goto err;
 
-       if ((ret = __rep_lockpages(dbenv,
-           dtab, NULL, &prev_lsn, &recs, recs.lockid)) != 0)
-               goto err;
-       if (recs.nalloc == 0)
+       /*
+        * The set of records for a transaction may include dbreg_register
+        * records.  Create a txnlist so that they can keep track of file
+        * state between records.
+        */
+       if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txninfo)) != 0)
                goto err;
 
-       /* Phase 3: Apply updates and release locks. */
+       /* Phase 2: Apply updates. */
        if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
                goto err;
-       memset(&data_dbt, 0, sizeof(data_dbt));
-       for (ap = &recs.array[0], i = 0; i < recs.npages; i++, ap++) {
-               if ((ret = logc->get(logc, &ap->lsn, &data_dbt, DB_SET)) != 0)
+       for (lsnp = &lc.array[0], i = 0; i < lc.nlsns; i++, lsnp++) {
+               if ((ret = __rep_lockpages(dbenv,
+                   dtab, dtabsize, lsnp, NULL, NULL, lockid)) != 0)
+                       goto err;
+               if ((ret = logc->get(logc, lsnp, &data_dbt, DB_SET)) != 0)
                        goto err;
-               if ((ret = __db_dispatch(dbenv, NULL,
-                   &data_dbt, &ap->lsn, DB_TXN_APPLY, NULL)) != 0)
+               if ((ret = __db_dispatch(dbenv, dbenv->recover_dtab,
+                   dbenv->recover_dtab_size, &data_dbt, lsnp,
+                   DB_TXN_APPLY, txninfo)) != 0)
                        goto err;
        }
 
-err:   if (recs.nalloc != 0) {
-               req.op = DB_LOCK_PUT_ALL;
-               if ((t_ret = dbenv->lock_vec(dbenv, recs.lockid,
-                   DB_LOCK_FREE_LOCKER, &req, 1, &lvp)) != 0 && ret == 0)
-                       ret = t_ret;
-               __os_free(dbenv, recs.array, recs.nalloc * sizeof(LSN_PAGE));
-       }
+err:   memset(&req, 0, sizeof(req));
+       req.op = DB_LOCK_PUT_ALL;
+       if ((t_ret = dbenv->lock_vec(dbenv, lockid,
+           DB_LOCK_FREE_LOCKER, &req, 1, &lvp)) != 0 && ret == 0)
+               ret = t_ret;
+
+       if (lc.nalloc != 0)
+               __os_free(dbenv, lc.array);
 
        if ((t_ret =
-           dbenv->lock_id_free(dbenv, recs.lockid)) != 0 && ret == 0)
+           dbenv->lock_id_free(dbenv, lockid)) != 0 && ret == 0)
                ret = t_ret;
 
-       if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
+       if (logc != NULL && (t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                ret = t_ret;
 
+       if (txninfo != NULL)
+               __db_txnlist_end(dbenv, txninfo);
+
        if (F_ISSET(&data_dbt, DB_DBT_REALLOC) && data_dbt.data != NULL)
-               __os_free(dbenv, data_dbt.data, 0);
+               __os_ufree(dbenv, data_dbt.data);
 
        if (dtab != NULL)
-               __os_free(dbenv, dtab, 0);
+               __os_free(dbenv, dtab);
+
+       if (ret == 0)
+               /*
+                * We don't hold the rep mutex, and could miscount if we race.
+                */
+               rep->stat.st_txns_applied++;
 
        return (ret);
 }
 
 /*
- * __rep_client_dbinit --
- *
- * Initialize the LSN database on the client side.  This is called from the
- * client initialization code.  The startup flag value indicates if
- * this is the first thread/process starting up and therefore should create
- * the LSN database.  This routine must be called once by each process acting
- * as a client.
- *
- * PUBLIC:  int __rep_client_dbinit __P((DB_ENV *, int));
+ * __rep_collect_txn
+ *     Recursive function that will let us visit every entry in a transaction
+ *     chain including all child transactions so that we can then apply
+ *     the entire transaction family at once.
  */
-int
-__rep_client_dbinit(dbenv, startup)
+static int
+__rep_collect_txn(dbenv, lsnp, lc)
        DB_ENV *dbenv;
-       int startup;
+       DB_LSN *lsnp;
+       LSN_COLLECTION *lc;
 {
-       DB_REP *db_rep;
-       DB *rep_db;
-       int ret, t_ret;
-       u_int32_t flags;
+       __txn_child_args *argp;
+       DB_LOGC *logc;
+       DB_LSN c_lsn;
+       DBT data;
+       u_int32_t rectype;
+       int nalloc, ret, t_ret;
 
-       PANIC_CHECK(dbenv);
-       db_rep = dbenv->rep_handle;
-       rep_db = NULL;
+       memset(&data, 0, sizeof(data));
+       F_SET(&data, DB_DBT_REALLOC);
 
-#define        REPDBNAME       "__db.rep.db"
+       if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
+               return (ret);
 
-       /* Check if this has already been called on this environment. */
-       if (db_rep->rep_db != NULL)
-               return (0);
+       while (!IS_ZERO_LSN(*lsnp) &&
+           (ret = logc->get(logc, lsnp, &data, DB_SET)) == 0) {
+               memcpy(&rectype, data.data, sizeof(rectype));
+               if (rectype == DB___txn_child) {
+                       if ((ret = __txn_child_read(dbenv,
+                           data.data, &argp)) != 0)
+                               goto err;
+                       c_lsn = argp->c_lsn;
+                       *lsnp = argp->prev_lsn;
+                       __os_free(dbenv, argp);
+                       ret = __rep_collect_txn(dbenv, &c_lsn, lc);
+               } else {
+                       if (lc->nalloc < lc->nlsns + 1) {
+                               nalloc = lc->nalloc == 0 ? 20 : lc->nalloc * 2;
+                               if ((ret = __os_realloc(dbenv,
+                                   nalloc * sizeof(DB_LSN), &lc->array)) != 0)
+                                       goto err;
+                               lc->nalloc = nalloc;
+                       }
+                       lc->array[lc->nlsns++] = *lsnp;
+
+                       /*
+                        * Explicitly copy the previous lsn.  The record
+                        * starts with a u_int32_t record type, a u_int32_t
+                        * txn id, and then the DB_LSN (prev_lsn) that we
+                        * want.  We copy explicitly because we have no idea
+                        * what kind of record this is.
+                        */
+                       memcpy(lsnp, (u_int8_t *)data.data +
+                           sizeof(u_int32_t) + sizeof(u_int32_t),
+                           sizeof(DB_LSN));
+               }
 
-       if (startup) {
-               if ((ret = db_create(&rep_db, dbenv, 0)) != 0)
+               if (ret != 0)
                        goto err;
-               /*
-                * Ignore errors, because if the file doesn't exist, this
-                * is perfectly OK.
-                */
-               (void)rep_db->remove(rep_db, REPDBNAME, NULL, 0);
        }
 
-       if ((ret = db_create(&rep_db, dbenv, 0)) != 0)
-               goto err;
-       if ((ret = rep_db->set_bt_compare(rep_db, __rep_bt_cmp)) != 0)
-               goto err;
-
-       flags = (F_ISSET(dbenv, DB_ENV_THREAD) ? DB_THREAD : 0) |
-           (startup ? DB_CREATE : 0);
-       if ((ret = rep_db->open(rep_db,
-           "__db.rep.db", NULL, DB_BTREE, flags, 0)) != 0)
-               goto err;
-
-       /* Allow writes to this database on a client. */
-       F_SET(rep_db, DB_CL_WRITER);
-
-       db_rep->rep_db = rep_db;
-
-       return (0);
-err:
-       if (rep_db != NULL &&
-           (t_ret = rep_db->close(rep_db, DB_NOSYNC)) != 0 && ret == 0)
+err:   if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                ret = t_ret;
-       db_rep->rep_db = NULL;
-
+       if (data.data != NULL)
+               __os_ufree(dbenv, data.data);
        return (ret);
 }
 
 /*
- * __rep_bt_cmp --
- *
- * Comparison function for the LSN table.  We use the entire control
- * structure as a key (for simplicity, so we don't have to merge the
- * other fields in the control with the data field), but really only
- * care about the LSNs.
+ * __rep_lsn_cmp --
+ *     qsort-type-compatible wrapper for log_compare.
  */
 static int
-__rep_bt_cmp(dbp, dbt1, dbt2)
-       DB *dbp;
-       const DBT *dbt1, *dbt2;
+__rep_lsn_cmp(lsn1, lsn2)
+       const void *lsn1, *lsn2;
 {
-       DB_LSN lsn1, lsn2;
-       REP_CONTROL *rp1, *rp2;
-
-       COMPQUIET(dbp, NULL);
-
-       rp1 = dbt1->data;
-       rp2 = dbt2->data;
-
-       __ua_memcpy(&lsn1, &rp1->lsn, sizeof(DB_LSN));
-       __ua_memcpy(&lsn2, &rp2->lsn, sizeof(DB_LSN));
-
-       if (lsn1.file > lsn2.file)
-               return (1);
 
-       if (lsn1.file < lsn2.file)
-               return (-1);
+       return (log_compare((DB_LSN *)lsn1, (DB_LSN *)lsn2));
+}
 
-       if (lsn1.offset > lsn2.offset)
-               return (1);
+/*
+ * __rep_newfile --
+ *     NEWFILE messages can contain either the last LSN of the old file
+ * or the first LSN of the new one, depending on which we have available
+ * when the message is sent.  When applying a NEWFILE message, make sure
+ * we haven't already swapped files, as it's possible (given the right sequence
+ * of out-of-order messages) to wind up with a NEWFILE message of each
+ * variety, and __rep_apply won't detect the two as duplicates of each other.
+ */
+static int
+__rep_newfile(dbenv, rc, msgdbt, lsnp)
+       DB_ENV *dbenv;
+       REP_CONTROL *rc;
+       DBT *msgdbt;
+       DB_LSN *lsnp;
+{
+       DB_LOG *dblp;
+       LOG *lp;
+       u_int32_t newfile;
 
-       if (lsn1.offset < lsn2.offset)
-               return (-1);
+       dblp = dbenv->lg_handle;
+       lp = dblp->reginfo.primary;
 
-       return (0);
+       /*
+        * A NEWFILE message containing the old file's LSN will be
+        * accompanied by a NULL rec DBT;  one containing the new one's LSN
+        * will need to supply the last record in the old file by
+        * sending it in the rec DBT.
+        */
+       if (msgdbt == NULL || msgdbt->size == 0)
+               newfile = rc->lsn.file + 1;
+       else
+               newfile = rc->lsn.file;
+
+       if (newfile > lp->lsn.file)
+               return (__log_newfile(dblp, lsnp));
+       else {
+               /* We've already applied this NEWFILE.  Just ignore it. */
+               *lsnp = lp->lsn;
+               return (0);
+       }
 }
-
index 895a8f7..38b3d17 100644 (file)
@@ -1,13 +1,13 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2001
+ * Copyright (c) 2001-2002
  *     Sleepycat Software.  All rights reserved.
  */
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "Id: rep_region.c,v 1.14 2001/10/25 14:08:49 bostic Exp ";
+static const char revid[] = "Id: rep_region.c,v 1.29 2002/08/06 04:50:36 bostic Exp ";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -16,8 +16,8 @@ static const char revid[] = "Id: rep_region.c,v 1.14 2001/10/25 14:08:49 bostic
 #include <string.h>
 
 #include "db_int.h"
-#include "rep.h"
-#include "log.h"
+#include "dbinc/rep.h"
+#include "dbinc/log.h"
 
 /*
  * __rep_region_init --
@@ -31,6 +31,7 @@ __rep_region_init(dbenv)
 {
        REGENV *renv;
        REGINFO *infop;
+       DB_MUTEX *db_mutexp;
        DB_REP *db_rep;
        REP *rep;
        int ret;
@@ -40,7 +41,7 @@ __rep_region_init(dbenv)
        renv = infop->primary;
        ret = 0;
 
-       MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, &renv->mutex);
        if (renv->rep_off == INVALID_ROFF) {
                /* Must create the region. */
                if ((ret = __db_shalloc(infop->addr,
@@ -49,19 +50,50 @@ __rep_region_init(dbenv)
                memset(rep, 0, sizeof(*rep));
                rep->tally_off = INVALID_ROFF;
                renv->rep_off = R_OFFSET(infop, rep);
-               if ((ret = __db_mutex_init(dbenv,
-                   &rep->mutex, renv->rep_off, 0)) != 0)
+
+               if ((ret = __db_mutex_setup(dbenv, infop, &rep->mutex,
+                   MUTEX_NO_RECORD)) != 0)
+                       goto err;
+
+               /*
+                * We must create a place for the db_mutex separately;
+                * mutexes have to be aligned to MUTEX_ALIGN, and the only way
+                * to guarantee that is to make sure they're at the beginning
+                * of a shalloc'ed chunk.
+                */
+               if ((ret = __db_shalloc(infop->addr, sizeof(DB_MUTEX),
+                   MUTEX_ALIGN, &db_mutexp)) != 0)
+                       goto err;
+               rep->db_mutex_off = R_OFFSET(infop, db_mutexp);
+
+               /*
+                * Because we have no way to prevent deadlocks and cannot log
+                * changes made to it, we single-thread access to the client
+                * bookkeeping database.  This is suboptimal, but it only gets
+                * accessed when messages arrive out-of-order, so it should
+                * stay small and not be used in a high-performance app.
+                */
+               if ((ret = __db_mutex_setup(dbenv, infop, db_mutexp,
+                   MUTEX_NO_RECORD)) != 0)
                        goto err;
 
                /* We have the region; fill in the values. */
                rep->eid = DB_EID_INVALID;
                rep->master_id = DB_EID_INVALID;
                rep->gen = 0;
+
+               /*
+                * Set default values for the min and max log records that we
+                * wait before requesting a missing log record.
+                */
+               rep->request_gap = DB_REP_REQUEST_GAP;
+               rep->max_gap = DB_REP_MAX_GAP;
        } else
                rep = R_ADDR(infop, renv->rep_off);
        MUTEX_UNLOCK(dbenv, &renv->mutex);
 
        db_rep->mutexp = &rep->mutex;
+       db_rep->db_mutexp = R_ADDR(infop, rep->db_mutex_off);
        db_rep->region = rep;
 
        return (0);
@@ -81,15 +113,19 @@ __rep_region_destroy(dbenv)
        DB_ENV *dbenv;
 {
        DB_REP *db_rep;
-       int ret;
+       int ret, t_ret;
 
-       ret = 0;
+       ret = t_ret = 0;
        db_rep = (DB_REP *)dbenv->rep_handle;
 
-       if (db_rep != NULL && db_rep->mutexp != NULL)
-               ret = __db_mutex_destroy(db_rep->mutexp);
+       if (db_rep != NULL) {
+               if (db_rep->mutexp != NULL)
+                       ret = __db_mutex_destroy(db_rep->mutexp);
+               if (db_rep->db_mutexp != NULL)
+                       t_ret = __db_mutex_destroy(db_rep->db_mutexp);
+       }
 
-       return (ret);
+       return (ret == 0 ? t_ret : ret);
 }
 
 /*
@@ -107,7 +143,7 @@ __rep_dbenv_close(dbenv)
        db_rep = (DB_REP *)dbenv->rep_handle;
 
        if (db_rep != NULL) {
-               __os_free(dbenv, db_rep, sizeof(DB_REP));
+               __os_free(dbenv, db_rep);
                dbenv->rep_handle = NULL;
        }
 
@@ -116,32 +152,36 @@ __rep_dbenv_close(dbenv)
 
 /*
  * __rep_preclose --
- * If we are a client, shut down our client database.  Remember that the
- * client database was opened in its own environment, not the environment
- * for which it keeps track of information.  Also, if we have a client
- * database (i.e., rep_handle->rep_db) that means we were a client and
- * could have applied file opens that need to be closed now.  This could
- * also mask errors where dbp's that weren't opened by us are still open,
- * but we have no way of distingushing the two.
+ *     If we are a client, shut down our client database and, if we're
+ * actually closing the environment, close all databases we've opened
+ * while applying messages.
  *
- * PUBLIC: int __rep_preclose __P((DB_ENV *));
+ * PUBLIC: int __rep_preclose __P((DB_ENV *, int));
  */
 int
-__rep_preclose(dbenv)
+__rep_preclose(dbenv, do_closefiles)
        DB_ENV *dbenv;
+       int do_closefiles;
 {
        DB *dbp;
        DB_REP *db_rep;
-       int ret;
+       int ret, t_ret;
 
-       ret = 0;
-       db_rep = (DB_REP *)dbenv->rep_handle;
+       ret = t_ret = 0;
+
+       /* If replication is not initialized, we have nothing to do. */
+       if ((db_rep = (DB_REP *)dbenv->rep_handle) == NULL)
+               return (0);
 
-       if (db_rep != NULL && (dbp = db_rep->rep_db) != NULL) {
-               __log_close_files(dbenv);
+       if ((dbp = db_rep->rep_db) != NULL) {
+               MUTEX_LOCK(dbenv, db_rep->db_mutexp);
                ret = dbp->close(dbp, 0);
                db_rep->rep_db = NULL;
+               MUTEX_UNLOCK(dbenv, db_rep->db_mutexp);
        }
 
-       return (ret);
+       if (do_closefiles)
+               t_ret = __dbreg_close_files(dbenv);
+
+       return (ret == 0 ? t_ret : ret);
 }
index 2b7d957..e561f58 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2001
+ * Copyright (c) 2001-2002
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "Id: rep_util.c,v 1.29 2001/11/16 10:57:51 krinsky Exp ";
+static const char revid[] = "Id: rep_util.c,v 1.50 2002/08/06 04:50:36 bostic Exp ";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -17,28 +17,27 @@ static const char revid[] = "Id: rep_util.c,v 1.29 2001/11/16 10:57:51 krinsky E
 #endif
 
 #include "db_int.h"
-#include "log.h"
-#include "rep.h"
-#include "txn.h"
-#include "db_page.h"
-#include "db_am.h"
-#include "btree.h"
-#include "hash.h"
-#include "qam.h"
-#include "db_shash.h"
-#include "lock.h"
+#include "dbinc/db_page.h"
+#include "dbinc/btree.h"
+#include "dbinc/fop.h"
+#include "dbinc/hash.h"
+#include "dbinc/log.h"
+#include "dbinc/qam.h"
+#include "dbinc/rep.h"
+#include "dbinc/txn.h"
 
 /*
  * rep_util.c:
  *     Miscellaneous replication-related utility functions, including
  *     those called by other subsystems.
  */
-static int __rep_apply_thread __P((DB_ENV *,
-    int (**)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *),
-    DBT *, DB_LSN *, TXN_RECS *));
 static int __rep_cmp_bylsn __P((const void *, const void *));
 static int __rep_cmp_bypage __P((const void *, const void *));
 
+#ifdef REP_DIAGNOSTIC
+static void __rep_print_logmsg __P((DB_ENV *, const DBT *, DB_LSN *));
+#endif
+
 /*
  * __rep_check_alloc --
  *     Make sure the array of TXN_REC entries is of at least size n.
@@ -90,6 +89,7 @@ __rep_send_message(dbenv, eid, rtype, lsnp, dbtp, flags)
        DBT cdbt, scrap_dbt;
        REP_CONTROL cntrl;
        u_int32_t send_flags;
+       int ret;
 
        db_rep = dbenv->rep_handle;
        rep = db_rep->region;
@@ -104,7 +104,7 @@ __rep_send_message(dbenv, eid, rtype, lsnp, dbtp, flags)
        cntrl.flags = flags;
        cntrl.rep_version = DB_REPVERSION;
        cntrl.log_version = DB_LOGVERSION;
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        cntrl.gen = rep->gen;
        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
@@ -118,11 +118,66 @@ __rep_send_message(dbenv, eid, rtype, lsnp, dbtp, flags)
                dbtp = &scrap_dbt;
        }
 
-       send_flags = (LF_ISSET(DB_FLUSH) ? DB_REP_PERMANENT : 0);
+       send_flags = (LF_ISSET(DB_PERMANENT) ? DB_REP_PERMANENT : 0);
 
-       return (db_rep->rep_send(dbenv, &cdbt, dbtp, eid, send_flags));
+#if 0
+       __rep_print_message(eid, &cntrl, "rep_send_message");
+#endif
+#ifdef REP_DIAGNOSTIC
+       if (rtype == REP_LOG)
+               __rep_print_logmsg(dbenv, dbtp, lsnp);
+#endif
+       ret = db_rep->rep_send(dbenv, &cdbt, dbtp, eid, send_flags);
+
+       /*
+        * We don't hold the rep lock, so this could miscount if we race.
+        * I don't think it's worth grabbing the mutex for that bit of
+        * extra accuracy.
+        */
+       if (ret == 0)
+               rep->stat.st_msgs_sent++;
+       else
+               rep->stat.st_msgs_send_failures++;
+
+       return (ret);
 }
 
+#ifdef REP_DIAGNOSTIC
+
+/*
+ * __rep_print_logmsg --
+ *     This is a debugging routine for printing out log records that
+ * we are about to transmit to a client.
+ */
+
+static void
+__rep_print_logmsg(dbenv, logdbt, lsnp)
+       DB_ENV *dbenv;
+       const DBT *logdbt;
+       DB_LSN *lsnp;
+{
+       /* Static structures to hold the printing functions. */
+       static int (**ptab)__P((DB_ENV *,
+           DBT *, DB_LSN *, db_recops, void *)) = NULL;
+       size_t ptabsize = 0;
+
+       if (ptabsize == 0) {
+               /* Initialize the table. */
+               (void)__bam_init_print(dbenv, &ptab, &ptabsize);
+               (void)__crdel_init_print(dbenv, &ptab, &ptabsize);
+               (void)__db_init_print(dbenv, &ptab, &ptabsize);
+               (void)__dbreg_init_print(dbenv, &ptab, &ptabsize);
+               (void)__fop_init_print(dbenv, &ptab, &ptabsize);
+               (void)__qam_init_print(dbenv, &ptab, &ptabsize);
+               (void)__ham_init_print(dbenv, &ptab, &ptabsize);
+               (void)__txn_init_print(dbenv, &ptab, &ptabsize);
+       }
+
+       (void)__db_dispatch(dbenv,
+           ptab, ptabsize, (DBT *)logdbt, lsnp, DB_TXN_PRINT, NULL);
+}
+
+#endif
 /*
  * __rep_new_master --
  *     Called after a master election to sync back up with a new master.
@@ -152,13 +207,14 @@ __rep_new_master(dbenv, cntrl, eid)
 
        db_rep = dbenv->rep_handle;
        rep = db_rep->region;
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        ELECTION_DONE(rep);
        change = rep->gen != cntrl->gen || rep->master_id != eid;
        if (change) {
                rep->gen = cntrl->gen;
                rep->master_id = eid;
                F_SET(rep, REP_F_RECOVER);
+               rep->stat.st_master_changes++;
        }
        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
@@ -180,8 +236,8 @@ __rep_new_master(dbenv, cntrl, eid)
        if (last_lsn.offset > sizeof(LOGP))
                last_lsn.offset -= lp->len;
        R_UNLOCK(dbenv, &dblp->reginfo);
-       if (IS_INIT_LSN(lsn)) {
-empty:         MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       if (IS_INIT_LSN(lsn) || IS_ZERO_LSN(lsn)) {
+empty:         MUTEX_LOCK(dbenv, db_rep->mutexp);
                F_CLR(rep, REP_F_RECOVER);
                MUTEX_UNLOCK(dbenv, db_rep->mutexp);
 
@@ -211,6 +267,9 @@ empty:              MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
                        return (ret);
        }
 
+       R_LOCK(dbenv, &dblp->reginfo);
+       lp->verify_lsn = last_lsn;
+       R_UNLOCK(dbenv, &dblp->reginfo);
        if ((ret = __rep_send_message(dbenv,
            eid, REP_VERIFY_REQ, &last_lsn, NULL, 0)) != 0)
                return (ret);
@@ -240,9 +299,10 @@ __rep_lockpgno_init(dbenv, dtabp, dtabsizep)
        if ((ret = __bam_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
            (ret = __crdel_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
            (ret = __db_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
+           (ret = __dbreg_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
+           (ret = __fop_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
            (ret = __qam_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
            (ret = __ham_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
-           (ret = __log_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0 ||
            (ret = __txn_init_getpgnos(dbenv, dtabp, dtabsizep)) != 0)
                return (ret);
 
@@ -277,12 +337,13 @@ __rep_unlockpages(dbenv, lid)
  *
  * PUBLIC: int __rep_lockpages __P((DB_ENV *,
  * PUBLIC:     int (**)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *),
- * PUBLIC:     DB_LSN *, DB_LSN *, TXN_RECS *, u_int32_t));
+ * PUBLIC:     size_t, DB_LSN *, DB_LSN *, TXN_RECS *, u_int32_t));
  */
 int
-__rep_lockpages(dbenv, dtab, key_lsn, max_lsn, recs, lid)
+__rep_lockpages(dbenv, dtab, dtabsize, key_lsn, max_lsn, recs, lid)
        DB_ENV *dbenv;
        int (**dtab)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
+       size_t dtabsize;
        DB_LSN *key_lsn, *max_lsn;
        TXN_RECS *recs;
        u_int32_t lid;
@@ -328,10 +389,13 @@ __rep_lockpages(dbenv, dtab, key_lsn, max_lsn, recs, lid)
 
        /* Single transaction apply. */
        if (max_lsn != NULL) {
+               DB_ASSERT(0); /* XXX */
+               /*
                tmp_lsn = *max_lsn;
-               if ((ret = __rep_apply_thread(dbenv, dtab,
+               if ((ret = __rep_apply_thread(dbenv, dtab, dtabsize,
                    &data_dbt, &tmp_lsn, t)) != 0)
                        goto err;
+                       */
        }
 
        /* In recovery. */
@@ -343,11 +407,19 @@ __rep_lockpages(dbenv, dtab, key_lsn, max_lsn, recs, lid)
                /* Save lsn values, since dispatch functions can change them. */
                tmp_lsn = *key_lsn;
                ret = __db_dispatch(dbenv,
-                   dtab, &data_dbt, &tmp_lsn, DB_TXN_APPLY, t);
+                   dtab, dtabsize, &data_dbt, &tmp_lsn, DB_TXN_GETPGNOS, t);
 
                if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
                        ret = t_ret;
-               if (ret != 0)
+
+               /*
+                * If ret == DB_DELETED, this record refers to a temporary
+                * file and there's nothing to apply.
+                */
+               if (ret == DB_DELETED) {
+                       ret = 0;
+                       goto out;
+               } else if (ret != 0)
                        goto err;
        }
 
@@ -380,8 +452,8 @@ __rep_lockpages(dbenv, dtab, key_lsn, max_lsn, recs, lid)
        /* Handle single lock case specially, else allocate space for locks. */
        if (unique == 1) {
                memset(&lo, 0, sizeof(lo));
-               lo.data = &t->array[i].pgdesc;
-               lo.size = sizeof(&t->array[0].pgdesc);
+               lo.data = &t->array[0].pgdesc;
+               lo.size = sizeof(t->array[0].pgdesc);
                ret = dbenv->lock_get(dbenv, lid, 0, &lo, DB_LOCK_WRITE, &l);
                goto out2;
        }
@@ -408,30 +480,26 @@ __rep_lockpages(dbenv, dtab, key_lsn, max_lsn, recs, lid)
                        locks.reqs[unique].mode = DB_LOCK_WRITE;
                        locks.reqs[unique].obj = &locks.objs[unique];
                        locks.objs[unique].data = &t->array[i].pgdesc;
-                       locks.objs[unique].size = sizeof(&t->array[i].pgdesc);
+                       locks.objs[unique].size = sizeof(t->array[i].pgdesc);
                        unique++;
                }
        }
 
        /* Finally, get the locks. */
        if ((ret =
-           dbenv->lock_vec(dbenv, lid, 0, locks.reqs, unique, &lvp)) != 0)
-               goto err;
-
-       if (0) {
+           dbenv->lock_vec(dbenv, lid, 0, locks.reqs, unique, &lvp)) != 0) {
                /*
-                * If we finished successfully, then we need to retain
-                * the locks, but we can free everything else up, because
-                * we can do a release by locker-id.
+                * If we were unsuccessful, unlock any locks we acquired before
+                * the error and return the original error value.
                 */
-err:           if ((t_ret = __rep_unlockpages(dbenv, lid)) != 0 && ret == 0)
-                       ret = t_ret;
+               (void)__rep_unlockpages(dbenv, lid);
        }
 
+err:
 out:   if (locks.objs != NULL)
-               __os_free(dbenv, locks.objs, locks.n * sizeof(DBT));
+               __os_free(dbenv, locks.objs);
        if (locks.reqs != NULL)
-               __os_free(dbenv, locks.reqs, locks.n * sizeof(DB_LOCKREQ));
+               __os_free(dbenv, locks.reqs);
 
        /*
         * Before we return, sort by LSN so that we apply records in the
@@ -439,11 +507,14 @@ out:      if (locks.objs != NULL)
         */
        qsort(t->array, t->npages, sizeof(LSN_PAGE), __rep_cmp_bylsn);
 
-out2:  if ((ret != 0 || recs == NULL) && t->nalloc != 0)
-               __os_free(dbenv, t->array, t->nalloc * sizeof(LSN_PAGE));
+out2:  if ((ret != 0 || recs == NULL) && t->nalloc != 0) {
+               __os_free(dbenv, t->array);
+               t->array = NULL;
+               t->npages = t->nalloc = 0;
+       }
 
        if (F_ISSET(&data_dbt, DB_DBT_REALLOC) && data_dbt.data != NULL)
-               __os_free(dbenv, data_dbt.data, 0);
+               __os_ufree(dbenv, data_dbt.data);
 
        return (ret);
 }
@@ -526,62 +597,6 @@ __rep_cmp_bylsn(a, b)
 }
 
 /*
- * __rep_apply_thread
- *     Recursive function that will let us visit every entry in a transaction
- *     chain including all child transactions so that we can then apply
- *     the entire transaction family at once.
- */
-static int
-__rep_apply_thread(dbenv, dtab, datap, lsnp, recp)
-       DB_ENV *dbenv;
-       int (**dtab) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
-       DBT *datap;
-       DB_LSN *lsnp;
-       TXN_RECS *recp;
-{
-       __txn_child_args *argp;
-       DB_LOGC *logc;
-       DB_LSN c_lsn;
-       u_int32_t rectype;
-       int ret, t_ret;
-
-       if ((ret = dbenv->log_cursor(dbenv, &logc, 0)) != 0)
-               return (ret);
-
-       while (!IS_ZERO_LSN(*lsnp) &&
-           (ret = logc->get(logc, lsnp, datap, DB_SET)) == 0) {
-               memcpy(&rectype, datap->data, sizeof(rectype));
-               if (rectype == DB_txn_child) {
-                       if ((ret = __txn_child_read(dbenv,
-                           datap->data, &argp)) != 0)
-                               goto err;
-                       c_lsn = argp->c_lsn;
-                       *lsnp = argp->prev_lsn;
-                       __os_free(dbenv, argp, 0);
-                       ret = __rep_apply_thread(dbenv,
-                           dtab, datap, &c_lsn, recp);
-               } else {
-                       ret = __db_dispatch(dbenv, dtab,
-                           datap, lsnp, DB_TXN_APPLY, recp);
-                       /*
-                        * Explicitly copy the previous lsn since the
-                        * page gathering routines don't modify it for you.
-                        */
-                       memcpy(lsnp, (u_int8_t *)datap->data +
-                           sizeof(u_int32_t) + sizeof (DB_TXN *),
-                           sizeof(DB_LSN));
-               }
-
-               if (ret != 0)
-                       goto err;
-       }
-
-err:   if ((t_ret = logc->close(logc, 0)) != 0 && ret == 0)
-               ret = t_ret;
-       return (ret);
-}
-
-/*
  * __rep_is_client
  *     Used by other subsystems to figure out if this is a replication
  * client sites.
@@ -600,7 +615,7 @@ __rep_is_client(dbenv)
                return (0);
        rep = db_rep->region;
 
-       MUTEX_LOCK(dbenv, db_rep->mutexp, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, db_rep->mutexp);
        ret = F_ISSET(rep, REP_F_UPGRADE | REP_F_LOGSONLY);
        MUTEX_UNLOCK(dbenv, db_rep->mutexp);
        return (ret);
@@ -610,19 +625,22 @@ __rep_is_client(dbenv)
  * __rep_send_vote
  *     Send this site's vote for the election.
  *
- * PUBLIC: int __rep_send_vote __P((DB_ENV *, DB_LSN *, int, int));
+ * PUBLIC: int __rep_send_vote __P((DB_ENV *, DB_LSN *, int, int, int));
  */
 int
-__rep_send_vote(dbenv, lsnp, nsites, pri)
+__rep_send_vote(dbenv, lsnp, nsites, pri, tiebreaker)
        DB_ENV *dbenv;
        DB_LSN *lsnp;
-       int nsites, pri;
+       int nsites, pri, tiebreaker;
 {
        DBT vote_dbt;
        REP_VOTE_INFO vi;
 
+       memset(&vi, 0, sizeof(vi));
+
        vi.priority = pri;
        vi.nsites = nsites;
+       vi.tiebreaker = tiebreaker;
 
        memset(&vote_dbt, 0, sizeof(vote_dbt));
        vote_dbt.data = &vi;
@@ -664,7 +682,7 @@ __rep_grow_sites(dbenv, nsites)
 
        infop = dbenv->reginfo;
        renv = infop->primary;
-       MUTEX_LOCK(dbenv, &renv->mutex, dbenv->lockfhp);
+       MUTEX_LOCK(dbenv, &renv->mutex);
        if ((ret = __db_shalloc(infop->addr,
            sizeof(nalloc * sizeof(int)), sizeof(int), &tally)) == 0) {
                if (rep->tally_off != INVALID_ROFF)
@@ -755,3 +773,93 @@ err:       if (LOCK_ISSET(lk) && (t_ret = __LPUT(dbc, lk)) != 0 && ret == 0)
        return (ret);
 }
 #endif
+
+#if 0
+/*
+ * PUBLIC: void __rep_print_message __P((int, REP_CONTROL *, char *));
+ */
+void
+__rep_print_message(eid, rp, str)
+       int eid;
+       REP_CONTROL *rp;
+       char *str;
+{
+       char *type;
+       switch (rp->rectype) {
+       case REP_ALIVE:
+               type = "alive";
+               break;
+       case REP_ALIVE_REQ:
+               type = "alive_req";
+               break;
+       case REP_ALL_REQ:
+               type = "all_req";
+               break;
+       case REP_ELECT:
+               type = "elect";
+               break;
+       case REP_FILE:
+               type = "file";
+               break;
+       case REP_FILE_REQ:
+               type = "file_req";
+               break;
+       case REP_LOG:
+               type = "log";
+               break;
+       case REP_LOG_MORE:
+               type = "log_more";
+               break;
+       case REP_LOG_REQ:
+               type = "log_req";
+               break;
+       case REP_MASTER_REQ:
+               type = "master_req";
+               break;
+       case REP_NEWCLIENT:
+               type = "newclient";
+               break;
+       case REP_NEWFILE:
+               type = "newfile";
+               break;
+       case REP_NEWMASTER:
+               type = "newmaster";
+               break;
+       case REP_NEWSITE:
+               type = "newsite";
+               break;
+       case REP_PAGE:
+               type = "page";
+               break;
+       case REP_PAGE_REQ:
+               type = "page_req";
+               break;
+       case REP_PLIST:
+               type = "plist";
+               break;
+       case REP_PLIST_REQ:
+               type = "plist_req";
+               break;
+       case REP_VERIFY:
+               type = "verify";
+               break;
+       case REP_VERIFY_FAIL:
+               type = "verify_fail";
+               break;
+       case REP_VERIFY_REQ:
+               type = "verify_req";
+               break;
+       case REP_VOTE1:
+               type = "vote1";
+               break;
+       case REP_VOTE2:
+               type = "vote2";
+               break;
+       default:
+               type = "NOTYPE";
+               break;
+       }
+       printf("%s: eid %d, type %s, LSN [%u][%u]\n", str, eid,
+               type, rp->lsn.file, rp->lsn.offset);
+}
+#endif
index fb29579..079fe44 100644 (file)
@@ -1,4 +1,5 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<!--Copyright 1999-2002 by Sleepycat Software, Inc.-->
+<!--All rights reserved.-->
 <html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
index 395535e..36e2193 100644 (file)
@@ -1,14 +1,14 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: bigfile002.tcl,v 11.4 2001/08/03 18:31:15 sandstro Exp 
+# Id: bigfile002.tcl,v 11.7 2002/08/10 13:39:26 bostic Exp 
 #
 # TEST bigfile002
 # TEST This one should be faster and not require so much disk space,
-#      although it doesn't test as extensively.  Create an mpool file
-#      with 1K pages.  Dirty page 6000000.  Sync.
+# TEST although it doesn't test as extensively.  Create an mpool file
+# TEST with 1K pages.  Dirty page 6000000.  Sync.
 proc bigfile002 { args } {
        source ./include.tcl
 
@@ -19,7 +19,7 @@ proc bigfile002 { args } {
        env_cleanup $testdir
 
        # Create env.
-       set env [berkdb env -create -home $testdir]
+       set env [berkdb_env -create -home $testdir]
        error_check_good valid_env [is_valid_env $env] TRUE
 
        # Create the file.
index d6ede9c..456ec6e 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2001
+# Copyright (c) 1996-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: dead006.tcl,v 1.3 2001/10/11 16:15:30 sandstro Exp 
+# Id: dead006.tcl,v 1.4 2002/01/11 15:53:21 bostic Exp 
 #
 # TEST dead006
 # TEST use timeouts rather than the normal dd algorithm.
index 9f58c01..c729454 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2001
+# Copyright (c) 1996-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: dead007.tcl,v 1.2 2001/10/20 14:21:08 bostic Exp 
+# Id: dead007.tcl,v 1.3 2002/01/11 15:53:22 bostic Exp 
 #
 # TEST dead007
 # TEST use timeouts rather than the normal dd algorithm.
index 40dba37..8187639 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1999-2001
+# Copyright (c) 1999-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: env009.tcl,v 11.2 2001/08/03 16:39:24 bostic Exp 
+# Id: env009.tcl,v 11.5 2002/08/12 20:40:36 sandstro Exp 
 #
 # TEST env009
 # TEST Test calls to all the various stat functions.  We have several
@@ -17,7 +17,7 @@ proc env009 { } {
        env_cleanup $testdir
        puts "\tEnv009.a: Setting up env and a database."
 
-       set e [berkdb env -create -home $testdir -txn]
+       set e [berkdb_env -create -home $testdir -txn]
        error_check_good dbenv [is_valid_env $e] TRUE
        set dbbt [berkdb_open -create -btree $testdir/env009bt.db]
        error_check_good dbopen [is_valid_db $dbbt] TRUE
@@ -27,7 +27,7 @@ proc env009 { } {
        error_check_good dbopen [is_valid_db $dbq] TRUE
 
        set rlist {
-       { "lock_stat" "Max locks" "Env009.b"}
+       { "lock_stat" "Maximum locks" "Env009.b"}
        { "log_stat" "Magic" "Env009.c"}
        { "mpool_stat" "Number of caches" "Env009.d"}
        { "txn_stat" "Max Txns" "Env009.e"}
index 18bf1a7..76d6731 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1999-2001
+# Copyright (c) 1999-2002
 #       Sleepycat Software.  All rights reserved.
 #
-# Id: env010.tcl,v 1.2 2001/08/03 16:39:24 bostic Exp 
+# Id: env010.tcl,v 1.4 2002/02/20 17:08:21 sandstro Exp 
 #
 # TEST env010
 # TEST Run recovery in an empty directory, and then make sure we can still
@@ -28,7 +28,7 @@ proc env010 { } {
 
                puts "\tEnv010: Creating env for $rmethod test."
                env_cleanup $testdir/EMPTYDIR
-               set e [berkdb env -create -home $testdir/EMPTYDIR -$rmethod]
+               set e [berkdb_env -create -home $testdir/EMPTYDIR -$rmethod]
                error_check_good dbenv [is_valid_env $e] TRUE
 
                # Open and close a database
index fcbdf25..bef1700 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2001
+# Copyright (c) 1996-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: lock004.tcl,v 11.2 2001/10/20 14:24:34 bostic Exp 
+# Id: lock004.tcl,v 11.5 2002/04/25 19:30:30 sue Exp 
 #
 # TEST lock004
 # TEST Test locker ids wraping around.
@@ -13,37 +13,17 @@ proc lock004 {} {
        global lock_curid
        global lock_maxid
 
-       puts "Lock004.a -- locker id wrapping"
-       locktest -S [expr $lock_maxid - 1] $lock_maxid
+       set save_curid $lock_curid
+       set save_maxid $lock_maxid
 
-       puts "Lock004.b -- test out of locker ids"
-       env_cleanup $testdir
+       set lock_curid [expr $lock_maxid - 1]
+       puts "Lock004: Locker id wraparound test"
+       puts "\tLock004.a: repeat lock001-lock003 with wraparound lockids"
 
-       # Open/create the lock region
-       set e [berkdb env -create -lock -home $testdir]
-       error_check_good env_open [is_substr $e env] 1
+       lock001
+       lock002
+       lock003
 
-       catch { $e lock_id } locker1
-       error_check_good locker1 [is_valid_locker $locker1] TRUE
-       error_check_good lock_id_set \
-           [$e lock_id_set [expr $lock_maxid - 1] $lock_maxid] 0
-
-       catch { $e lock_id } locker2
-       error_check_good locker2 [is_valid_locker $locker2] TRUE
-       catch { $e lock_id } locker3
-       error_check_bad locker3 [is_valid_locker $locker3] TRUE
-       error_check_good locker3 [string match "*wrapped*" $locker3] 1
-
-       catch { $e lock_id_free $locker1 } ret
-       error_check_good free $ret 0
-       catch { $e lock_id } locker4
-       error_check_good locker4 [is_valid_locker $locker4] TRUE
-
-       catch { $e lock_id_free $locker2 } ret
-       error_check_good free $ret 0
-       catch { $e lock_id_free $locker4 } ret
-       error_check_good free $ret 0
-
-       catch {$e close} ret
-       error_check_good close $ret 0
+       set lock_curid $save_curid
+       set lock_maxid $save_maxid
 }
index 3f54745..33032af 100644 (file)
@@ -1,12 +1,12 @@
 # See the file LICENSE for redistribution information.
 #
 # Copyright (c) 1996-2001
-#      Sleepycat Software.  All rights reserved.
+# Sleepycat Software. All rights reserved.
 #
-# Id: lock005.tcl,v 1.1 2001/11/16 20:13:04 sandstro Exp 
+# Id: lock005.tcl,v 1.7 2002/08/08 15:38:07 bostic Exp 
 #
-# TEST lock005
-# TEST Check that page locks are being released properly.
+# TEST lock005
+# TEST Check that page locks are being released properly.
 
 proc lock005 { } {
        source ./include.tcl
@@ -17,31 +17,161 @@ proc lock005 { } {
        env_cleanup $testdir
 
        # Open/create the lock region
-       set e [berkdb env -create -lock -home $testdir -txn -log]
+       set e [berkdb_env -create -lock -home $testdir -txn -log]
        error_check_good env_open [is_valid_env $e] TRUE
 
        # Open/create the database
-       set db [berkdb open -create -env $e -len 10 -queue q.db]
+       set db [berkdb open -create -auto_commit -env $e -len 10 -queue q.db]
        error_check_good dbopen [is_valid_db $db] TRUE
 
+       # Check that records are locking by trying to
+       # fetch a record on the wrong transaction.
+       puts "\tLock005.a: Verify that we are locking"
+
        # Start the first transaction
        set txn1 [$e txn -nowait]
        error_check_good txn_begin [is_valid_txn $txn1 $e] TRUE
-       set ret [$db put -txn $txn1 -append record1]
-       error_check_good dbput_txn1 $ret 1
+       set ret [catch {$db put -txn $txn1 -append record1} recno1]
+       error_check_good dbput_txn1 $ret 0
 
-       # Start a second transaction while first is still running
+       # Start second txn while the first is still running ...
        set txn2 [$e txn -nowait]
-       error_check_good txn_begin [is_valid_txn $txn2 $e] TRUE 
-       set ret [catch {$db put -txn $txn2 -append record2} res] 
-       error_check_good dbput_txn2 $ret 0
-      error_check_good dbput_txn2recno $res 2  
+       error_check_good txn_begin [is_valid_txn $txn2 $e] TRUE
 
-       # Clean up
+       # ... and try to get a record from the first txn (should fail)
+       set ret [catch {$db get -txn $txn2 $recno1} res]
+       error_check_good dbget_wrong_record \
+           [is_substr $res "Lock not granted"] 1
+
+       # End transactions
        error_check_good txn1commit [$txn1 commit] 0
+       how_many_locks 1 $e
        error_check_good txn2commit [$txn2 commit] 0
+       # The number of locks stays the same here because the first
+       # lock is released and the second lock was never granted.
+       how_many_locks 1 $e
+
+       # Test lock behavior for both abort and commit
+       puts "\tLock005.b: Verify locks after abort or commit"
+       foreach endorder {forward reverse} {
+               end_order_test $db $e commit abort $endorder
+               end_order_test $db $e abort commit $endorder
+               end_order_test $db $e commit commit $endorder
+               end_order_test $db $e abort abort $endorder
+       }
+
+       # Clean up
        error_check_good db_close [$db close] 0
        error_check_good env_close [$e close] 0
+}
 
+proc end_order_test { db e txn1end txn2end endorder } {
+       # Start one transaction
+       set txn1 [$e txn -nowait]
+       error_check_good txn_begin [is_valid_txn $txn1 $e] TRUE
+       set ret [catch {$db put -txn $txn1 -append record1} recno1]
+       error_check_good dbput_txn1 $ret 0
+
+       # Check number of locks
+       how_many_locks 2 $e
+
+       # Start a second transaction while first is still running
+       set txn2 [$e txn -nowait]
+       error_check_good txn_begin [is_valid_txn $txn2 $e] TRUE
+       set ret [catch {$db put -txn $txn2 -append record2} recno2]
+       error_check_good dbput_txn2 $ret 0
+       how_many_locks 3 $e
+
+       # Now commit or abort one txn and make sure the other is okay
+       if {$endorder == "forward"} {
+               # End transaction 1 first
+               puts "\tLock005.b.1: $txn1end txn1 then $txn2end txn2"
+               error_check_good txn_$txn1end [$txn1 $txn1end] 0
+               how_many_locks 2 $e
+
+               # txn1 is now ended, but txn2 is still running
+               set ret1 [catch {$db get -txn $txn2 $recno1} res1]
+               set ret2 [catch {$db get -txn $txn2 $recno2} res2]
+               if { $txn1end == "commit" } {
+                       error_check_good txn2_sees_txn1 $ret1 0
+                       error_check_good txn2_sees_txn2 $ret2 0
+               } else {
+                       # transaction 1 was aborted
+                       error_check_good txn2_cantsee_txn1 [llength $res1] 0
+               }
+
+               # End transaction 2 second
+               error_check_good txn_$txn2end [$txn2 $txn2end] 0
+               how_many_locks 1 $e
+
+               # txn1 and txn2 should both now be invalid
+               # The get no longer needs to be transactional
+               set ret3 [catch {$db get $recno1} res3]
+               set ret4 [catch {$db get $recno2} res4]
+
+               if { $txn2end == "commit" } {
+                       error_check_good txn2_sees_txn1 $ret3 0
+                       error_check_good txn2_sees_txn2 $ret4 0
+                       error_check_good txn2_has_record2 \
+                           [is_substr $res4 "record2"] 1
+               } else {
+                       # transaction 2 was aborted
+                       error_check_good txn2_cantsee_txn1 $ret3 0
+                       error_check_good txn2_aborted [llength $res4] 0
+               }
+
+       } elseif { $endorder == "reverse" } {
+               # End transaction 2 first
+               puts "\tLock005.b.2: $txn2end txn2 then $txn1end txn1"
+               error_check_good txn_$txn2end [$txn2 $txn2end] 0
+               how_many_locks 2 $e
+
+               # txn2 is ended, but txn1 is still running
+               set ret1 [catch {$db get -txn $txn1 $recno1} res1]
+               set ret2 [catch {$db get -txn $txn1 $recno2} res2]
+               if { $txn2end == "commit" } {
+                       error_check_good txn1_sees_txn1 $ret1 0
+                       error_check_good txn1_sees_txn2 $ret2 0
+               } else {
+                       # transaction 2 was aborted
+                       error_check_good txn1_cantsee_txn2 [llength $res2] 0
+               }
+
+               # End transaction 1 second
+               error_check_good txn_$txn1end [$txn1 $txn1end] 0
+               how_many_locks 1 $e
+
+               # txn1 and txn2 should both now be invalid
+               # The get no longer needs to be transactional
+               set ret3 [catch {$db get $recno1} res3]
+               set ret4 [catch {$db get $recno2} res4]
+
+               if { $txn1end == "commit" } {
+                       error_check_good txn1_sees_txn1 $ret3 0
+                       error_check_good txn1_sees_txn2 $ret4 0
+                       error_check_good txn1_has_record1 \
+                           [is_substr $res3 "record1"] 1
+               } else {
+                       # transaction 1 was aborted
+                       error_check_good txn1_cantsee_txn2 $ret4 0
+                       error_check_good txn1_aborted [llength $res3] 0
+               }
+       }
 }
 
+proc how_many_locks { expected env } {
+       set stat [$env lock_stat]
+       set str "Current number of locks"
+       set checked 0
+       foreach statpair $stat {
+               if { $checked == 1 } {
+                       break
+               }
+               if { [is_substr [lindex $statpair 0] $str] != 0} {
+                       set checked 1
+                       set nlocks [lindex $statpair 1]
+                       error_check_good expected_nlocks $nlocks $expected
+               }
+       }
+       error_check_good checked $checked 1
+}
index fdfc95d..9080b2b 100644 (file)
@@ -1,16 +1,16 @@
 # Code to load up the tests in to the Queue database
-# Id: parallel.tcl,v 11.9 2001/10/03 20:48:51 sandstro Exp 
+# Id: parallel.tcl,v 11.23 2002/08/08 19:25:39 sue Exp 
 proc load_queue { file  {dbdir RUNQUEUE} nitems } {
 
        puts -nonewline "Loading run queue with $nitems items..."
        flush stdout
 
-       set env [berkdb env -create -lock -home $dbdir]
-       error_check_good dbenv [is_valid_widget $env env] TRUE
+       set env [berkdb_env -create -lock -home $dbdir]
+       error_check_good dbenv [is_valid_env $env] TRUE
 
        set db [eval {berkdb_open -env $env -create -truncate \
-            -mode 0644 -len 100 -queue queue.db} ]
-        error_check_good dbopen [is_valid_widget $db db] TRUE
+            -mode 0644 -len 120 -queue queue.db} ]
+        error_check_good dbopen [is_valid_db $db] TRUE
 
        set fid [open $file]
 
@@ -54,29 +54,32 @@ proc load_queue { file  {dbdir RUNQUEUE} nitems } {
        $env close
 }
 
-proc init_runqueue { {dbdir RUNQUEUE} nitems } {
+proc init_runqueue { {dbdir RUNQUEUE} nitems list} {
 
        if { [file exists $dbdir] != 1 } {
                file mkdir $dbdir
        }
        puts "Creating test list..."
-       run_all -n
+       $list -n
        load_queue ALL.OUT $dbdir $nitems
-       file delete ALL.OUT
+       file delete TEST.LIST
+       file rename ALL.OUT TEST.LIST
+#      file delete ALL.OUT
 }
 
-proc run_parallel { nprocs {nitems ALL} } {
+proc run_parallel { nprocs {list run_all} {nitems ALL} } {
        set basename ./PARALLEL_TESTDIR
        set queuedir ./RUNQUEUE
        source ./include.tcl
 
        mkparalleldirs $nprocs $basename $queuedir
 
-       init_runqueue $queuedir $nitems
+       init_runqueue $queuedir $nitems $list
 
        set basedir [pwd]
        set pidlist {}
-        set queuedir ../../[string range $basedir [string last "/" $basedir] end]/$queuedir
+      set queuedir ../../[string range $basedir \
+           [string last "/" $basedir] end]/$queuedir
 
        for { set i 1 } { $i <= $nprocs } { incr i } {
                fileremove -f ALL.OUT.$i
@@ -112,12 +115,12 @@ proc run_queue { i rundir queuedir nitems } {
        source ./include.tcl
        global env
 
-       set dbenv [berkdb env -create -lock -home $queuedir]
-       error_check_good dbenv [is_valid_widget $dbenv env] TRUE
+       set dbenv [berkdb_env -create -lock -home $queuedir]
+       error_check_good dbenv [is_valid_env $dbenv] TRUE
 
        set db [eval {berkdb_open -env $dbenv \
-            -mode 0644 -len 80 -queue queue.db} ]
-        error_check_good dbopen [is_valid_widget $db db] TRUE
+            -mode 0644 -len 120 -queue queue.db} ]
+        error_check_good dbopen [is_valid_db $db] TRUE
 
        set dbc  [eval $db cursor]
         error_check_good cursor [is_valid_cursor $dbc $db] TRUE
@@ -131,7 +134,9 @@ proc run_queue { i rundir queuedir nitems } {
                        set cmd [lindex [lindex $line 0] 1]
                        set num [lindex [lindex $line 0] 0]
                        set o [open $builddir/ALL.OUT.$i a]
-                       puts $o "\nExecuting record $num:\n"
+                       puts $o "\nExecuting record $num ([timestamp -w]):\n"
+                       set tdir "TESTDIR.$i"
+                       regsub {TESTDIR} $cmd $tdir cmd
                        puts $o $cmd
                        close $o
                        if { [expr {$num % 10} == 0] } {
@@ -179,6 +184,7 @@ proc mkparalleldirs { nprocs basename queuedir } {
        for { set i 1 } { $i <= $nprocs } { incr i } {
                set destdir $basename.$i
                catch {file mkdir $destdir}
+               puts "Created $destdir"
                if { $is_windows_test == 1 } {
                        catch {file mkdir $destdir/Debug}
                        catch {eval file copy \
@@ -202,13 +208,18 @@ proc mkparalleldirs { nprocs basename queuedir } {
 
                regsub {test_path } $d {test_path ../} d
                regsub {src_root } $d {src_root ../} d
+               set tdir "testdir ./TESTDIR.$i"
+               regsub {testdir \./TESTDIR} $d $tdir d
                regsub {KILL \.} $d {KILL ..} d
                set outfile [open $destdir/include.tcl w]
                puts $outfile $d
                close $outfile
 
-               if { [file exists $dir/berkeley_db_svc$EXE] } {
-                       catch {eval file copy $dir/berkeley_db_svc$EXE $destdir}
+               global svc_list
+               foreach svc_exe $svc_list {
+                       if { [file exists $dir/$svc_exe] } {
+                               catch {eval file copy $dir/$svc_exe $destdir}
+                       }
                }
        }
 }
index 0513d1d..1b50f21 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1999-2001
+# Copyright (c) 1999-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: recd016.tcl,v 11.1 2001/11/07 18:45:02 sue Exp 
+# Id: recd016.tcl,v 11.6 2002/05/24 16:14:15 sue Exp 
 #
 # TEST recd016
 # TEST This is a recovery test for testing running recovery while
@@ -39,12 +39,17 @@ proc recd016 { method args } {
        set t3 $testdir/t3
        set t4 $testdir/t4
        set t5 $testdir/t5
+       # Since we are using txns, we need at least 1 lock per
+       # record (for queue).  So set lock_max accordingly.
+       set lkmax [expr $nentries * 2]
 
        puts "\tRecd016.a: Create environment and database"
-       set env_cmd "berkdb env -create -log_max $log_max -txn -home $testdir"
+       set env_cmd "berkdb_env -create -log_max $log_max \
+           -lock_max $lkmax -txn -home $testdir"
        set env [eval $env_cmd]
        error_check_good dbenv [is_valid_env $env] TRUE
-       set db [eval {berkdb_open -create} $omethod -env $env $args $testfile]
+       set db [eval {berkdb_open -create} \
+           $omethod -auto_commit -env $env $args $testfile]
        error_check_good dbopen [is_valid_db $db] TRUE
        set did [open $dict]
        set abid [open $t4 w]
@@ -149,8 +154,7 @@ proc recd016 { method args } {
        set env [eval $env_cmd]
        error_check_good dbenv [is_valid_env $env] TRUE
 
-       set txn ""
-       open_and_dump_file $testfile $env $txn $t1 $checkfunc \
+       open_and_dump_file $testfile $env $t1 $checkfunc \
            dump_file_direction "-first" "-next"
        filesort $t1 $t3
        error_check_good envclose [$env close] 0
index 53760e6..a4039d3 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2001
+# Copyright (c) 1996-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: recd15scr.tcl,v 1.3 2001/05/10 15:22:18 sue Exp 
+# Id: recd15scr.tcl,v 1.5 2002/01/30 13:18:04 margo Exp 
 #
 # Recd15 - lots of txns - txn prepare script
 # Usage: recd15script envcmd dbcmd gidf numtxns
@@ -37,7 +37,7 @@ error_check_good envopen [is_valid_env $dbenv] TRUE
 set usedb 0
 if { $dbfile != "NULL" } {
        set usedb 1
-       set db [berkdb_open -env $dbenv $dbfile]
+       set db [berkdb_open -auto_commit -env $dbenv $dbfile]
        error_check_good dbopen [is_valid_db $db] TRUE
 }
 
index f524bfc..b89cef4 100644 (file)
@@ -1,51 +1,96 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: rep001.tcl,v 11.3 2001/11/16 10:50:12 krinsky Exp 
+# Id: rep001.tcl,v 1.14 2002/08/08 18:13:12 sue Exp 
 #
 # TEST  rep001
-# TEST Replication smoke test.
+# TEST Replication rename and forced-upgrade test.
 # TEST
 # TEST Run a modified version of test001 in a replicated master environment;
 # TEST  verify that the database on the client is correct.
+# TEST Next, remove the database, close the master, upgrade the 
+# TEST client, reopen the master, and make sure the new master can correctly
+# TEST run test001 and propagate it in the other direction.
 
+proc rep001 { method { niter 1000 } { tnum "01" } args } {
+       global passwd
 
-proc rep001 { method args } {
+       puts "Rep0$tnum: Replication sanity test."
+
+       set envargs ""
+       rep001_sub $method $niter $tnum $envargs $args
+
+       puts "Rep0$tnum: Replication and security sanity test."
+       append envargs " -encryptaes $passwd "
+       append args " -encrypt "
+       rep001_sub $method $niter $tnum $envargs $args
+}
+
+proc rep001_sub { method niter tnum envargs largs } {
        source ./include.tcl
        global testdir
+       global encrypt
 
        env_cleanup $testdir
 
-       replsetup $testdir/REPDIR_MSGQUEUE
+       replsetup $testdir/MSGQUEUEDIR
 
-       set masterdir $testdir/REPDIR_MASTER
-       set clientdir $testdir/REPDIR_CLIENT
+       set masterdir $testdir/MASTERDIR
+       set clientdir $testdir/CLIENTDIR
 
        file mkdir $masterdir
        file mkdir $clientdir
 
-       puts "Rep001: Replication sanity test."
+       if { [is_record_based $method] == 1 } {
+               set checkfunc test001_recno.check
+       } else {
+               set checkfunc test001.check
+       }
 
        # Open a master.
        repladd 1
-       set masterenv [berkdb env -create -log_max 1000000 \
-           -home $masterdir -txn -rep_master -rep_transport [list 1 replsend]]
+       set masterenv \
+           [eval {berkdb_env -create -lock_max 2500 -log_max 1000000} \
+           $envargs {-home $masterdir -txn -rep_master -rep_transport \
+           [list 1 replsend]}]
        error_check_good master_env [is_valid_env $masterenv] TRUE
 
        # Open a client
        repladd 2
-       set clientenv [berkdb env -create \
-           -home $clientdir -txn -rep_client -rep_transport [list 2 replsend]]
+       set clientenv [eval {berkdb_env -create} $envargs -txn -lock_max 2500 \
+           {-home $clientdir -rep_client -rep_transport [list 2 replsend]}]
        error_check_good client_env [is_valid_env $clientenv] TRUE
 
-       # Run a modified test001 in the master.
-       puts "\tRep001.a: Running test001 in replicated env."
-       eval rep_test001 $method 10000 "01" -env $masterenv $args
+       # Bring the client online by processing the startup messages.
+       set donenow 0
+       while { 1 } {
+               set nproced 0
+
+               incr nproced [replprocessqueue $masterenv 1]
+               incr nproced [replprocessqueue $clientenv 2]
 
-       # Loop, processing first the master's messages, then the client's,
-       # until both queues are empty.
+               if { $nproced == 0 } {
+                       break
+               }
+       }
+
+       # Open a test database on the master (so we can test having handles
+       # open across an upgrade).
+       puts "\tRep0$tnum.a:\
+           Opening test database for post-upgrade client logging test."
+       set master_upg_db [berkdb_open \
+           -create -auto_commit -btree -env $masterenv rep0$tnum-upg.db]
+       set puttxn [$masterenv txn]
+       error_check_good master_upg_db_put \
+           [$master_upg_db put -txn $puttxn hello world] 0
+       error_check_good puttxn_commit [$puttxn commit] 0
+       error_check_good master_upg_db_close [$master_upg_db close] 0
+
+       # Run a modified test001 in the master (and update client).
+       puts "\tRep0$tnum.b: Running test001 in replicated env."
+       eval test001 $method $niter 0 $tnum 1 -env $masterenv $largs
        set donenow 0
        while { 1 } {
                set nproced 0
@@ -58,157 +103,147 @@ proc rep001 { method args } {
                }
        }
 
+       # Open the cross-upgrade database on the client and check its contents.
+       set client_upg_db [berkdb_open \
+            -create -auto_commit -btree -env $clientenv rep0$tnum-upg.db]
+       error_check_good client_upg_db_get [$client_upg_db get hello] \
+            [list [list hello world]]
+       # !!! We use this handle later.  Don't close it here.
+
        # Verify the database in the client dir.
-       puts "\tRep001.b: Verifying client database contents."
+       puts "\tRep0$tnum.c: Verifying client database contents."
+       set testdir [get_home $masterenv]
        set t1 $testdir/t1
        set t2 $testdir/t2
        set t3 $testdir/t3
-       open_and_dump_file test001.db $clientenv "" $testdir/t1 test001.check \
-           dump_file_direction "-first" "-next"
-       filesort $t1 $t3
-       error_check_good diff_files($t2,$t3) [filecmp $t2 $t3] 0
-
-       verify_dir $clientdir "\tRep001.c:" 0 0 1
-}
+       open_and_dump_file test0$tnum.db $clientenv $t1 \
+           $checkfunc dump_file_direction "-first" "-next"
+
+       # Remove the file (and update client).
+       puts "\tRep0$tnum.d: Remove the file on the master and close master."
+       error_check_good remove \
+           [$masterenv dbremove -auto_commit test0$tnum.db] 0
+       error_check_good masterenv_close [$masterenv close] 0
+       set donenow 0
+       while { 1 } {
+               set nproced 0
 
-proc rep_test001 { method {nentries 10000} {tnum "01"} args } {
-       source ./include.tcl
+               incr nproced [replprocessqueue $masterenv 1]
+               incr nproced [replprocessqueue $clientenv 2]
 
-       set args [convert_args $method $args]
-       set omethod [convert_method $method]
-
-       puts "\tRep0$tnum: $method ($args) $nentries equal key/data pairs"
-
-       # Create the database and open the dictionary
-       set eindex [lsearch -exact $args "-env"]
-       #
-       # If we are using an env, then testfile should just be the db name.
-       # Otherwise it is the test directory and the name.
-       # If we are not using an external env, then test setting
-       # the database cache size and using multiple caches.
-       if { $eindex == -1 } {
-               set testfile $testdir/test0$tnum.db
-               append args " -cachesize {0 1048576 3} "
-               set env NULL
-       } else {
-               set testfile test0$tnum.db
-               incr eindex
-               set env [lindex $args $eindex]
+               if { $nproced == 0 } {
+                       break
+               }
        }
-       set t1 $testdir/t1
-       set t2 $testdir/t2
-       set t3 $testdir/t3
-       set db [eval {berkdb_open \
-            -create -mode 0644} $args $omethod $testfile]
-       error_check_good dbopen [is_valid_db $db] TRUE
-       set did [open $dict]
 
-       set pflags ""
-       set gflags ""
-       set txn ""
+       # Don't get confused in Tcl.
+       puts "\tRep0$tnum.e: Upgrade client."
+       set newmasterenv $clientenv
+       error_check_good upgrade_client [$newmasterenv rep_start -master] 0
 
-       if { [is_record_based $method] == 1 } {
-               set checkfunc test001_recno.check
-               append gflags " -recno"
-       } else {
-               set checkfunc test001.check
+       # Run test001 in the new master
+       puts "\tRep0$tnum.f: Running test001 in new master."
+       eval test001 $method $niter 0 $tnum 1 -env $newmasterenv $largs
+       set donenow 0
+       while { 1 } {
+               set nproced 0
+
+               incr nproced [replprocessqueue $newmasterenv 2]
+
+               if { $nproced == 0 } {
+                       break
+               }
        }
-       puts "\t\tRep0$tnum.a: put/get loop"
-       # Here is the loop where we put and get each key/data pair
-       set count 0
-       while { [gets $did str] != -1 && $count < $nentries } {
-               if { [is_record_based $method] == 1 } {
-                       global kvals
-
-                       set key [expr $count + 1]
-                       if { 0xffffffff > 0 && $key > 0xffffffff } {
-                               set key [expr $key - 0x100000000]
-                       }
-                       if { $key == 0 || $key - 0xffffffff == 1 } {
-                               incr key
-                               incr count
-                       }
-                       set kvals($key) [pad_data $method $str]
-               } else {
-                       set key $str
-                       set str [reverse $str]
+
+       puts "\tRep0$tnum.g: Reopen old master as client and catch up."
+       # Throttle master so it can't send everything at once
+       $newmasterenv rep_limit 0 [expr 64 * 1024]
+       set newclientenv [eval {berkdb_env -create -recover} $envargs \
+           -txn -lock_max 2500 \
+           {-home $masterdir -rep_client -rep_transport [list 1 replsend]}]
+       error_check_good newclient_env [is_valid_env $newclientenv] TRUE
+       set donenow 0
+       while { 1 } {
+               set nproced 0
+
+               incr nproced [replprocessqueue $newclientenv 1]
+               incr nproced [replprocessqueue $newmasterenv 2]
+
+               if { $nproced == 0 } {
+                       break
                }
-               set curtxn [$env txn]
-               set ret [eval {$db put} \
-                   -txn $curtxn $pflags {$key [chop_data $method $str]}]
-               error_check_good put $ret 0
-               error_check_good txn_commit($key) [$curtxn commit] 0
-
-               set ret [eval {$db get} $gflags {$key}]
-               error_check_good \
-                   get $ret [list [list $key [pad_data $method $str]]]
-
-               # Test DB_GET_BOTH for success
-               set ret [$db get -get_both $key [pad_data $method $str]]
-               error_check_good \
-                   getboth $ret [list [list $key [pad_data $method $str]]]
-
-               # Test DB_GET_BOTH for failure
-               set ret [$db get -get_both $key [pad_data $method BAD$str]]
-               error_check_good getbothBAD [llength $ret] 0
-
-               incr count
        }
-       close $did
-       # Now we will get each key from the DB and compare the results
-       # to the original.
-       puts "\t\tRep0$tnum.b: dump file"
-       dump_file $db $txn $t1 $checkfunc
-       error_check_good db_close [$db close] 0
-
-       # Now compare the keys to see if they match the dictionary (or ints)
-       if { [is_record_based $method] == 1 } {
-               set oid [open $t2 w]
-               for {set i 1} {$i <= $nentries} {incr i} {
-                       set j [expr $i]
-                       if { 0xffffffff > 0 && $j > 0xffffffff } {
-                               set j [expr $j - 0x100000000]
-                       }
-                       if { $j == 0 } {
-                               incr i
-                               incr j
-                       }
-                       puts $oid $j
+       set stats [$newmasterenv rep_stat]
+       set nthrottles [getstats $stats {Transmission limited}]
+       error_check_bad nthrottles $nthrottles -1
+       error_check_bad nthrottles $nthrottles 0
+
+       # Run a modified test001 in the new master (and update client).
+       puts "\tRep0$tnum.h: Running test001 in new master."
+       eval test001 $method \
+           $niter $niter $tnum 1 -env $newmasterenv $largs
+       set donenow 0
+       while { 1 } {
+               set nproced 0
+
+               incr nproced [replprocessqueue $newclientenv 1]
+               incr nproced [replprocessqueue $newmasterenv 2]
+
+               if { $nproced == 0 } {
+                       break
                }
-               close $oid
-       } else {
-               set q q
-               filehead $nentries $dict $t2
        }
-       filesort $t2 $t3
-       file rename -force $t3 $t2
-       filesort $t1 $t3
-
-       error_check_good \tRep0$tnum:diff($t3,$t2) \
-           [filecmp $t3 $t2] 0
-
-       puts "\t\tRep0$tnum.c: close, open, and dump file"
-       # Now, reopen the file and run the last test again.
-       open_and_dump_file $testfile $env $txn $t1 $checkfunc \
-           dump_file_direction "-first" "-next"
-       if { [string compare $omethod "-recno"] != 0 } {
-               filesort $t1 $t3
+
+       # Test put to the database handle we opened back when the new master
+       # was a client.
+       puts "\tRep0$tnum.i: Test put to handle opened before upgrade."
+       set puttxn [$newmasterenv txn]
+       error_check_good client_upg_db_put \
+           [$client_upg_db put -txn $puttxn hello there] 0
+       error_check_good puttxn_commit [$puttxn commit] 0
+       set donenow 0
+       while { 1 } {
+               set nproced 0
+
+               incr nproced [replprocessqueue $newclientenv 1]
+               incr nproced [replprocessqueue $newmasterenv 2]
+
+               if { $nproced == 0 } {
+                       break
+               }
        }
 
-       error_check_good \tRep0$tnum:diff($t2,$t3) \
-           [filecmp $t2 $t3] 0
+       # Close the new master's handle for the upgrade-test database;  we
+       # don't need it.  Then check to make sure the client did in fact
+       # update the database.
+       error_check_good client_upg_db_close [$client_upg_db close] 0
+       set newclient_upg_db [berkdb_open -env $newclientenv rep0$tnum-upg.db]
+       error_check_good newclient_upg_db_get [$newclient_upg_db get hello] \
+           [list [list hello there]]
+       error_check_good newclient_upg_db_close [$newclient_upg_db close] 0
 
-       # Now, reopen the file and run the last test again in the
-       # reverse direction.
-       puts "\t\tRep0$tnum.d: close, open, and dump file in reverse direction"
-       open_and_dump_file $testfile $env $txn $t1 $checkfunc \
-           dump_file_direction "-last" "-prev"
+       # Verify the database in the client dir.
+       puts "\tRep0$tnum.j: Verifying new client database contents."
+       set testdir [get_home $newmasterenv]
+       set t1 $testdir/t1
+       set t2 $testdir/t2
+       set t3 $testdir/t3
+       open_and_dump_file test0$tnum.db $newclientenv $t1 \
+           $checkfunc dump_file_direction "-first" "-next"
 
-       if { [string compare $omethod "-recno"] != 0 } {
+       if { [string compare [convert_method $method] -recno] != 0 } {
                filesort $t1 $t3
        }
+       error_check_good diff_files($t2,$t3) [filecmp $t2 $t3] 0
 
-       error_check_good \tRep0$tnum:diff($t3,$t2) \
-           [filecmp $t3 $t2] 0
-}
 
+       error_check_good newmasterenv_close [$newmasterenv close] 0
+       error_check_good newclientenv_close [$newclientenv close] 0
+
+       if { [lsearch $envargs "-encrypta*"] !=-1 } {
+               set encrypt 1
+       }
+       error_check_good verify \
+           [verify_dir $clientdir "\tRep0$tnum.k: " 0 0 1] 0
+       replclose $testdir/MSGQUEUEDIR
+}
index d41886a..ed0aa78 100644 (file)
@@ -1,14 +1,32 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: reputils.tcl,v 11.3 2001/11/16 00:36:20 krinsky Exp 
+# Id: reputils.tcl,v 11.34 2002/08/12 17:54:18 sandstro Exp 
 #
 # Replication testing utilities
 
 # Environment handle for the env containing the replication "communications
 # structure" (really a CDB environment).
+
+# The test environment consists of a queue and a # directory (environment)
+# per replication site.  The queue is used to hold messages destined for a
+# particular site and the directory will contain the environment for the
+# site.  So the environment looks like:
+#                              $testdir
+#                       ___________|______________________________
+#                      /           |              \               \
+#              MSGQUEUEDIR     MASTERDIR       CLIENTDIR.0 ... CLIENTDIR.N-1
+#              | | ... |
+#              1 2 .. N+1
+#
+# The master is site 1 in the MSGQUEUEDIR and clients 1-N map to message
+# queues 2 - N+1.
+#
+# The globals repenv(1-N) contain the environment handles for the sites
+# with a given id (i.e., repenv(1) is the master's environment.
+
 global queueenv
 
 # Array of DB handles, one per machine ID, for the databases that contain
@@ -16,13 +34,347 @@ global queueenv
 global queuedbs
 global machids
 
+global elect_timeout
+set elect_timeout 50000000
+set drop 0
+
+# Create the directory structure for replication testing.
+# Open the master and client environments; store these in the global repenv
+# Return the master's environment: "-env masterenv"
+#
+proc repl_envsetup { envargs largs tnum {nclients 1} {droppct 0} { oob 0 } } {
+       source ./include.tcl
+       global clientdir
+       global drop drop_msg
+       global masterdir
+       global repenv
+       global testdir
+
+       env_cleanup $testdir
+
+       replsetup $testdir/MSGQUEUEDIR
+
+       set masterdir $testdir/MASTERDIR
+       file mkdir $masterdir
+       if { $droppct != 0 } {
+               set drop 1
+               set drop_msg [expr 100 / $droppct]
+       } else {
+               set drop 0
+       }
+
+       for { set i 0 } { $i < $nclients } { incr i } {
+               set clientdir($i) $testdir/CLIENTDIR.$i
+               file mkdir $clientdir($i)
+       }
+
+       # Open a master.
+       repladd 1
+       #
+       # Set log smaller than default to force changing files,
+       # but big enough so that the tests that use binary files
+       # as keys/data can run.
+       #
+       set lmax [expr 3 * 1024 * 1024]
+       set masterenv [eval {berkdb_env -create -log_max $lmax} $envargs \
+           {-home $masterdir -txn -rep_master -rep_transport \
+           [list 1 replsend]}]
+       error_check_good master_env [is_valid_env $masterenv] TRUE
+       set repenv(master) $masterenv
+
+       # Open clients
+       for { set i 0 } { $i < $nclients } { incr i } {
+               set envid [expr $i + 2]
+               repladd $envid
+               set clientenv [eval {berkdb_env -create} $envargs -txn \
+                   {-cachesize { 0 10000000 0 }} -lock_max 10000 \
+                   {-home $clientdir($i) -rep_client -rep_transport \
+                   [list $envid replsend]}]
+               error_check_good client_env [is_valid_env $clientenv] TRUE
+               set repenv($i) $clientenv
+       }
+       set repenv($i) NULL
+       append largs " -env $masterenv "
+
+       # Process startup messages
+       repl_envprocq $tnum $nclients $oob
+
+       return $largs
+}
+
+# Process all incoming messages.  Iterate until there are no messages left
+# in anyone's queue so that we capture all message exchanges. We verify that
+# the requested number of clients matches the number of client environments
+# we have.  The oob parameter indicates if we should process the queue
+# with out-of-order delivery.  The replprocess procedure actually does
+# the real work of processing the queue -- this routine simply iterates
+# over the various queues and does the initial setup.
+
+proc repl_envprocq { tnum { nclients 1 } { oob 0 }} {
+       global repenv
+       global drop
+
+       set masterenv $repenv(master)
+       for { set i 0 } { 1 } { incr i } {
+               if { $repenv($i) == "NULL"} {
+                       break
+               }
+       }
+       error_check_good i_nclients $nclients $i
+
+       set name [format "Repl%03d" $tnum]
+       berkdb debug_check
+       puts -nonewline "\t$name: Processing master/$i client queues"
+       set rand_skip 0
+       if { $oob } {
+               puts " out-of-order"
+       } else {
+               puts " in order"
+       }
+       set do_check 1
+       set droprestore $drop
+       while { 1 } {
+               set nproced 0
+
+               if { $oob } {
+                       set rand_skip [berkdb random_int 2 10]
+               }
+               incr nproced [replprocessqueue $masterenv 1 $rand_skip]
+               for { set i 0 } { $i < $nclients } { incr i } {
+                       set envid [expr $i + 2]
+                       if { $oob } {
+                               set rand_skip [berkdb random_int 2 10]
+                       }
+                       set n [replprocessqueue $repenv($i) \
+                           $envid $rand_skip]
+                       incr nproced $n
+               }
+
+               if { $nproced == 0 } {
+                       # Now that we delay requesting records until
+                       # we've had a few records go by, we should always
+                       # see that the number of requests is lower than the
+                       # number of messages that were enqueued.
+                       for { set i 0 } { $i < $nclients } { incr i } {
+                               set clientenv $repenv($i)
+                               set stats [$clientenv rep_stat]
+                               set queued [getstats $stats  \
+                                  {Total log records queued}]
+                               error_check_bad queued_stats \
+                                   $queued -1
+                               set requested [getstats $stats \
+                                  {Log records requested}]
+                               error_check_bad requested_stats \
+                                   $requested -1
+                               if { $queued != 0 && $do_check != 0 } {
+                                       error_check_good num_requested \
+                                           [expr $requested < $queued] 1
+                               }
+
+                               $clientenv rep_request 1 1
+                       }
+
+                       # If we were dropping messages, we might need
+                       # to flush the log so that we get everything
+                       # and end up in the right state.
+                       if { $drop != 0 } {
+                               set drop 0
+                               set do_check 0
+                               $masterenv rep_flush
+                               berkdb debug_check
+                               puts "\t$name: Flushing Master"
+                       } else {
+                               break
+                       }
+               }
+       }
+
+       # Reset the clients back to the default state in case we
+       # have more processing to do.
+       for { set i 0 } { $i < $nclients } { incr i } {
+               set clientenv $repenv($i)
+               $clientenv rep_request 4 128
+       }
+       set drop $droprestore
+}
+
+# Verify that the directories in the master are exactly replicated in
+# each of the client environments.
+
+proc repl_envver0 { tnum method { nclients 1 } } {
+       global clientdir
+       global masterdir
+       global repenv
+
+       # Verify the database in the client dir.
+       # First dump the master.
+       set t1 $masterdir/t1
+       set t2 $masterdir/t2
+       set t3 $masterdir/t3
+       set omethod [convert_method $method]
+       set name [format "Repl%03d" $tnum]
+
+       #
+       # We are interested in the keys of whatever databases are present
+       # in the master environment, so we just call a no-op check function
+       # since we have no idea what the contents of this database really is.
+       # We just need to walk the master and the clients and make sure they
+       # have the same contents.
+       #
+       set cwd [pwd]
+       cd $masterdir
+       set stat [catch {glob test*.db} dbs]
+       cd $cwd
+       if { $stat == 1 } {
+               return
+       }
+       foreach testfile $dbs {
+               open_and_dump_file $testfile $repenv(master) $masterdir/t2 \
+                   repl_noop dump_file_direction "-first" "-next"
+
+               if { [string compare [convert_method $method] -recno] != 0 } {
+                       filesort $t2 $t3
+                       file rename -force $t3 $t2
+               }
+               for { set i 0 } { $i < $nclients } { incr i } {
+                       puts "\t$name: Verifying client $i database \
+                           $testfile contents."
+                       open_and_dump_file $testfile $repenv($i) \
+                           $t1 repl_noop dump_file_direction "-first" "-next"
+
+                       if { [string compare $omethod "-recno"] != 0 } {
+                               filesort $t1 $t3
+                       } else {
+                               catch {file copy -force $t1 $t3} ret
+                       }
+                       error_check_good diff_files($t2,$t3) [filecmp $t2 $t3] 0
+               }
+       }
+}
+
+# Remove all the elements from the master and verify that these
+# deletions properly propagated to the clients.
+
+proc repl_verdel { tnum method { nclients 1 } } {
+       global clientdir
+       global masterdir
+       global repenv
+
+       # Delete all items in the master.
+       set name [format "Repl%03d" $tnum]
+       set cwd [pwd]
+       cd $masterdir
+       set stat [catch {glob test*.db} dbs]
+       cd $cwd
+       if { $stat == 1 } {
+               return
+       }
+       foreach testfile $dbs {
+               puts "\t$name: Deleting all items from the master."
+               set txn [$repenv(master) txn]
+               error_check_good txn_begin [is_valid_txn $txn \
+                   $repenv(master)] TRUE
+               set db [berkdb_open -txn $txn -env $repenv(master) $testfile]
+               error_check_good reopen_master [is_valid_db $db] TRUE
+               set dbc [$db cursor -txn $txn]
+               error_check_good reopen_master_cursor \
+                   [is_valid_cursor $dbc $db] TRUE
+               for { set dbt [$dbc get -first] } { [llength $dbt] > 0 } \
+                   { set dbt [$dbc get -next] } {
+                       error_check_good del_item [$dbc del] 0
+               }
+               error_check_good dbc_close [$dbc close] 0
+               error_check_good txn_commit [$txn commit] 0
+               error_check_good db_close [$db close] 0
+
+               repl_envprocq $tnum $nclients
+
+               # Check clients.
+               for { set i 0 } { $i < $nclients } { incr i } {
+                       puts "\t$name: Verifying emptiness of client database $i."
+
+                       set db [berkdb_open -env $repenv($i) $testfile]
+                       error_check_good reopen_client($i) \
+                           [is_valid_db $db] TRUE
+                       set dbc [$db cursor]
+                       error_check_good reopen_client_cursor($i) \
+                           [is_valid_cursor $dbc $db] TRUE
+
+                       error_check_good client($i)_empty \
+                           [llength [$dbc get -first]] 0
+
+                       error_check_good dbc_close [$dbc close] 0
+                       error_check_good db_close [$db close] 0
+               }
+       }
+}
+
+# Replication "check" function for the dump procs that expect to
+# be able to verify the keys and data.
+proc repl_noop { k d } {
+       return
+}
+
+# Close all the master and client environments in a replication test directory.
+proc repl_envclose { tnum envargs } {
+       source ./include.tcl
+       global clientdir
+       global encrypt
+       global masterdir
+       global repenv
+       global testdir
+
+       if { [lsearch $envargs "-encrypta*"] !=-1 } {
+               set encrypt 1
+       }
+
+       # In order to make sure that we have fully-synced and ready-to-verify
+       # databases on all the clients, do a checkpoint on the master and
+       # process messages in order to flush all the clients.
+       set drop 0
+       set do_check 0
+       set name [format "Repl%03d" $tnum]
+       berkdb debug_check
+       puts "\t$name: Checkpointing master."
+       error_check_good masterenv_ckp [$repenv(master) txn_checkpoint] 0
+
+       # Count clients.
+       for { set ncli 0 } { 1 } { incr ncli } {
+               if { $repenv($ncli) == "NULL" } {
+                       break
+               }
+       }
+       repl_envprocq $tnum $ncli
+
+       error_check_good masterenv_close [$repenv(master) close] 0
+       verify_dir $masterdir "\t$name: " 0 0 1
+       for { set i 0 } { $i < $ncli } { incr i } {
+               error_check_good client($i)_close [$repenv($i) close] 0
+               verify_dir $clientdir($i) "\t$name: " 0 0 1
+       }
+       replclose $testdir/MSGQUEUEDIR
+
+}
+
+# Close up a replication group
+proc replclose { queuedir } {
+       global queueenv queuedbs machids
+
+       foreach m $machids {
+               set db $queuedbs($m)
+               error_check_good dbr_close [$db close] 0
+       }
+       error_check_good qenv_close [$queueenv close] 0
+       set machids {}
+}
+
 # Create a replication group for testing.
 proc replsetup { queuedir } {
        global queueenv queuedbs machids
 
        file mkdir $queuedir
        set queueenv \
-           [berkdb env -create -cdb -home $queuedir]
+           [berkdb_env -create -txn -lock_max 20000 -home $queuedir]
        error_check_good queueenv [is_valid_env $queueenv] TRUE
 
        if { [info exists queuedbs] } {
@@ -33,18 +385,30 @@ proc replsetup { queuedir } {
        return $queueenv
 }
 
+# Send function for replication.
 proc replsend { control rec fromid toid } {
-       global queuedbs machids
-
+       global queuedbs queueenv machids
+       global drop drop_msg
 
+       #
+       # If we are testing with dropped messages, then we drop every
+       # $drop_msg time.  If we do that just return 0 and don't do
+       # anything.
+       #
+       if { $drop != 0 } {
+               incr drop
+               if { $drop == $drop_msg } {
+                       set drop 1
+                       return 0
+               }
+       }
        # XXX
        # -1 is DB_BROADCAST_MID
        if { $toid == -1 } {
                set machlist $machids
        } else {
                if { [info exists queuedbs($toid)] != 1 } {
-                       puts stderr "FAIL: replsend: machid $toid not found"
-                       return -1
+                       error "replsend: machid $toid not found"
                }
                set machlist [list $toid]
        }
@@ -56,13 +420,34 @@ proc replsend { control rec fromid toid } {
                }
 
                set db $queuedbs($m)
-
-               $db put -append [list $control $rec $fromid]
+               set txn [$queueenv txn]
+               $db put -txn $txn -append [list $control $rec $fromid]
+               error_check_good replsend_commit [$txn commit] 0
        }
 
        return 0
 }
 
+# Nuke all the pending messages for a particular site.
+proc replclear { machid } {
+       global queuedbs queueenv
+
+       if { [info exists queuedbs($machid)] != 1 } {
+               error "FAIL: replclear: machid $machid not found"
+       }
+
+       set db $queuedbs($machid)
+       set txn [$queueenv txn]
+       set dbc [$db cursor -txn $txn]
+       for { set dbt [$dbc get -rmw -first] } { [llength $dbt] > 0 } \
+           { set dbt [$dbc get -rmw -next] } {
+               error_check_good replclear($machid)_del [$dbc del] 0
+       }
+       error_check_good replclear($machid)_dbc_close [$dbc close] 0
+       error_check_good replclear($machid)_txn_commit [$txn commit] 0
+}
+
+# Add a machine to a replication environment.
 proc repladd { machid } {
        global queueenv queuedbs machids
 
@@ -70,19 +455,41 @@ proc repladd { machid } {
                error "FAIL: repladd: machid $machid already exists"
        }
 
-       set queuedbs($machid) \
-           [berkdb open -env $queueenv -create -recno repqueue$machid.db]
+       set queuedbs($machid) [berkdb open -auto_commit \
+           -env $queueenv -create -recno -renumber repqueue$machid.db]
        error_check_good repqueue_create [is_valid_db $queuedbs($machid)] TRUE
 
        lappend machids $machid
 }
 
-proc replprocessqueue { dbenv machid } {
-       global queuedbs
+# Process a queue of messages, skipping every "skip_interval" entry.
+# We traverse the entire queue, but since we skip some messages, we
+# may end up leaving things in the queue, which should get picked up
+# on a later run.
+
+proc replprocessqueue { dbenv machid { skip_interval 0 } \
+    { hold_electp NONE } { newmasterp NONE } } {
+       global queuedbs queueenv errorCode
+
+       # hold_electp is a call-by-reference variable which lets our caller
+       # know we need to hold an election.
+       if { [string compare $hold_electp NONE] != 0 } {
+               upvar $hold_electp hold_elect
+       }
+       set hold_elect 0
+
+       # newmasterp is the same idea, only returning the ID of a master
+       # given in a DB_REP_NEWMASTER return.
+       if { [string compare $newmasterp NONE] != 0 } {
+               upvar $newmasterp newmaster
+       }
+       set newmaster 0
 
        set nproced 0
 
-       set dbc [$queuedbs($machid) cursor -update]
+       set txn [$queueenv txn]
+       set dbc [$queuedbs($machid) cursor -txn $txn]
+
        error_check_good process_dbc($machid) \
            [is_valid_cursor $dbc $queuedbs($machid)] TRUE
 
@@ -91,18 +498,162 @@ proc replprocessqueue { dbenv machid } {
            { set dbt [$dbc get -next] } {
                set data [lindex [lindex $dbt 0] 1]
 
-               # XXX
-               # It would be nice to make sure that NEWMASTER messages
-               # indicate the right master.  We don't have the necessary
-               # info in here, though.
-               $dbenv rep_process_message \
-                   [lindex $data 2] [lindex $data 0] [lindex $data 1]
+               # If skip_interval is nonzero, we want to process messages
+               # out of order.  We do this in a simple but slimy way--
+               # continue walking with the cursor without processing the
+               # message or deleting it from the queue, but do increment
+               # "nproced".  The way this proc is normally used, the
+               # precise value of nproced doesn't matter--we just don't
+               # assume the queues are empty if it's nonzero.  Thus,
+               # if we contrive to make sure it's nonzero, we'll always
+               # come back to records we've skipped on a later call
+               # to replprocessqueue.  (If there really are no records,
+               # we'll never get here.)
+               #
+               # Skip every skip_interval'th record (and use a remainder other
+               # than zero so that we're guaranteed to really process at least
+               # one record on every call).
+               if { $skip_interval != 0 } {
+                       if { $nproced % $skip_interval == 1 } {
+                               incr nproced
+                               continue
+                       }
+               }
+
+               # We have to play an ugly cursor game here:  we currently
+               # hold a lock on the page of messages, but rep_process_message
+               # might need to lock the page with a different cursor in
+               # order to send a response.  So save our recno, close
+               # the cursor, and then reopen and reset the cursor.
+               set recno [lindex [lindex $dbt 0] 0]
+               error_check_good dbc_process_close [$dbc close] 0
+               error_check_good txn_commit [$txn commit] 0
+               set ret [catch {$dbenv rep_process_message \
+                   [lindex $data 2] [lindex $data 0] [lindex $data 1]} res]
+               set txn [$queueenv txn]
+               set dbc [$queuedbs($machid) cursor -txn $txn]
+               set dbt [$dbc get -set $recno]
+
+               if { $ret != 0 } {
+                       if { [is_substr $res DB_REP_HOLDELECTION] } {
+                               set hold_elect 1
+                       } else {
+                               error "FAIL:[timestamp]\
+                                   rep_process_message returned $res"
+                       }
+               }
 
                incr nproced
 
                $dbc del
+
+               if { $ret == 0 && $res != 0 } {
+                       if { [is_substr $res DB_REP_NEWSITE] } {
+                               # NEWSITE;  do nothing.
+                       } else {
+                               set newmaster $res
+                               # Break as soon as we get a NEWMASTER message;
+                               # our caller needs to handle it.
+                               break
+                       }
+               }
+
+               if { $hold_elect == 1 } {
+                       # Break also on a HOLDELECTION, for the same reason.
+                       break
+               }
+
        }
 
+       error_check_good dbc_close [$dbc close] 0
+       error_check_good txn_commit [$txn commit] 0
+
        # Return the number of messages processed.
        return $nproced
 }
+
+set run_repl_flag "-run_repl"
+
+proc extract_repl_args { args } {
+       global run_repl_flag
+
+       for { set arg [lindex $args [set i 0]] } \
+           { [string length $arg] > 0 } \
+           { set arg [lindex $args [incr i]] } {
+               if { [string compare $arg $run_repl_flag] == 0 } {
+                       return [lindex $args [expr $i + 1]]
+               }
+       }
+       return ""
+}
+
+proc delete_repl_args { args } {
+       global run_repl_flag
+
+       set ret {}
+
+       for { set arg [lindex $args [set i 0]] } \
+           { [string length $arg] > 0 } \
+           { set arg [lindex $args [incr i]] } {
+               if { [string compare $arg $run_repl_flag] != 0 } {
+                       lappend ret $arg
+               } else {
+                       incr i
+               }
+       }
+       return $ret
+}
+
+global elect_serial
+global elections_in_progress
+set elect_serial 0
+
+# Start an election in a sub-process.
+proc start_election { qdir envstring nsites pri timeout {err "none"}} {
+       source ./include.tcl
+       global elect_serial elect_timeout elections_in_progress machids
+
+       incr elect_serial
+
+       set t [open "|$tclsh_path >& $testdir/ELECTION_OUTPUT.$elect_serial" w]
+
+       puts $t "source $test_path/test.tcl"
+       puts $t "replsetup $qdir"
+       foreach i $machids { puts $t "repladd $i" }
+       puts $t "set env_cmd \{$envstring\}"
+       puts $t "set dbenv \[eval \$env_cmd -errfile \
+           $testdir/ELECTION_ERRFILE.$elect_serial -errpfx FAIL: \]"
+# puts "Start election err $err, env $envstring"
+       puts $t "\$dbenv test abort $err"
+       puts $t "set res \[catch \{\$dbenv rep_elect $nsites $pri \
+           $elect_timeout\} ret\]"
+       if { $err != "none" } {
+               puts $t "\$dbenv test abort none"
+               puts $t "set res \[catch \{\$dbenv rep_elect $nsites $pri \
+                   $elect_timeout\} ret\]"
+       }
+       flush $t
+
+       set elections_in_progress($elect_serial) $t
+       return $elect_serial
+}
+
+proc close_election { i } {
+       global elections_in_progress
+       set t $elections_in_progress($i)
+       puts $t "\$dbenv close"
+       close $t
+       unset elections_in_progress($i)
+}
+
+proc cleanup_elections { } {
+       global elect_serial elections_in_progress
+
+       for { set i 0 } { $i <= $elect_serial } { incr i } {
+               if { [info exists elections_in_progress($i)] != 0 } {
+                       close_election $i
+               }
+       }
+
+       set elect_serial 0
+}
index e5ad7d4..9b462fa 100644 (file)
@@ -1,14 +1,15 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2003
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: rpc003.tcl,v 11.5 2001/08/29 19:07:42 sue Exp 
+# Id: rpc003.tcl,v 11.9 2002/07/16 20:53:03 bostic Exp 
 #
 # Test RPC and secondary indices.
 proc rpc003 { } {
        source ./include.tcl
        global dict nsecondaries
+       global rpc_svc
 
        #
        # First set up the files.  Secondary indices only work readonly
@@ -39,7 +40,7 @@ proc rpc003 { } {
 
        # Open an environment
        # XXX if one is not supplied!
-       set env [berkdb env -create -home $testdir]
+       set env [berkdb_env -create -home $testdir]
        error_check_good env_open [is_valid_env $env] TRUE
 
        # Open the primary.
@@ -84,12 +85,12 @@ proc rpc003 { } {
        # We have set up our databases, so now start the server and
        # read them over RPC.
        #
-       set dpid [exec $util_path/berkeley_db_svc -h $rpc_testdir &]
+       set dpid [exec $util_path/$rpc_svc -h $rpc_testdir &]
        puts "\tRpc003.c: Started server, pid $dpid"
        tclsleep 2
 
        set home [file tail $rpc_testdir]
-       set env [eval {berkdb env -create -mode 0644 -home $home \
+       set env [eval {berkdb_env_noerr -create -mode 0644 -home $home \
            -server $rpc_server}]
        error_check_good lock_env:open [is_valid_env $env] TRUE
 
@@ -141,11 +142,9 @@ proc rpc003 { } {
        error_check_good primary_close [$pdb close] 0
        error_check_good env_close [$env close] 0
 
-       exec $KILL $dpid
-       return
+       tclkill $dpid
 }
 
-
 proc rpc003_assoc_err { popen sopen msg } {
        set pdb [eval $popen]
        error_check_good assoc_err_popen [is_valid_db $pdb] TRUE
index 32c0cb7..1ee3d83 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: rsrc004.tcl,v 11.2 2001/08/03 16:39:29 bostic Exp 
+# Id: rsrc004.tcl,v 11.3 2002/01/11 15:53:33 bostic Exp 
 #
 # TEST rsrc004
 # TEST Recno backing file test for EOF-terminated records.
index 00197e9..f520491 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.code,v 1.9 2001/10/17 16:15:22 bostic Exp 
+# Id: chk.code,v 1.10 2002/02/04 16:03:26 bostic Exp 
 #
 # Check to make sure that the code samples in the documents build.
 
@@ -26,7 +26,7 @@ for i in `find $d/docs_src -name '*.cs'`; do
            -e 's/__LB__/[/g' \
            -e 's/__LT__/</g' \
            -e 's/__RB__/]/g' < $i > t.c
-       if cc -Wall -I.. t.c ../libdb.a -o t; then
+       if cc -Wall -Werror -I.. t.c ../libdb.a -o t; then
                :
        else
                echo "FAIL: unable to compile $i"
index 508a69b..2a8a88c 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.def,v 1.7 2001/10/12 17:55:31 bostic Exp 
+# Id: chk.def,v 1.9 2002/03/27 04:32:57 bostic Exp 
 #
 # Check to make sure we haven't forgotten to add any interfaces
 # to the Win32 libdb.def file.
@@ -26,7 +26,7 @@ sed '/; /d' $f |
        -e '/^__/d' -e '/^;/d' |
     sort > $t1
 
-egrep __P $d/include_auto/global_ext.in |
+egrep __P $d/dbinc_auto/ext_prot.in |
     sed '/^[a-z]/!d' |
     awk '{print $2}' |
     sed 's/^\*//' |
index ea47734..b4c4e4b 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.define,v 1.15 2001/10/12 17:55:32 bostic Exp 
+# Id: chk.define,v 1.21 2002/03/27 04:32:58 bostic Exp 
 #
 # Check to make sure that all #defines are actually used.
 
@@ -14,61 +14,62 @@ d=../..
 exitv=0
 t1=__1
 t2=__2
+t3=__3
 
-egrep '^#define' $d/include/*.h $d/include/*.in |
+egrep '^#define' $d/dbinc/*.h $d/dbinc/*.in |
     sed -e '/db_185.in/d' -e '/xa.h/d' |
     awk '{print $2}' |
-    sed -e '/^ALIGNP/d' \
-       -e '/^B_DELETE/d' \
+    sed -e '/^B_DELETE/d' \
        -e '/^B_MAX/d' \
-       -e '/^CIRCLEQ/d' \
-       -e '/^DB_AM_TXN/d' \
+       -e '/^CIRCLEQ_/d' \
        -e '/^DB_BTREEOLDVER/d' \
        -e '/^DB_HASHOLDVER/d' \
        -e '/^DB_LOCKVERSION/d' \
        -e '/^DB_MAX_PAGES/d' \
        -e '/^DB_QAMOLDVER/d' \
-       -e '/^DB_RO_ACCESS/d' \
        -e '/^DB_TXNVERSION/d' \
+       -e '/^DB_UNUSED/d' \
        -e '/^DEFINE_DB_CLASS/d' \
-       -e '/^LIST/d' \
+       -e '/^HASH_UNUSED/d' \
+       -e '/^LIST_/d' \
        -e '/^LOG_OP/d' \
        -e '/^MINFILL/d' \
        -e '/^MUTEX_FIELDS/d' \
        -e '/^NCACHED2X/d' \
        -e '/^NCACHED30/d' \
        -e '/^PAIR_MASK/d' \
-       -e '/^POWER_OF_TWO/d' \
        -e '/^P_16_COPY/d' \
        -e '/^P_32_COPY/d' \
        -e '/^P_32_SWAP/d' \
-       -e '/^SH_CIRCLEQ/d' \
-       -e '/^SH_LIST/d' \
-       -e '/^SH_TAILQ/d' \
-       -e '/^TAILQ/d' \
+       -e '/^P_TO_UINT16/d' \
+       -e '/^QPAGE_CHKSUM/d' \
+       -e '/^QPAGE_NORMAL/d' \
+       -e '/^QPAGE_SEC/d' \
+       -e '/^SH_CIRCLEQ_/d' \
+       -e '/^SH_LIST_/d' \
+       -e '/^SH_TAILQ_/d' \
+       -e '/^SIZEOF_PAGE/d' \
+       -e '/^TAILQ_/d' \
        -e '/^WRAPPED_CLASS/d' \
-       -e '/^XA_$/d' \
        -e '/^__BIT_TYPES_DEFINED__/d' \
        -e '/^__DBC_INTERNAL/d' \
-       -e '/_AUTO_H$/d' \
-       -e '/_H_$/d' \
-       -e '/_UNUSED/d' \
-        -e '/^i_/d' \
-        -e '/ext_h_/d' \
+       -e '/^i_/d' \
+       -e '/_H_/d' \
        -e 's/(.*//' | sort > $t1
 
+find $d -name '*.c' -o -name '*.cpp' > $t2
 for i in `cat $t1`; do
-       if egrep -w $i $d/*/*.c $d/*/*.cpp > /dev/null; then
+       if egrep -w $i `cat $t2` > /dev/null; then
            :;
        else
-           f=`egrep -l "#define.*$i" $d/include/*.h  $d/include/*.in |
-           sed 's;\.\.\/\.\.\/include/;;' | tr -s "[:space:]" " "`
+           f=`egrep -l "#define.*$i" $d/dbinc/*.h  $d/dbinc/*.in |
+           sed 's;\.\.\/\.\.\/dbinc/;;' | tr -s "[:space:]" " "`
            echo "FAIL: $i: $f"
        fi
-done | sort +1 > $t2
+done | sort -k 2 > $t3
 
-test -s $t2 && {
-       cat $t2
+test -s $t3 && {
+       cat $t3
        echo "FAIL: found unused #defines"
        exit 1
 }
index 248b557..c85a356 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.javafiles,v 1.4 2001/10/12 17:55:33 bostic Exp 
+# Id: chk.javafiles,v 1.5 2002/01/30 19:50:52 bostic Exp 
 #
 # Check to make sure we haven't forgotten to add any Java files to the list
 # of source files in the Makefile.
@@ -13,14 +13,14 @@ d=../..
 }
 
 f=$d/dist/Makefile.in
-d=$d/java/src/com/sleepycat
+j=$d/java/src/com/sleepycat
 
 t1=__1
 t2=__2
 
-find ${d}/db/ $d/examples -name \*.java -print |
+find $j/db/ $j/examples $d/rpc_server/java -name \*.java -print |
     sed -e 's/^.*\///' | sort > $t1
-tr ' \t' '\n' < ${f} | sed -e '/\.java$/!d' -e 's/^.*\///' | sort > $t2
+tr ' \t' '\n' < $f | sed -e '/\.java$/!d' -e 's/^.*\///' | sort > $t2
 
 cmp $t1 $t2 > /dev/null || {
        echo "<<< java source files >>> Makefile"
index 876be2f..4ad1b3c 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.nl,v 1.5 2001/10/12 17:55:33 bostic Exp 
+# Id: chk.nl,v 1.6 2002/01/07 15:12:12 bostic Exp 
 #
 # Check to make sure that there are no trailing newlines in __db_err calls.
 
@@ -68,12 +68,23 @@ chk(fp, name)
                        if (ch == '\n')
                                ++line;
                }
-               while ((ch = getc(fp)) != '"') {
-                       if (ch == EOF)
+               while ((ch = getc(fp)) != '"')
+                       switch (ch) {
+                       case EOF:
                                return (exitv);
-                       if (ch == '\n')
+                       case '\\n':
                                ++line;
-                       if (ch == '\\\\')
+                               break;
+                       case '.':
+                               if ((ch = getc(fp)) != '"')
+                                       ungetc(ch, fp);
+                               else {
+                                       fprintf(stderr,
+                                   "%s: <period> at line %d\n", name, line);
+                                       exitv = 1;
+                               }
+                               break;
+                       case '\\\\':
                                if ((ch = getc(fp)) != 'n')
                                        ungetc(ch, fp);
                                else if ((ch = getc(fp)) != '"')
@@ -83,7 +94,8 @@ chk(fp, name)
                                    "%s: <newline> at line %d\n", name, line);
                                        exitv = 1;
                                }
-               }
+                               break;
+                       }
        }
        return (exitv);
 }
@@ -93,7 +105,7 @@ cc t.c -o t
 if ./t $d/*/*.[ch] $d/*/*.cpp $d/*/*.in ; then
        :
 else
-       echo "FAIL: found __db_err calls with newline strings."
+       echo "FAIL: found __db_err calls ending with periods/newlines."
        exit 1
 fi
 
index 74ce687..043f717 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.proto,v 1.6 2001/10/12 17:55:34 bostic Exp 
+# Id: chk.proto,v 1.8 2002/03/27 04:32:59 bostic Exp 
 #
 # Check to make sure that prototypes are actually needed.
 
@@ -13,8 +13,9 @@ d=../..
 
 t1=__1
 t2=__2
+t3=__3
 
-egrep '__P' $d/include_auto/*.h |
+egrep '__P' $d/dbinc_auto/*.h |
     sed -e 's/[         ][      ]*__P.*//' \
     -e 's/^.*[  *]//' \
     -e '/__db_cprint/d' \
@@ -29,14 +30,14 @@ egrep '__P' $d/include_auto/*.h |
     -e '/_print$/d' \
     -e '/_read$/d' > $t1
 
+find $d -name '*.in' -o -name '*.[ch]' -o -name '*.cpp' > $t2
 for i in `cat $t1`; do
-       c=`egrep -low $i $d/include/*.in \
-           $d/include/*.h $d/*/*.c $d/*/*.cpp | wc -l`
+       c=$(egrep -low $i $(cat $t2) | wc -l)
        echo "$i: $c"
-done | egrep ' 1$' > $t2
+done | egrep ' 1$' > $t3
 
-test -s $t2 && {
-       cat $t2
+test -s $t3 && {
+       cat $t3
        echo "FAIL: found unnecessary prototypes."
        exit 1
 }
index 95a30ca..4f59e83 100644 (file)
@@ -45,9 +45,9 @@ while read name isdoc isinc isjava; do
 done
 
 # Check that pubdef.in has everything listed in db.in.
-f=$d/include/db.in
+f=$d/dbinc/db.in
 sed -n \
-    -e 's/^#define[     ]*\(DB_[A-Z_]*\).*/\1/p' \
+    -e 's/^#define[     ]*\(DB_[A-Z_0-9]*\).*/\1/p' \
     -e 's/^[    ]*\(DB_[A-Z_]*\)=[0-9].*/\1/p' \
     -e d < $f |
 while read name; do
@@ -60,10 +60,10 @@ while read name; do
 done
 
 # Check that db.in has everything listed in pubdef.in.
-f=$d/include/db.in
+f=$d/dbinc/db.in
 sed '/^#/d' $p |
 while read name isdoc isinc isjava; do
-       if `egrep -w "#define[   ]$name|[        ][      ]*$name=[0-9]" \
+       if `egrep -w "#define[   ]$name|[        ][      ]*$name=[0-9][0-9]*" \
            $f > /dev/null`; then
                [ "X$isinc" != "XI" ] && {
                        echo "$name should not appear in $f"
index c9e6bff..c2cb399 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.srcfiles,v 1.9 2001/10/12 17:55:35 bostic Exp 
+# Id: chk.srcfiles,v 1.10 2002/02/04 22:25:33 bostic Exp 
 #
 # Check to make sure we haven't forgotten to add any files to the list
 # of source files Win32 uses to build its dsp files.
@@ -21,8 +21,11 @@ sed -e '/^[  #]/d' \
     awk '{print $1}' > $t1
 find $d -type f |
     sed -e 's/^\.\.\/\.\.\///' \
-        -e '/^test/d' \
-        -e '/^build[^_]/d' |
+        -e '/^build[^_]/d' \
+        -e '/^test\//d' \
+        -e '/^test_server/d' \
+        -e '/^test_thread/d' \
+        -e '/^test_vxworks/d' |
     egrep '\.c$|\.cpp$|\.def$|\.rc$' |
     sed -e '/perl.DB_File\/version.c/d' |
     sort > $t2
index b3fd9cf..2211d46 100644 (file)
@@ -1,10 +1,14 @@
+AES
 AJVX
 ALLDB
 API
 APP
 AccessExample
 Acflmo
+Aclmop
 Ahlm
+Ahm
+BCFILprRsvVxX
 BCc
 BDBXXXXXX
 BH
@@ -12,16 +16,23 @@ BI
 BII
 BINTERNAL
 BTREE
+Bc
 BerkeleyDB
 BtRecExample
 Btree
+CD
 CDB
 CDS
 CDdFILTVvX
 CFILpRsv
+CFLprsvVxX
 CFh
+CHKSUM
+CLpsvxX
 CONFIG
 CdFILTvX
+ClassNotFoundException
+Config
 DBC
 DBENV
 DBS
@@ -36,6 +47,7 @@ DUPMASTER
 DUPSORT
 Db
 DbAppendRecno
+DbAttachImpl
 DbBtreeCompare
 DbBtreePrefix
 DbBtreeStat
@@ -63,12 +75,16 @@ DbMpoolStat
 DbPreplist
 DbQueueStat
 DbRecoveryInit
+DbRepStat
 DbRepTransport
 DbRunRecoveryException
 DbSecondaryKeyCreate
 DbTxn
 DbTxnRecover
 DbTxnStat
+DbUtil
+DbXAResource
+DbXid
 Dbc
 Dbt
 Dde
@@ -83,10 +99,16 @@ Exp
 FIXEDLEN
 Fd
 Ff
+Fh
 FileNotFoundException
+GetFileInformationByHandle
+GetJavaVM
 GetJoin
 HOFFSET
 HOLDELECTION
+Hashtable
+ILo
+ILprR
 INDX
 INIT
 IREAD
@@ -137,6 +159,11 @@ NOSERVER
 NOSYNC
 NOTFOUND
 NOTGRANTED
+NOTYPE
+NOWAIT
+NP
+NoP
+NoqV
 NqV
 NrV
 NsV
@@ -145,6 +172,7 @@ ORDERCHKONLY
 Offpage
 OpenFileMapping
 OutputStream
+PGNO
 PID
 PREV
 RECNO
@@ -161,9 +189,11 @@ RepProcessMessage
 SERVERPROG
 SERVERVERS
 SETFD
+SHA
 SS
 Shm
 Sleepycat
+Subdatabase
 TDS
 TESTDIR
 TID
@@ -179,11 +209,13 @@ TempFolder
 TestKeyRange
 TestLogc
 TpcbExample
+Tt
 Txn
 Txns
 UID
 UNAVAIL
 USERMEM
+Unencrypted
 UnmapViewOfFile
 VM
 VX
@@ -195,9 +227,13 @@ Vx
 VxWorks
 Waitsfor
 XA
+XAException
+Xid
 XxZ
 YIELDCPU
 YY
+abc
+abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq
 abcdef
 abs
 addpage
@@ -212,6 +248,7 @@ alsVv
 amx
 anum
 appl
+appname
 archivedir
 arg
 args
@@ -244,6 +281,7 @@ cdb
 cdel
 ceVv
 ceh
+celmNrtVZ
 celmNtV
 celmNtVZ
 cget
@@ -254,6 +292,7 @@ chkpoint
 chkpt
 chksum
 ckp
+cksum
 clearerr
 clientrun
 cmdargs
@@ -282,6 +321,7 @@ dbminit
 dbobj
 dbopen
 dbp
+dbreg
 dbremove
 dbrename
 dbs
@@ -293,6 +333,7 @@ def
 del
 delext
 delim
+dev
 df
 dh
 dir
@@ -310,6 +351,12 @@ dupset
 dupsort
 efh
 eid
+electinit
+electsend
+electvote
+electwait
+encryptaes
+encryptany
 endian
 env
 envid
@@ -330,6 +377,7 @@ ff
 ffactor
 fget
 fh
+fid
 fileid
 fileopen
 firstkey
@@ -344,10 +392,14 @@ fset
 fstat
 fsync
 ftype
+func
 fv
 gbytes
 gc'ed
 gen
+getBranchQualifier
+getFormatId
+getGlobalTransactionId
 gettime
 gettimeofday
 gettype
@@ -374,6 +426,7 @@ inlen
 inp
 insdel
 int
+intValue
 io
 iread
 isdeleted
@@ -381,6 +434,7 @@ itemorder
 iter
 iwr
 iwrite
+javax
 kb
 kbyte
 kbytes
@@ -393,10 +447,12 @@ keyrange
 killinterval
 killiteration
 killtest
+klNpP
 klNprRV
 klNprRs
 krinsky
 lM
+lP
 lang
 lastid
 ld
@@ -413,6 +469,7 @@ logc
 logclean
 logfile
 logflush
+logsonly
 lorder
 lpgno
 lsVv
@@ -428,6 +485,7 @@ luM
 luMB
 luMb
 lx
+mNP
 mNs
 machid
 makedup
@@ -483,6 +541,7 @@ mvptr
 mydrive
 mydrivexxx
 nO
+nP
 nTV
 nTt
 naborts
@@ -500,10 +559,14 @@ needswap
 nelem
 nevict
 newalloc
+newclient
+newfile
 newitem
+newmaster
 newname
 newpage
 newpgno
+newsite
 nextdup
 nextkey
 nextlsn
@@ -531,6 +594,7 @@ nopanic
 nosort
 nosync
 notfound
+notgranted
 nowait
 nowaits
 npages
@@ -547,10 +611,13 @@ num
 numdup
 obj
 offpage
+ok
 olddata
 olditem
+oldname
 opd
 opflags
+opmods
 orig
 os
 osynch
@@ -569,6 +636,7 @@ panic'ing
 paniccall
 panicstate
 parentid
+passwd
 perf
 perfdb
 pflag
@@ -583,12 +651,15 @@ pgnum
 pgout
 pgsize
 pid
+pkey
+plist
 pn
 postdestroy
 postlog
 postlogmeta
 postopen
 postsync
+prR
 prec
 predestroy
 preopen
@@ -604,9 +675,13 @@ pthread
 pthreads
 ptype
 pv
+qV
 qam
 qs
 qtest
+rRV
+rRs
+rV
 rand
 rcuradj
 rdonly
@@ -618,6 +693,7 @@ reclength
 recno
 recnum
 recnums
+recs
 refcount
 regionmax
 regop
@@ -629,16 +705,22 @@ rf
 rkey
 rlsn
 rm
+rmid
 rmw
 ro
 rootent
 rootlsn
 rpc
+rpcid
+rs
 rsplit
 runlog
 rw
 rwrw
 rwrwrw
+sS
+sV
+sVv
 scount
 secon
 secs
@@ -661,6 +743,7 @@ splitmeta
 srand
 stat
 str
+strcmp
 strdup
 strerror
 strlen
@@ -673,8 +756,10 @@ tVZ
 tas
 tcl
 tcp
+thr
 threadID
 tid
+tiebreaker
 timestamp
 tlen
 tm
@@ -708,6 +793,8 @@ upi
 usec
 usecs
 usr
+util
+vVxXZ
 vZ
 val
 var
@@ -727,6 +814,7 @@ wc
 wcount
 wordlist
 writeable
+wrnosync
 wt
 xa
 xid
index 1925048..64413b8 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.vx_code,v 1.3 2001/10/12 17:55:37 bostic Exp 
+# Id: chk.vx_code,v 1.6 2002/03/27 20:20:25 bostic Exp 
 #
 # Check to make sure the auto-generated utility code in the VxWorks build
 # directory compiles.
@@ -30,13 +30,16 @@ header()
  echo "{"
  echo "int i;") > t1.c
 
-for i in db_archive db_checkpoint db_deadlock \
-    db_dump db_load db_printlog db_recover db_stat db_upgrade db_verify; do
+for i in db_archive db_checkpoint db_deadlock db_dump db_load \
+    db_printlog db_recover db_stat db_upgrade db_verify dbdemo; do
        echo "  compiling build_vxworks/$i"
        (cat $d/build_vxworks/$i/$i.c; header $i) > t.c
-       if cc -Wall -I.. -I$d/include -I$d/include_auto \
-           t.c $d/clib/getopt.c $d/common/util_arg.c \
-           $d/common/util_log.c $d/common/util_sig.c ../libdb.a -o t; then
+       if cc -Wall -I.. -I$d t.c \
+           $d/clib/getopt.c \
+           $d/common/util_arg.c \
+           $d/common/util_cache.c \
+           $d/common/util_log.c \
+           $d/common/util_sig.c ../libdb.a -o t; then
                :
        else
                echo "FAIL: unable to compile $i"
@@ -50,9 +53,12 @@ done
 (cat t2.c t1.c; echo "return (0); }") > t.c
 
 echo " compiling build_vxworks utility composite"
-if cc -Dlint -Wall -I.. -I$d/include -I$d/include_auto \
-    t.c $d/clib/getopt.c $d/common/util_arg.c \
-    $d/common/util_log.c $d/common/util_sig.c ../libdb.a -o t; then
+if cc -Dlint -Wall -I.. -I$d t.c \
+    $d/clib/getopt.c \
+    $d/common/util_arg.c \
+    $d/common/util_cache.c \
+    $d/common/util_log.c \
+    $d/common/util_sig.c ../libdb.a -o t; then
        :
 else
        echo "FAIL: unable to compile utility composite"
index 9b92997..db87ec3 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.stats,v 1.4 2001/10/12 17:55:37 bostic Exp 
+# Id: chk.stats,v 1.5 2002/03/27 04:33:04 bostic Exp 
 #
 # Check to make sure all of the stat structure members are included in
 # all of the possible formats.
@@ -21,7 +21,7 @@ t=__tmp
 inc_fields()
 {
        sed -e "/struct $1 {/,/^};$/p" \
-           -e d < $d/include/db.in |
+           -e d < $d/dbinc/db.in |
        sed -e 1d \
            -e '$d' \
            -e '/;/!d' \
@@ -80,7 +80,7 @@ man()
                        echo "  $1: ignoring $i"
                        continue
                fi
-               if egrep -w $i $d/include/db.in > /dev/null; then
+               if egrep -w $i $d/dbinc/db.in > /dev/null; then
                        :;
                else
                        echo "  $1: $i not found in db.h."
index e43e920..88f5a54 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.err,v 1.2 2001/10/12 17:55:38 bostic Exp 
+# Id: chk.err,v 1.3 2002/03/27 04:33:05 bostic Exp 
 #
 # Check to make sure all of the error values have corresponding error
 # message strings in db_strerror().
@@ -17,7 +17,7 @@ d=../..
 t1=__tmp1
 t2=__tmp2
 
-egrep -- "define.*DB_.*-309" $d/include/db.in | awk '{print $2}' > $t1
+egrep -- "define.*DB_.*-309" $d/dbinc/db.in | awk '{print $2}' > $t1
 sed -e '/^db_strerror/,/^}/{' \
     -e '/      case DB_/{' \
     -e 's/:.*//' \
index 56c595f..602ce67 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestConstruct01.cpp,v 1.3 2001/10/05 01:50:17 bostic Exp 
+ * Id: TestConstruct01.cpp,v 1.5 2002/01/23 14:26:40 bostic Exp 
  */
 
 /*
@@ -109,8 +109,7 @@ void rundb(Db *db, int count, int has_env)
        // opening the db.
        //
        CHK(db->set_pagesize(1024));
-       CHK(db->open(name, NULL, DB_BTREE,
-                count ? 0 : DB_CREATE, 0664));
+       CHK(db->open(NULL, name, NULL, DB_BTREE, count ? 0 : DB_CREATE, 0664));
 
        // The bit map of keys we've seen
        long bitmap = 0;
index 8f0c142..a6fcb90 100644 (file)
@@ -1,19 +1,21 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997-2001
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestExceptInclude.cpp,v 1.1 2001/05/31 23:09:12 dda Exp 
+ * Id: TestExceptInclude.cpp,v 1.4 2002/07/05 22:17:59 dda Exp 
  */
 
 /* We should be able to include cxx_except.h without db_cxx.h,
- * and use the DbException class.
+ * and use the DbException class.  We do need db.h to get a few
+ * typedefs defined that the DbException classes use.
  *
  * This program does nothing, it's just here to make sure
  * the compilation works.
  */
-#include "cxx_except.h"
+#include <db.h>
+#include <cxx_except.h>
 
 int main(int argc, char *argv[])
 {
index f6d66dc..cb5cb1e 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestGetSetMethods.cpp,v 1.3 2001/10/05 01:50:17 bostic Exp 
+ * Id: TestGetSetMethods.cpp,v 1.4 2002/01/11 15:53:59 bostic Exp 
  */
 
 /*
index 62592ae..3a296c7 100644 (file)
@@ -6,10 +6,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestKeyRange.cpp,v 1.2 2001/10/09 20:58:35 dda Exp 
+ * Id: TestKeyRange.cpp,v 1.4 2002/01/23 14:26:41 bostic Exp 
  */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -90,7 +90,7 @@ void TestKeyRange::run()
        db.set_errpfx("TestKeyRange");
        db.set_pagesize(1024);          /* Page size: 1K. */
        db.set_cachesize(0, 32 * 1024, 0);
-       db.open(FileName, NULL, DB_BTREE, DB_CREATE, 0664);
+       db.open(NULL, FileName, NULL, DB_BTREE, DB_CREATE, 0664);
 
        //
        // Insert records into the database, where the key is the user
index 3a2521e..3ea36e8 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestLogc.cpp,v 1.4 2001/10/16 15:40:53 dda Exp 
+ * Id: TestLogc.cpp,v 1.6 2002/01/23 14:26:41 bostic Exp 
  */
 
 /*
@@ -36,7 +36,7 @@ int main(int argc, char *argv[])
 
                // Do some database activity to get something into the log.
                Db *db1 = new Db(env, 0);
-               db1->open("first.db", NULL, DB_BTREE, DB_CREATE, 0);
+               db1->open(NULL, "first.db", NULL, DB_BTREE, DB_CREATE, 0);
                Dbt *key = new Dbt((char *)"a", 1);
                Dbt *data = new Dbt((char *)"b", 1);
                db1->put(NULL, key, data, 0);
@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
                db1->close(0);
 
                Db *db2 = new Db(env, 0);
-               db2->open("second.db", NULL, DB_BTREE, DB_CREATE, 0);
+               db2->open(NULL, "second.db", NULL, DB_BTREE, DB_CREATE, 0);
                key->set_data((char *)"w");
                data->set_data((char *)"x");
                db2->put(NULL, key, data, 0);
index fb8714c..fbb8d91 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestSimpleAccess.cpp,v 1.3 2001/10/05 01:50:17 bostic Exp 
+ * Id: TestSimpleAccess.cpp,v 1.5 2002/01/23 14:26:41 bostic Exp 
  */
 
 /*
@@ -21,7 +21,7 @@ int main(int argc, char *argv[])
 {
        try {
                Db *db = new Db(NULL, 0);
-               db->open("my.db", NULL, DB_BTREE, DB_CREATE, 0644);
+               db->open(NULL, "my.db", NULL, DB_BTREE, DB_CREATE, 0644);
 
                // populate our massive database.
                // all our strings include null for convenience.
index 4902429..6faa8f6 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestTruncate.cpp,v 1.3 2001/10/05 01:50:17 bostic Exp 
+ * Id: TestTruncate.cpp,v 1.5 2002/01/23 14:26:41 bostic Exp 
  */
 
 /*
@@ -21,7 +21,7 @@ int main(int argc, char *argv[])
 {
        try {
                Db *db = new Db(NULL, 0);
-               db->open("my.db", NULL, DB_BTREE, DB_CREATE, 0644);
+               db->open(NULL, "my.db", NULL, DB_BTREE, DB_CREATE, 0644);
 
                // populate our massive database.
                // all our strings include null for convenience.
index 702ee57..fbc5f91 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.cxxtests,v 1.3 2001/10/23 21:23:04 dda Exp 
+# Id: chk.cxxtests,v 1.5 2002/07/05 22:17:59 dda Exp 
 #
 # Check to make sure that regression tests for C++ run.
 
@@ -8,7 +8,7 @@ TEST_CXX_SRCDIR=../test/scr015  # must be a relative directory
 
 # All paths must be relative to a subdirectory of the build directory
 LIBS="-L.. -ldb -ldb_cxx"
-CXXFLAGS="-I.. -I../../include"
+CXXFLAGS="-I.. -I../../dbinc"
 
 # Test must be run from a local build directory, not from a test
 # directory.
@@ -43,6 +43,7 @@ for testname in $testnames; do
        rm -rf TESTCXX; mkdir TESTCXX
        cd ./TESTCXX
        testprefix=../$TEST_CXX_SRCDIR/$testname
+
        ${CXX} ${CXXFLAGS} -o $testname $testprefix.cpp ${LIBS} > ../$testname.compileout 2>&1 || {
                echo "FAIL: compilation of $testname failed, see ../$testname.compileout"
                exit 1
index 587e684..eede964 100644 (file)
@@ -8,7 +8,7 @@ public class CallbackTest
         try {
             Db db = new Db(null, 0);
             db.set_bt_compare(new BtreeCompare());
-            db.open("test.db", "", Db.DB_BTREE, Db.DB_CREATE, 0666);
+            db.open(null, "test.db", "", Db.DB_BTREE, Db.DB_CREATE, 0666);
             StringDbt[] keys = new StringDbt[10];
             StringDbt[] datas = new StringDbt[10];
             for (int i = 0; i<10; i++) {
index 67703f0..efd6938 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestClosedDb.java,v 1.2 2001/10/05 02:36:08 bostic Exp 
+ * Id: TestClosedDb.java,v 1.4 2002/01/23 14:29:51 bostic Exp 
  */
 
 /*
@@ -22,7 +22,7 @@ public class TestClosedDb
     {
         try {
             Db db = new Db(null, 0);
-            db.open("my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+            db.open(null, "my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
 
             // populate our massive database.
             Dbt keydbt = new Dbt("key".getBytes());
index e4d97f1..0d207f8 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestConstruct01.java,v 1.4 2001/10/05 02:36:08 bostic Exp 
+ * Id: TestConstruct01.java,v 1.6 2002/01/23 14:29:51 bostic Exp 
  */
 
 /*
@@ -96,7 +96,7 @@ public class TestConstruct01
        // opening the db.
        //
        db.set_pagesize(1024);
-       db.open(name, null, Db.DB_BTREE,
+       db.open(null, name, null, Db.DB_BTREE,
                (count != 0) ? 0 : Db.DB_CREATE, 0664);
 
 
index d4442ce..91c47a3 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 2000
+ * Copyright (c) 2000-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestConstruct02.java,v 1.3 2001/10/05 02:36:09 bostic Exp 
+ * Id: TestConstruct02.java,v 1.5 2002/01/23 14:29:51 bostic Exp 
  */
 
 /*
@@ -185,7 +185,7 @@ public class TestConstruct02
        Db db = new Db(dbenv, 0);
        db.set_error_stream(System.err);
        db.set_pagesize(1024);
-       db.open(CONSTRUCT02_DBNAME, null, Db.DB_BTREE,
+       db.open(null, CONSTRUCT02_DBNAME, null, Db.DB_BTREE,
                Db.DB_CREATE, 0664);
 
        rundb(db, itemcount++);
@@ -200,7 +200,7 @@ public class TestConstruct02
        db = new Db(dbenv, 0);
        db.set_error_stream(System.err);
        db.set_pagesize(1024);
-       db.open(CONSTRUCT02_DBNAME, null, Db.DB_BTREE,
+       db.open(null, CONSTRUCT02_DBNAME, null, Db.DB_BTREE,
                Db.DB_CREATE, 0664);
        rundb(db, itemcount++);
        rundb(db, itemcount++);
index 2b37807..3716b28 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestReplication.java,v 1.1 2001/10/12 13:02:33 dda Exp 
+ * Id: TestReplication.java,v 1.3 2002/01/23 14:29:51 bostic Exp 
  */
 
 /*
@@ -117,7 +117,7 @@ public class TestReplication extends Thread
             }
             System.err.println("c70");
             Db db = new Db(client_env, 0);
-            db.open("x.db", null, Db.DB_BTREE, 0, 0);
+            db.open(null, "x.db", null, Db.DB_BTREE, 0, 0);
             Dbt data = new Dbt();
             System.err.println("c80");
             db.get(null, new Dbt("Hello".getBytes()), data, 0);
@@ -204,7 +204,7 @@ public class TestReplication extends Thread
             System.err.println("10");
             Db db = new Db(master_env, 0);
             System.err.println("20");
-            db.open("x.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+            db.open(null, "x.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
             System.err.println("30");
             db.put(null, new Dbt("Hello".getBytes()),
                    new Dbt("world".getBytes()), 0);
index d4024b1..e9bb3d4 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestSameDbt.java,v 1.2 2001/10/05 02:36:10 bostic Exp 
+ * Id: TestSameDbt.java,v 1.4 2002/01/23 14:29:51 bostic Exp 
  */
 
 /*
@@ -22,7 +22,7 @@ public class TestSameDbt
     {
         try {
             Db db = new Db(null, 0);
-            db.open("my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+            db.open(null, "my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
 
             // try reusing the dbt
             Dbt keydatadbt = new Dbt("stuff".getBytes());
index 7b2cf61..4a3c689 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestSimpleAccess.java,v 1.2 2001/10/05 02:36:10 bostic Exp 
+ * Id: TestSimpleAccess.java,v 1.4 2002/01/23 14:29:52 bostic Exp 
  */
 
 /*
@@ -22,7 +22,7 @@ public class TestSimpleAccess
     {
         try {
             Db db = new Db(null, 0);
-            db.open("my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+            db.open(null, "my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
 
             // populate our massive database.
             Dbt keydbt = new Dbt("key".getBytes());
index 3f74e8c..3878998 100644 (file)
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997, 1998, 1999, 2000
+ * Copyright (c) 1997-2002
  *     Sleepycat Software.  All rights reserved.
  *
- * Id: TestTruncate.java,v 1.2 2001/10/05 02:36:11 bostic Exp 
+ * Id: TestTruncate.java,v 1.4 2002/01/23 14:29:52 bostic Exp 
  */
 
 /*
@@ -22,7 +22,7 @@ public class TestTruncate
     {
         try {
             Db db = new Db(null, 0);
-            db.open("my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
+            db.open(null, "my.db", null, Db.DB_BTREE, Db.DB_CREATE, 0644);
 
             // populate our massive database.
             Dbt keydbt = new Dbt("key".getBytes());
index df845f5..51b55f8 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/sh -
 #
-# Id: chk.javatests,v 1.2 2001/10/12 13:02:34 dda Exp 
+# Id: chk.javatests,v 1.4 2002/03/27 04:33:08 bostic Exp 
 #
 # Check to make sure that regression tests for Java run.
 
@@ -17,7 +17,7 @@ export LD_LIBRARY_PATH="../.libs"
 
 # All paths must be relative to a subdirectory of the build directory
 LIBS="-L.. -ldb -ldb_cxx"
-CXXFLAGS="-I.. -I../../include"
+CXXFLAGS="-I.. -I../../dbinc"
 
 # Test must be run from a local build directory, not from a test
 # directory.
@@ -30,7 +30,7 @@ cd ..
        echo 'FAIL: chk.javatests must be run from a local build directory.'
        exit 1
 }
-version=`head -1 ../README | sed -e 's/.* \([0-9]*\.[0-9]*\)\..*/\1/'`
+version=`sed -e 's/.* \([0-9]*\.[0-9]*\)\..*/\1/' -e q ../README `
 [ -f libdb_java-$version.la ] || make libdb_java-$version.la || {
        echo "FAIL: unable to build libdb_java-$version.la"
        exit 1
index ad3c880..7d6e9f0 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: shelltest.tcl,v 1.15 2001/11/03 18:43:48 bostic Exp 
+# Id: shelltest.tcl,v 1.20 2002/04/19 15:42:20 bostic Exp 
 #
 # TEST scr###
 # TEST The scr### directories are shell scripts that test a variety of
@@ -82,3 +82,7 @@ proc scr015 {} { shelltest 15 }
 proc scr016 {} { shelltest 16 }
 proc scr017 {} { shelltest 17 }
 proc scr018 {} { shelltest 18 }
+proc scr019 {} { shelltest 19 }
+proc scr020 {} { shelltest 20 }
+proc scr021 {} { shelltest 21 }
+proc scr022 {} { shelltest 22 }
index e6c241f..0cde6f5 100644 (file)
@@ -1,10 +1,10 @@
 
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2001
+# Copyright (c) 2001-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: si005.tcl,v 11.2 2001/07/02 01:08:46 bostic Exp 
+# Id: si005.tcl,v 11.4 2002/04/29 17:12:03 sandstro Exp 
 #
 # Sindex005: Secondary index and join test.
 proc sindex005 { methods {nitems 1000} {tnum 5} args } {
@@ -46,7 +46,7 @@ proc sindex005 { methods {nitems 1000} {tnum 5} args } {
 
        # Open an environment
        # XXX if one is not supplied!
-       set env [berkdb env -create -home $testdir]
+       set env [berkdb_env -create -home $testdir]
        error_check_good env_open [is_valid_env $env] TRUE
 
        # Open the databases.
index da6334c..61d20f0 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 2000-2001
+# Copyright (c) 2000-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: test095.tcl,v 11.13 2001/10/11 18:08:40 sandstro Exp 
+# Id: test095.tcl,v 11.16 2002/08/08 15:38:12 bostic Exp 
 #
 # TEST test095
 # TEST Bulk get test. [#2934]
@@ -12,6 +12,7 @@ proc test095 { method {nsets 1000} {noverflows 25} {tnum 95} args } {
        set args [convert_args $method $args]
        set omethod [convert_method $method]
 
+       set txnenv 0
        set eindex [lsearch -exact $args "-env"]
        #
        # If we are using an env, then testfile should just be the db name.
@@ -26,6 +27,12 @@ proc test095 { method {nsets 1000} {noverflows 25} {tnum 95} args } {
                set basename test0$tnum
                incr eindex
                set env [lindex $args $eindex]
+               set txnenv [is_txnenv $env]
+               if { $txnenv == 1 } {
+                       puts "Skipping for environment with txns"
+                       return
+               }
+               set testdir [get_home $env]
                set carg {}
        }
        cleanup $testdir $env
@@ -266,6 +273,7 @@ proc t95_verify { res multiple_keys } {
 # Add nsets dup sets, each consisting of {word$ndups word$n} pairs,
 # with "word" having (i * pad_bytes)  bytes extra padding.
 proc t95_populate { db did nsets pad_bytes } {
+       set txn ""
        for { set i 1 } { $i <= $nsets } { incr i } {
                # basekey is a padded dictionary word
                gets $did basekey
@@ -278,7 +286,7 @@ proc t95_populate { db did nsets pad_bytes } {
                for { set j 0 } { $j < $i } { incr j } {
                        set data $basekey.[format %4u $j]
                        error_check_good db_put($key,$data) \
-                           [$db put $key $data] 0
+                           [eval {$db put} $txn {$key $data}] 0
                }
        }
 
index aff0090..84bd6dd 100644 (file)
@@ -1,18 +1,20 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1999-2001
+# Copyright (c) 1999-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: test096.tcl,v 11.9 2001/08/03 16:39:49 bostic Exp 
+# Id: test096.tcl,v 11.18 2002/07/22 16:53:00 sue Exp 
 #
 # TEST test096
 # TEST Db->truncate test.
-proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
+proc test096 { method {pagesize 512} {nentries 50} {ndups 4} args} {
        global fixed_len
        source ./include.tcl
 
        set orig_fixed_len $fixed_len
-       set opts [convert_args $method $args]
+       set args [convert_args $method $args]
+       set encargs ""
+       set args [split_encargs $args encargs]
        set omethod [convert_method $method]
 
        puts "Test096: $method db truncate method test"
@@ -33,22 +35,23 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        if { $eindex != -1 } {
                incr eindex
                set env [lindex $args $eindex]
-               #
-               # Make sure the env we were given supports txns.
-               #
-               set stat [catch {$env txn} txn]
-               if { $stat != 0 } {
+               set txnenv [is_txnenv $env]
+               if { $txnenv == 0 } {
                        puts "Environment w/o txns specified;  skipping."
                        return
                }
-               error_check_good txnabort [$txn abort] 0
+               if { $nentries == 1000 } {
+                       set nentries 100
+               }
+               reduce_dups nentries ndups
+               set testdir [get_home $env]
                set closeenv 0
        } else {
                env_cleanup $testdir
 
                #
                # We need an env for exclusive-use testing.
-               set env [berkdb env -create -home $testdir -txn]
+               set env [eval {berkdb_env -create -home $testdir -txn} $encargs]
                error_check_good env_create [is_valid_env $env] TRUE
                set closeenv 1
        }
@@ -56,7 +59,7 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        set t1 $testdir/t1
 
        puts "\tTest096.a: Create $nentries entries"
-       set db [eval {berkdb_open_noerr -create \
+       set db [eval {berkdb_open -create -auto_commit \
            -env $env $omethod -mode 0644} $args $testfile]
        error_check_good db_open [is_valid_db $db] TRUE
 
@@ -68,9 +71,13 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        while { [gets $did str] != -1 && $count < $nentries } {
                set key $str
                set datastr [reverse $str]
+               set t [$env txn]
+               error_check_good txn [is_valid_txn $t $env] TRUE
+               set txn "-txn $t"
                set ret [eval {$db put} \
                    $txn $pflags {$key [chop_data $method $datastr]}]
                error_check_good put $ret 0
+               error_check_good txn [$t commit] 0
 
                set ret [eval {$db get} $gflags {$key}]
                error_check_good $key:dbget [llength $ret] 1
@@ -81,15 +88,15 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
 
        puts "\tTest096.b: Truncate database"
        error_check_good dbclose [$db close] 0
-       set dbtr [eval {berkdb_open_noerr -create \
+       set dbtr [eval {berkdb_open -create -auto_commit \
            -env $env $omethod -mode 0644} $args $testfile]
        error_check_good db_open [is_valid_db $dbtr] TRUE
 
-       set ret [$dbtr truncate]
+       set ret [$dbtr truncate -auto_commit]
        error_check_good dbtrunc $ret $nentries
        error_check_good db_close [$dbtr close] 0
 
-       set db [berkdb_open -env $env $testfile]
+       set db [eval {berkdb_open -env $env} $args $testfile]
        error_check_good dbopen [is_valid_db $db] TRUE
        set ret [$db get -glob *]
        error_check_good dbget [llength $ret] 0
@@ -101,8 +108,8 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        #
        puts "\tTest096.d: Create $nentries entries with $ndups duplicates"
        set ret [berkdb dbremove -env $env $testfile]
-       set db [eval {berkdb_open_noerr -pagesize $pagesize -dup -create \
-           -env $env $omethod -mode 0644} $args $testfile]
+       set db [eval {berkdb_open -pagesize $pagesize -dup -auto_commit \
+           -create -env $env $omethod -mode 0644} $args $testfile]
        error_check_good db_open [is_valid_db $db] TRUE
        set did [open $dict]
        set count 0
@@ -113,9 +120,13 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
                set key $str
                for { set i 1 } { $i <= $ndups } { incr i } {
                        set datastr $i:$str
+                       set t [$env txn]
+                       error_check_good txn [is_valid_txn $t $env] TRUE
+                       set txn "-txn $t"
                        set ret [eval {$db put} \
                            $txn $pflags {$key [chop_data $method $datastr]}]
                        error_check_good put $ret 0
+                       error_check_good txn [$t commit] 0
                }
 
                set ret [eval {$db get} $gflags {$key}]
@@ -129,7 +140,11 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        for { set i 1 } {$i <= $ndups} {incr i} {
                lappend dlist $i
        }
+       set t [$env txn]
+       error_check_good txn [is_valid_txn $t $env] TRUE
+       set txn "-txn $t"
        dup_check $db $txn $t1 $dlist
+       error_check_good txn [$t commit] 0
        puts "\tTest096.e: Verify off page duplicates status"
        set stat [$db stat]
        error_check_bad stat:offpage [is_substr $stat \
@@ -141,7 +156,7 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        puts "\tTest096.f: Truncate database in a txn then abort"
        set txn [$env txn]
 
-       set dbtr [eval {berkdb_open_noerr -create \
+       set dbtr [eval {berkdb_open -auto_commit -create \
            -env $env $omethod -mode 0644} $args $testfile]
        error_check_good db_open [is_valid_db $dbtr] TRUE
        error_check_good txnbegin [is_valid_txn $txn $env] TRUE
@@ -152,7 +167,7 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        error_check_good txnabort [$txn abort] 0
        error_check_good db_close [$dbtr close] 0
 
-       set db [berkdb_open -env $env $testfile]
+       set db [eval {berkdb_open -auto_commit -env $env} $args $testfile]
        error_check_good dbopen [is_valid_db $db] TRUE
        set ret [$db get -glob *]
        error_check_good dbget [llength $ret] $recs
@@ -162,22 +177,23 @@ proc test096 { method {pagesize 512} {nentries 1000} {ndups 19} args} {
        set txn [$env txn]
        error_check_good txnbegin [is_valid_txn $txn $env] TRUE
 
-       set dbtr [eval {berkdb_open_noerr -create \
+       set dbtr [eval {berkdb_open -auto_commit -create \
            -env $env $omethod -mode 0644} $args $testfile]
        error_check_good db_open [is_valid_db $dbtr] TRUE
 
        set ret [$dbtr truncate -txn $txn]
        error_check_good dbtrunc $ret $recs
 
-       error_check_good db_close [$dbtr close] 0
        error_check_good txncommit [$txn commit] 0
+       error_check_good db_close [$dbtr close] 0
 
-       set db [berkdb_open -env $env $testfile]
+       set db [berkdb_open -auto_commit -env $env $testfile]
        error_check_good dbopen [is_valid_db $db] TRUE
        set ret [$db get -glob *]
        error_check_good dbget [llength $ret] 0
        error_check_good dbclose [$db close] 0
 
+       set testdir [get_home $env]
        error_check_good dbverify [verify_dir $testdir "\tTest096.h: "] 0
 
        if { $closeenv == 1 } {
index 8739b1d..66be1e9 100644 (file)
@@ -1,9 +1,9 @@
 # See the file LICENSE for redistribution information.
 #
-# Copyright (c) 1996-2001
+# Copyright (c) 1996-2002
 #      Sleepycat Software.  All rights reserved.
 #
-# Id: txnscript.tcl,v 11.1 2001/05/31 18:12:45 sue Exp 
+# Id: txnscript.tcl,v 11.3 2002/01/23 15:33:40 bostic Exp 
 #
 # Txn003 script - outstanding child prepare script
 # Usage: txnscript envcmd dbcmd gidf key data
@@ -36,7 +36,7 @@ set dbenv [eval $envcmd]
 error_check_good envopen [is_valid_env $dbenv] TRUE
 
 set usedb 1
-set db [berkdb_open -env $dbenv $dbfile]
+set db [berkdb_open -auto_commit -env $dbenv $dbfile]
 error_check_good dbopen [is_valid_db $db] TRUE
 
 puts "\tTxnscript.a: begin parent and child txn"
index 8207acb..d15a889 100644 (file)
@@ -1,38 +1,35 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996-2001
+ * Copyright (c) 1996-2002
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "db_config.h"
 
 #ifndef lint
-static const char revid[] = "Id: txn_method.c,v 11.55 2001/10/08 16:04:37 bostic Exp ";
+static const char revid[] = "Id: txn_method.c,v 11.62 2002/05/09 20:09:35 bostic Exp ";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
-#include <string.h>
+#ifdef HAVE_RPC
+#include <rpc/rpc.h>
 #endif
 
-#ifdef  HAVE_RPC
-#include "db_server.h"
+#include <string.h>
 #endif
 
 #include "db_int.h"
-#include "db_page.h"
-#include "log.h"
-#include "txn.h"
+#include "dbinc/txn.h"
 
 #ifdef HAVE_RPC
-#include "rpc_client_ext.h"
+#include "dbinc_auto/db_server.h"
+#include "dbinc_auto/rpc_client_ext.h"
 #endif
 
 static int __txn_set_tx_max __P((DB_ENV *, u_int32_t));
-static int __txn_set_tx_recover __P((DB_ENV *,
-              int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops)));
 static int __txn_set_tx_timestamp __P((DB_ENV *, time_t *));
 
 /*
@@ -57,7 +54,6 @@ __txn_dbenv_create(dbenv)
 #ifdef HAVE_RPC
        if (F_ISSET(dbenv, DB_ENV_RPCCLIENT)) {
                dbenv->set_tx_max = __dbcl_set_tx_max;
-               dbenv->set_tx_recover = __dbcl_set_tx_recover;
                dbenv->set_tx_timestamp = __dbcl_set_tx_timestamp;
                dbenv->txn_checkpoint = __dbcl_txn_checkpoint;
                dbenv->txn_recover = __dbcl_txn_recover;
@@ -67,7 +63,6 @@ __txn_dbenv_create(dbenv)
 #endif
        {
                dbenv->set_tx_max = __txn_set_tx_max;
-               dbenv->set_tx_recover = __txn_set_tx_recover;
                dbenv->set_tx_timestamp = __txn_set_tx_timestamp;
                dbenv->txn_checkpoint = __txn_checkpoint;
 #ifdef CONFIG_TEST
@@ -95,21 +90,6 @@ __txn_set_tx_max(dbenv, tx_max)
 }
 
 /*
- * __txn_set_tx_recover --
- *     Set the transaction abort recover function.
- */
-static int
-__txn_set_tx_recover(dbenv, tx_recover)
-       DB_ENV *dbenv;
-       int (*tx_recover) __P((DB_ENV *, DBT *, DB_LSN *, db_recops));
-{
-       ENV_ILLEGAL_AFTER_OPEN(dbenv, "set_tx_recover");
-
-       dbenv->tx_recover = tx_recover;
-       return (0);
-}
-
-/*
  * __txn_set_tx_timestamp --
  *     Set the transaction recovery timestamp.
  */