#!/usr/bin/perl -w

use 5.008;
use strict;
use warnings;

use Getopt::Std;
use Fcntl;			# For O_RDWR, O_CREAT, etc.
use Fcntl ':flock';		# For LOCK_EX and friends
use NDBM_File;

my $write = 0;
my $lock = 0;

my %opts = ( n => 1, m => 100 );
if (!getopts('n:m:wls', \%opts) || @ARGV != 1) {
    print STDERR "\
Usage: $0 [-n <count>] [-m <val>] [-w] [-l] [-s] <ndbm-file>
	-n <count>	Run <count> read-or-write iterations [1]
	-m <maxval>	Maximum key number is <maxval> [100]
	-w		Write random values [read values]
	-l		Lock NDBM file for all accesses
	-s		Sleep briefly during each access
";
    exit 1;
}

my $niterations = $opts{n};
my $maxkey = $opts{m};
my $dbfile = $ARGV[0];

my $lockval = $opts{w} ? LOCK_EX : LOCK_SH;
my $tieval = $opts{w} ? O_RDWR|O_CREAT : O_RDONLY;

foreach my $i (1..$niterations) {
    my $filename = "$dbfile.dir";
    flock($filename, $lockval) or die "$0 can't lock '$filename': $!"
	if $opts{l};

    my %h;
    if (!tie(%h, "NDBM_File", $dbfile, $tieval, 0666)) {
	die "Couldn't open NDBM file '$dbfile': $!";
    }

    my $key = int(rand($maxkey));
    if ($opts{w}) {
	my $chars = join("", "A".."Z", "a".."z", "0".."9", "+", "/");
	my $val = "";
	foreach my $i (1..12) {
	    $val .= substr($chars, int(rand()*64), 1);
	}
	$h{$key} = $val;
    } else {
	my $val = $h{$key};
	print($key, ":", defined $val ? $val : "--", "\n");
    }

    select(undef, undef, undef, rand(0.1)) # Random sleep up to 1/10 seconds
	if $opts{s};

    untie %h;

    flock($filename, LOCK_UN) or die "$0 can't unlock '$filename': $!"
	if $opts{l}
}
