Recipe 14.5. Locking DBM Files
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:42:49Z

#

| Chapter 14 Database Access |

## 14.5. Locking DBM Files

### Problem

You need several concurrently running programs to have simultaneous access to a DBM file.

### Solution

Either use the DBM implementation's locking mechanism if it has one, lock the file with `flock`, or use an auxiliary locking scheme as in Recipe 7.21.

### Discussion

With SDBM or NDBM, you can't do much to lock the database itself. You must devise an auxiliary locking scheme using an extra lockfile.

GDBM uses the concept of readers and writers: either many readers or one solitary writer may have a GDBM file open at any given time. You specify whether you're a reader or a writer when you open it. This can be annoying.

Version 1 of Berkeley DB gives you access to the file descriptor of the open database, allowing you to `flock` it. The lock applies to the database as a whole, not to individual records. Version 2 implements its own full transaction system with locking.

Example 14.3 shows an example of locking a database using Berkeley DB. Run this repeatedly in the background to see locks granted in proper order.

#### Example 14.3: dblockdemo

    #!/usr/bin/perl
    # dblockdemo - demo locking dbm databases
    use DB_File;
    use strict;

    sub LOCK_SH { 1 }                   # In case you don't have
    sub LOCK_EX { 2 }                   # the standard Fcntl module.  You
    sub LOCK_NB { 4 }                   # should, but who can tell
    sub LOCK_UN { 8 }                   # how those chips fall?

    my($oldval, $fd, $db, %db, $value, $key);

    $key    = shift || 'default';
    $value  = shift || 'magic';
    $value .= " $$";

    $db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0666)
        or die "dbcreat /tmp/foo.db $!";
    $fd = $db->fd;                      # need this for locking
    print "$$: db fd is $fd\n";
    open(DB_FH, "+<&=$fd")
        or die "dup $!";

    unless (flock (DB_FH, LOCK_SH | LOCK_NB)) {
        print "$$: CONTENTION; can't read during write update!
                    Waiting for read lock ($!) ....";
        unless (flock (DB_FH, LOCK_SH)) { die "flock: $!" }
    }
    print "$$: Read lock granted\n";

    $oldval = $db{$key};
    print "$$: Old value was $oldval\n";
    flock(DB_FH, LOCK_UN);

    unless (flock (DB_FH, LOCK_EX | LOCK_NB)) {
        print "$$: CONTENTION; must have exclusive lock!
                    Waiting for write lock ($!) ....";
        unless (flock (DB_FH, LOCK_EX)) { die "flock: $!" }
    }

    print "$$: Write lock granted\n";
    $db{$key} = $value;
    $db->sync;  # to flush
    sleep 10;

    flock(DB_FH, LOCK_UN);
    undef $db;
    untie %db;
    close(DB_FH);
    print "$$: Updated db to $key=$value\n";

### See Also

The documentation for the standard DB_File module, also in Chapter 7 of Programming Perl; Recipe 7.11; Recipe 16.12

14.4. Merging DBM Files |  | 14.6. Sorting Large DBM Files