[comp.lang.perl] Trouble opening and closing a dbm file several times.

roger@mav.com (Roger Droz) (05/07/91)

[Apologies if I'm bugging the net about a long-since fixed problem.  I
have a perfectly good Perl 4.0 tar that I've been too busy to unpack...]

Gdbm permits only one writer to a database, so perl programs need to
close databases before requesting input in order to permit concurrent
access to other users.

As a general solution, I wrapped dbmopen in the following perl
subroutine to wait with a timeout for the database to be available.
Sometimes the database would be corrupted when a perl program opened a
database with subroutine wait_dbmopen and closed it with dbmclose
several times:

    $foodata{'?'}; # make sure array is defined before passing reference.
    .
    .
    .
    &wait_dbmopen(*foodata, "filename", 0444) || die "Can't open.";
    .
    .
    .
    dbmclose(foodata);
    .
    .
    .
    &wait_dbmopen(*foodata, "filename", 0444);
    .
    .
    .
    dbmclose(foodata); # This sometimes corrupts the gdm file.

Issuing another dummy operation on the array before each call to
wait_dbmopen seems to have fixed the problem, but I'd like to ask the
perl wizzards why.  

I really do intend to install a later version of perl some day.
Meanwhile, this is either a long fixed bug or more probably yet
another interesting caveat (misunderstanding) of using the *name
production...

$Header: perly.c,v 3.0.1.5 90/03/27 16:20:57 lwall Locked $
Patch level: 18

;#** Header3 *****************************************************
;# Routine: wait_dbmopen(*array, $file, $mode, $quiet)      Author: RLD
;#                       DESCRIPTION
;#   Open a dbm database file, waiting if necessary to
;#   obtain the requested permissions.  (Use regular dbmclose to close
;#   the database.)
;#
;#   Note: perl only permits one instance of an open database at a time,
;#   despite gdbm's ability to have multiple readers.
;#
;# Entry:
;#   *array = an associative array to be bound to the keyfile, as in
;#            dbmopen.
;#   $file = filename, suitable for dbmopen.
;#   $mode = open mode.
;#   $quiet = a boolean telling the routine to wait quietly.  This
;#            suppresses "waiting" messages from appearing on STDERR.
;# Exit:
;#   boolean value indicating success.
;#** EndHeader **************************************************
sub wait_dbmopen {
    local(*array, $file, $mode, $quiet) = @_;
    local($proceed) = 0;
    local($cnt) = 0;
    local($dbmname) = $file . '.pag';
    
    if ( -f $dbmname ) {
        $! = 0;
        do {
            $proceed = dbmopen(array, $file, $mode);
            unless ($proceed) {
                unless ($quiet) {
                    printf STDERR "\rWaiting %d seconds to open %s (Err: %d)\r", $cnt, $file, $!;
                }
                sleep 5;
                $cnt += 5;
            }
        } until ($proceed || $cnt > 3600);
        print STDERR "\r", (' ' x 75), "\r" if (!$quiet && $cnt > 0);
    } else {
        $proceed = dbmopen(array, $file, $mode);
    }
    $proceed;
}

____________
               Roger Droz                  Domain: roger@mav.COM           
()       ()    Maverick International      UUCP: uw-beaver!gtisqr!roger
 (_______)     Mukilteo, WA 
  (     )      
   |   |       Disclaimer: "We're all mavericks here: 
   |   |                    Each of us has our own opinions,
   (___)                    and the company has yet different ones!"