releasing/cbrtools/perl/MLDBM/Sync.pm
author Ross Qin <ross.qin@nokia.com>
Tue, 30 Nov 2010 14:05:41 +0800
changeset 713 7b7f0409fc00
parent 602 3145852acc89
permissions -rw-r--r--
merge
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
602
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     1
# Copyright (c) 2001-2002 Joshua Chamas, Chamas Enterprises Inc.  All rights reserved.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     2
# Sponsored by development on NodeWorks http://www.nodeworks.com and Apache::ASP
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     3
# http://www.apache-asp.org
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     4
#
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     5
# This program is free software; you can redistribute it
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     6
# and/or modify it under the same terms as Perl itself.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     7
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     8
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
     9
package MLDBM::Sync;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    10
$VERSION = '0.30';
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    11
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    12
use MLDBM;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    13
use MLDBM::Sync::SDBM_File;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    14
use Data::Dumper;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    15
use Fcntl qw(:flock);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    16
use Digest::MD5 qw(md5_hex);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    17
use strict;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    18
use Carp qw(confess);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    19
no strict qw(refs);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    20
use vars qw($AUTOLOAD @EXT $CACHE_ERR $LOCK_SH $LOCK_EX $LOCK_UN);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    21
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    22
eval "use Tie::Cache;";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    23
if (($@)) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    24
    $CACHE_ERR = $@;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    25
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    26
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    27
$LOCK_SH = LOCK_SH;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    28
$LOCK_UN = LOCK_UN;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    29
$LOCK_EX = LOCK_EX;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    30
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    31
@EXT = ('.pag', '.dir', '');
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    32
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    33
sub TIEHASH {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    34
    my($class, $file, @args) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    35
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    36
    $file =~ /^(.*)$/s;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    37
    $file = $1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    38
    my $fh = $file.".lock";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    39
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    40
    my $self = bless {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    41
		      'file' => $file,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    42
		      'args' => [ $file, @args ],
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    43
		      'lock_fh' => $fh,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    44
		      'lock_file' => $fh,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    45
		      'lock_num' => 0,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    46
		      'md5_keys' => 0,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    47
		      'pid' => $$,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    48
		      'keys' => [],
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    49
		      'db_type' => $MLDBM::UseDB,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    50
		      'serializer' => $MLDBM::Serializer,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    51
		      'remove_taint' => $MLDBM::RemoveTaint,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    52
		     };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    53
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    54
    $self;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    55
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    56
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    57
sub DESTROY { 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    58
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    59
    if($self->{lock_num}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    60
	$self->{lock_num} = 1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    61
	$self->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    62
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    63
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    64
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    65
sub AUTOLOAD {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    66
    my($self, $key, $value) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    67
    $AUTOLOAD =~ /::([^:]+)$/;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    68
    my $func = $1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    69
    grep($func eq $_, ('FETCH', 'STORE', 'EXISTS', 'DELETE'))
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    70
      || die("$func not handled by object $self");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    71
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    72
    ## CHECKSUM KEYS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    73
    if(defined $key && $self->{md5_keys}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    74
	$key = $self->SyncChecksum($key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    75
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    76
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    77
    # CACHE, short circuit if found in cache on FETCH/EXISTS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    78
    # after checksum, since that's what we store
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    79
    my $cache = (defined $key) ? $self->{cache} : undef;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    80
    if($cache && ($func eq 'FETCH' or $func eq 'EXISTS')) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    81
	my $rv = $cache->$func($key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    82
	defined($rv) && return($rv);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    83
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    84
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    85
    my $rv;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    86
    if ($func eq 'FETCH' or $func eq 'EXISTS') {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    87
	$self->read_lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    88
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    89
	$self->lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    90
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    91
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    92
    {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    93
	local $MLDBM::RemoveTaint = $self->{remove_taint};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    94
	if (defined $value) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    95
	    $rv = $self->{dbm}->$func($key, $value);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    96
	} else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    97
	    $rv = $self->{dbm}->$func($key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    98
	}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
    99
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   100
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   101
    $self->unlock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   102
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   103
    # do after lock critical section, no point taking 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   104
    # any extra time there
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   105
    $cache && $cache->$func($key, $value);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   106
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   107
    $rv;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   108
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   109
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   110
sub CLEAR { 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   111
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   112
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   113
    $self->lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   114
    $self->{dbm}->CLEAR;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   115
    $self->{dbm} = undef;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   116
    # delete the files to free disk space
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   117
    my $unlinked = 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   118
    for (@EXT) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   119
	my $file = $self->{file}.$_;	
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   120
	next if(! -e $file);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   121
	if(-d $file) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   122
	    rmdir($file) || warn("can't unlink dir $file: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   123
	} else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   124
	    unlink($file) || die("can't unlink file $file: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   125
	}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   126
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   127
	$unlinked++;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   128
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   129
    if($self->{lock_num} > 1) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   130
	$self->SyncTie; # recreate, not done with it yet
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   131
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   132
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   133
    $self->unlock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   134
    if($self->{lock_num} == 0) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   135
	# only unlink if we are clear of all the locks
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   136
	unlink($self->{lock_file});
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   137
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   138
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   139
    $self->{cache} && $self->{cache}->CLEAR;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   140
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   141
    1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   142
};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   143
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   144
# don't bother with cache for first/next key since it'll kill
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   145
# the cache anyway likely
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   146
sub FIRSTKEY {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   147
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   148
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   149
    if($self->{md5_keys}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   150
	confess("can't get keys() or each() on MLDBM::Sync database ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   151
		"with SyncKeysChecksum(1) set");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   152
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   153
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   154
    $self->read_lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   155
    my $key = $self->{dbm}->FIRSTKEY();
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   156
    my @keys;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   157
    while(1) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   158
	last if ! defined($key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   159
	push(@keys, $key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   160
	$key = $self->{dbm}->NEXTKEY($key);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   161
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   162
    $self->unlock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   163
    $self->{'keys'} = \@keys;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   164
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   165
    $self->NEXTKEY;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   166
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   167
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   168
sub NEXTKEY {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   169
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   170
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   171
    if($self->{md5_keys}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   172
	confess("can't get keys() or each() on MLDBM::Sync database ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   173
		"with SyncKeysChecksum(1) set");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   174
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   175
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   176
    my $rv = shift(@{$self->{'keys'}});
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   177
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   178
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   179
sub SyncChecksum {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   180
    my($self, $key) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   181
    if(ref $key) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   182
	join('g', md5_hex($$key), sprintf("%07d",length($$key)));
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   183
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   184
	join('g', md5_hex($key), sprintf("%07d", length($key)));
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   185
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   186
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   187
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   188
sub SyncCacheSize {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   189
    my($self, $size) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   190
    $CACHE_ERR && die("need Tie::Cache installed to use this feature: $@");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   191
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   192
    if ($size =~ /^(\d+)(M|K)$/) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   193
	my($num, $type) = ($1, $2);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   194
	if (($type eq 'M')) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   195
	    $size = $num * 1024 * 1024;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   196
	} elsif (($type eq 'K')) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   197
	    $size = $num * 1024;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   198
	} else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   199
	    die "$type symbol not understood for $size";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   200
	}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   201
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   202
	($size =~ /^\d+$/) or die("$size must be bytes size for cache");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   203
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   204
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   205
    if ($self->{cache}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   206
	$self->{cache}->CLEAR(); # purge old cache, to free up RAM maybe for mem leaks
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   207
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   208
    
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   209
    my %cache;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   210
    my $cache = tie %cache, 'Tie::Cache', { MaxBytes => $size };
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   211
    $self->{cache} = $cache; # use non tied interface, faster
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   212
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   213
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   214
sub SyncTie {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   215
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   216
    my %temp_hash;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   217
    my $args = $self->{args};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   218
    local $MLDBM::UseDB = $self->{db_type};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   219
    local $MLDBM::Serializer = $self->{serializer};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   220
    local $MLDBM::RemoveTaint = $self->{remove_taint};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   221
    $self->{dbm} = tie(%temp_hash, 'MLDBM', @$args) || die("can't tie to MLDBM with args: ".join(',', @$args)."; error: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   222
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   223
    $self->{dbm};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   224
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   225
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   226
#### DOCUMENTED API ################################################################
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   227
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   228
sub SyncKeysChecksum {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   229
    my($self, $setting) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   230
    if(defined $setting) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   231
	$self->{md5_keys} = $setting;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   232
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   233
	$self->{md5_keys};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   234
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   235
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   236
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   237
*read_lock = *ReadLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   238
sub ReadLock { shift->Lock(1); }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   239
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   240
*lock = *SyncLock = *Lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   241
sub Lock {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   242
    my($self, $read_lock) = @_;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   243
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   244
    if($self->{lock_num}++ == 0) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   245
	my $file = $self->{lock_file};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   246
	open($self->{lock_fh}, "+>$file") || die("can't open file $file: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   247
	flock($self->{lock_fh}, ($read_lock ? $LOCK_SH : $LOCK_EX))
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   248
	  || die("can't ". ($read_lock ? "read" : "write") ." lock $file: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   249
	$self->{read_lock} = $read_lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   250
	$self->SyncTie;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   251
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   252
	if ($self->{read_lock} and ! $read_lock) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   253
	    $self->{lock_num}--; # roll back lock count
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   254
	    # confess here to help developer track this down
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   255
	    confess("Can't upgrade lock type from LOCK_SH to LOCK_EX! ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   256
		    "This could happen if you tried to write to the MLDBM ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   257
		    "in a critical section locked by ReadLock(). ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   258
		    "Also the read expression my \$v = \$db{'key1'}{'key2'} will trigger a write ".
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   259
		    "if \$db{'key1'} does not already exist, so this will error in a ReadLock() section"
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   260
		    );
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   261
	}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   262
	1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   263
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   264
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   265
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   266
*unlock = *SyncUnLock = *UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   267
sub UnLock {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   268
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   269
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   270
    if($self->{lock_num} && $self->{lock_num}-- == 1) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   271
	$self->{lock_num} = 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   272
	undef $self->{dbm};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   273
	flock($self->{'lock_fh'}, $LOCK_UN) || die("can't unlock $self->{'lock_file'}: $!");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   274
	close($self->{'lock_fh'}) || die("can't close $self->{'lock_file'}");
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   275
	$self->{read_lock} = undef;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   276
	1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   277
    } else {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   278
	1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   279
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   280
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   281
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   282
sub SyncSize {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   283
    my $self = shift;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   284
    my $size = 0;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   285
    for (@EXT) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   286
	my $file = $self->{file}.$_;	
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   287
	next unless -e $file;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   288
	$size += (stat($file))[7];
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   289
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   290
	if(-d $file) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   291
	    $size += (stat($file))[7];
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   292
	    opendir(DIR, $file) || next;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   293
	    my @files = readdir(DIR);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   294
	    for my $dir_file (@files) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   295
		next if $dir_file =~ /^\.\.?$/;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   296
		$size += (stat("$file/$dir_file"))[7];
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   297
	    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   298
	    closedir(DIR);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   299
	}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   300
    }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   301
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   302
    $size;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   303
}
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   304
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   305
1;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   306
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   307
__END__
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   308
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   309
=head1 NAME
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   310
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   311
  MLDBM::Sync - safe concurrent access to MLDBM databases
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   312
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   313
=head1 SYNOPSIS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   314
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   315
  use MLDBM::Sync;                       # this gets the default, SDBM_File
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   316
  use MLDBM qw(DB_File Storable);        # use Storable for serializing
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   317
  use MLDBM qw(MLDBM::Sync::SDBM_File);  # use extended SDBM_File, handles values > 1024 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   318
  use Fcntl qw(:DEFAULT);                # import symbols O_CREAT & O_RDWR for use with DBMs
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   319
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   320
  # NORMAL PROTECTED read/write with implicit locks per i/o request
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   321
  my $sync_dbm_obj = tie %cache, 'MLDBM::Sync' [..other DBM args..] or die $!;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   322
  $cache{"AAAA"} = "BBBB";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   323
  my $value = $cache{"AAAA"};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   324
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   325
  # SERIALIZED PROTECTED read/write with explicit lock for both i/o requests
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   326
  my $sync_dbm_obj = tie %cache, 'MLDBM::Sync', '/tmp/syncdbm', O_CREAT|O_RDWR, 0640;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   327
  $sync_dbm_obj->Lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   328
  $cache{"AAAA"} = "BBBB";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   329
  my $value = $cache{"AAAA"};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   330
  $sync_dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   331
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   332
  # SERIALIZED PROTECTED READ access with explicit read lock for both reads
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   333
  $sync_dbm_obj->ReadLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   334
  my @keys = keys %cache;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   335
  my $value = $cache{'AAAA'};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   336
  $sync_dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   337
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   338
  # MEMORY CACHE LAYER with Tie::Cache
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   339
  $sync_dbm_obj->SyncCacheSize('100K');
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   340
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   341
  # KEY CHECKSUMS, for lookups on MD5 checksums on large keys
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   342
  my $sync_dbm_obj = tie %cache, 'MLDBM::Sync', '/tmp/syncdbm', O_CREAT|O_RDWR, 0640;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   343
  $sync_dbm_obj->SyncKeysChecksum(1);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   344
  my $large_key = "KEY" x 10000;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   345
  $sync{$large_key} = "LARGE";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   346
  my $value = $sync{$large_key};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   347
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   348
=head1 DESCRIPTION
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   349
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   350
This module wraps around the MLDBM interface, by handling concurrent
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   351
access to MLDBM databases with file locking, and flushes i/o explicity
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   352
per lock/unlock.  The new [Read]Lock()/UnLock() API can be used to serialize
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   353
requests logically and improve performance for bundled reads & writes.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   354
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   355
  my $sync_dbm_obj = tie %cache, 'MLDBM::Sync', '/tmp/syncdbm', O_CREAT|O_RDWR, 0640;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   356
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   357
  # Write locked critical section
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   358
  $sync_dbm_obj->Lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   359
    ... all accesses to DBM LOCK_EX protected, and go to same tied file handles
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   360
    $cache{'KEY'} = 'VALUE';
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   361
  $sync_dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   362
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   363
  # Read locked critical section
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   364
  $sync_dbm_obj->ReadLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   365
    ... all read accesses to DBM LOCK_SH protected, and go to same tied files
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   366
    ... WARNING, cannot write to DBM in ReadLock() section, will die()
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   367
    ... WARNING, my $v = $cache{'KEY'}{'SUBKEY'} will trigger a write so not safe
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   368
    ...   to use in ReadLock() section
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   369
    my $value = $cache{'KEY'};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   370
  $sync_dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   371
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   372
  # Normal access OK too, without explicity locking
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   373
  $cache{'KEY'} = 'VALUE';
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   374
  my $value = $cache{'KEY'};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   375
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   376
MLDBM continues to serve as the underlying OO layer that
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   377
serializes complex data structures to be stored in the databases.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   378
See the MLDBM L<BUGS> section for important limitations.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   379
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   380
MLDBM::Sync also provides built in RAM caching with Tie::Cache
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   381
md5 key checksum functionality.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   382
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   383
=head1 INSTALL
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   384
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   385
Like any other CPAN module, either use CPAN.pm, or perl -MCPAN C<-e> shell,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   386
or get the file MLDBM-Sync-x.xx.tar.gz, unzip, untar and:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   387
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   388
  perl Makefile.PL
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   389
  make
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   390
  make test
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   391
  make install
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   392
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   393
=head1 LOCKING
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   394
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   395
The MLDBM::Sync wrapper protects MLDBM databases by locking
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   396
and unlocking around read and write requests to the databases.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   397
Also necessary is for each new lock to tie() to the database
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   398
internally, untie()ing when unlocking.  This flushes any
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   399
i/o for the dbm to the operating system, and allows for
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   400
concurrent read/write access to the databases.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   401
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   402
Without any extra effort from the developer, an existing 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   403
MLDBM database will benefit from MLDBM::sync.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   404
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   405
  my $dbm_obj = tie %dbm, ...;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   406
  $dbm{"key"} = "value";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   407
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   408
As a write or STORE operation, the above will automatically
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   409
cause the following:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   410
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   411
  $dbm_obj->Lock; # also ties
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   412
  $dbm{"key"} = "value";
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   413
  $dbm_obj->UnLock; # also unties
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   414
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   415
Just so, a read or FETCH operation like:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   416
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   417
  my $value = $dbm{"key"};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   418
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   419
will really trigger:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   420
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   421
  $dbm_obj->ReadLock; # also ties
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   422
  my $value = $dbm{"key"};
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   423
  $dbm_obj->Lock; # also unties
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   424
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   425
However, these lock operations are expensive because of the 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   426
underlying tie()/untie() that occurs for i/o flushing, so 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   427
when bundling reads & writes, a developer may explicitly
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   428
use this API for greater performance:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   429
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   430
  # tie once to database, write 100 times
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   431
  $dbm_obj->Lock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   432
  for (1..100) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   433
    $dbm{$_} = $_ * 100;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   434
    ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   435
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   436
  $dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   437
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   438
  # only tie once to database, and read 100 times
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   439
  $dbm_obj->ReadLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   440
  for(1..100) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   441
    my $value = $dbm{$_};  
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   442
    ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   443
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   444
  $dbm_obj->UnLock;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   445
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   446
=head1 CACHING
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   447
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   448
I built MLDBM::Sync to serve as a fast and robust caching layer
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   449
for use in multi-process environments like mod_perl.  In order
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   450
to provide an additional speed boost when caching static data,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   451
I have added an RAM caching layer with Tie::Cache, which 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   452
regulates the size of the memory used with its MaxBytes setting.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   453
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   454
To activate this caching, just:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   455
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   456
  my $dbm = tie %cache, 'MLDBM::Sync', '/tmp/syncdbm', O_CREAT|O_RDWR, 0640;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   457
  $dbm->SyncCacheSize(100000);  # 100000 bytes max memory used
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   458
  $dbm->SyncCacheSize('100K');  # 100 Kbytes max memory used
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   459
  $dbm->SyncCacheSize('1M');    # 1 Megabyte max memory used
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   460
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   461
The ./bench/bench_sync.pl, run like "bench_sync.pl C<-c>" will run 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   462
the tests with caching turned on creating a benchmark with 50%
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   463
cache hits.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   464
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   465
One run without caching was:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   466
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   467
 === INSERT OF 50 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   468
  Time for 100 writes + 100 reads for  SDBM_File                  0.16 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   469
  Time for 100 writes + 100 reads for  MLDBM::Sync::SDBM_File     0.17 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   470
  Time for 100 writes + 100 reads for  GDBM_File                  3.37 seconds     17980 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   471
  Time for 100 writes + 100 reads for  DB_File                    4.45 seconds     20480 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   472
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   473
And with caching, with 50% cache hits:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   474
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   475
 === INSERT OF 50 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   476
  Time for 100 writes + 100 reads for  SDBM_File                  0.11 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   477
  Time for 100 writes + 100 reads for  MLDBM::Sync::SDBM_File     0.11 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   478
  Time for 100 writes + 100 reads for  GDBM_File                  2.49 seconds     17980 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   479
  Time for 100 writes + 100 reads for  DB_File                    2.55 seconds     20480 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   480
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   481
Even for SDBM_File, this speedup is near 33%.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   482
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   483
=head1 KEYS CHECKSUM
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   484
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   485
A common operation on database lookups is checksumming
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   486
the key, prior to the lookup, because the key could be
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   487
very large, and all one really wants is the data it maps
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   488
too.  To enable this functionality automatically with 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   489
MLDBM::Sync, just:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   490
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   491
  my $sync_dbm_obj = tie %cache, 'MLDBM::Sync', '/tmp/syncdbm', O_CREAT|O_RDWR, 0640;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   492
  $sync_dbm_obj->SyncKeysChecksum(1);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   493
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   494
 !! WARNING: keys() & each() do not work on these databases
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   495
 !! as of v.03, so the developer will not be fooled into thinking
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   496
 !! the stored key values are meaningful to the calling application 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   497
 !! and will die() if called.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   498
 !!
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   499
 !! This behavior could be relaxed in the future.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   500
 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   501
An example of this might be to cache a XSLT conversion,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   502
which are typically very expensive.  You have the 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   503
XML data and the XSLT data, so all you do is:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   504
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   505
  # $xml_data, $xsl_data are strings
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   506
  my $xslt_output;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   507
  unless ($xslt_output = $cache{$xml_data.'&&&&'.$xsl_data}) {
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   508
    ... do XSLT conversion here for $xslt_output ...
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   509
    $cache{$xml_data.'&&&&'.xsl_data} = $xslt_output;
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   510
  }
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   511
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   512
What you save by doing this is having to create HUGE keys
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   513
to lookup on, which no DBM is likely to do efficiently.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   514
This is the same method that File::Cache uses internally to 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   515
hash its file lookups in its directories.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   516
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   517
=head1 New MLDBM::Sync::SDBM_File
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   518
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   519
SDBM_File, the default used for MLDBM and therefore MLDBM::Sync 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   520
has a limit of 1024 bytes for the size of a record.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   521
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   522
SDBM_File is also an order of magnitude faster for small records
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   523
to use with MLDBM::Sync, than DB_File or GDBM_File, because the
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   524
tie()/untie() to the dbm is much faster.  Therefore,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   525
bundled with MLDBM::Sync release is a MLDBM::Sync::SDBM_File
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   526
layer which works around this 1024 byte limit.  To use, just:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   527
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   528
  use MLDBM qw(MLDBM::Sync::SDBM_File);
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   529
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   530
It works by breaking up up the STORE() values into small 128 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   531
byte segments, and spreading those segments across many records,
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   532
creating a virtual record layer.  It also uses Compress::Zlib
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   533
to compress STORED data, reducing the number of these 128 byte 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   534
records. In benchmarks, 128 byte record segments seemed to be a
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   535
sweet spot for space/time efficiency, as SDBM_File created
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   536
very bloated *.pag files for 128+ byte records.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   537
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   538
=head1 BENCHMARKS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   539
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   540
In the distribution ./bench directory is a bench_sync.pl script
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   541
that can benchmark using the various DBMs with MLDBM::Sync.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   542
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   543
The MLDBM::Sync::SDBM_File DBM is special because is uses 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   544
SDBM_File for fast small inserts, but slows down linearly
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   545
with the size of the data being inserted and read.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   546
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   547
The results for a dual PIII-450 linux 2.4.7, with a ext3 file system 
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   548
blocksize 4096 mounted async on a RAID-1 2xIDE 7200 RPM disk were as follows:
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   549
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   550
 === INSERT OF 50 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   551
  Time for 100 writes + 100 reads for  SDBM_File                  0.16 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   552
  Time for 100 writes + 100 reads for  MLDBM::Sync::SDBM_File     0.19 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   553
  Time for 100 writes + 100 reads for  GDBM_File                  1.09 seconds     18066 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   554
  Time for 100 writes + 100 reads for  DB_File                    0.67 seconds     12288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   555
  Time for 100 writes + 100 reads for  Tie::TextDir .04           0.31 seconds     13192 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   556
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   557
 === INSERT OF 500 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   558
 (skipping test for SDBM_File 100 byte limit)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   559
  Time for 100 writes + 100 reads for  MLDBM::Sync::SDBM_File     0.52 seconds    110592 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   560
  Time for 100 writes + 100 reads for  GDBM_File                  1.20 seconds     63472 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   561
  Time for 100 writes + 100 reads for  DB_File                    0.66 seconds     86016 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   562
  Time for 100 writes + 100 reads for  Tie::TextDir .04           0.32 seconds     58192 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   563
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   564
 === INSERT OF 5000 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   565
 (skipping test for SDBM_File 100 byte limit)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   566
  Time for 100 writes + 100 reads for  MLDBM::Sync::SDBM_File     1.41 seconds   1163264 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   567
  Time for 100 writes + 100 reads for  GDBM_File                  1.38 seconds    832400 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   568
  Time for 100 writes + 100 reads for  DB_File                    1.21 seconds    831488 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   569
  Time for 100 writes + 100 reads for  Tie::TextDir .04           0.58 seconds    508192 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   570
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   571
 === INSERT OF 20000 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   572
 (skipping test for SDBM_File 100 byte limit)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   573
 (skipping test for MLDBM::Sync db size > 1M)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   574
  Time for 100 writes + 100 reads for  GDBM_File                  2.23 seconds   2063912 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   575
  Time for 100 writes + 100 reads for  DB_File                    1.89 seconds   2060288 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   576
  Time for 100 writes + 100 reads for  Tie::TextDir .04           1.26 seconds   2008192 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   577
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   578
 === INSERT OF 50000 BYTE RECORDS ===
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   579
 (skipping test for SDBM_File 100 byte limit)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   580
 (skipping test for MLDBM::Sync db size > 1M)
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   581
  Time for 100 writes + 100 reads for  GDBM_File                  3.66 seconds   5337944 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   582
  Time for 100 writes + 100 reads for  DB_File                    3.64 seconds   5337088 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   583
  Time for 100 writes + 100 reads for  Tie::TextDir .04           2.80 seconds   5008192 bytes
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   584
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   585
=head1 AUTHORS
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   586
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   587
Copyright (c) 2001-2002 Joshua Chamas, Chamas Enterprises Inc.  All rights reserved.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   588
Sponsored by development on NodeWorks http://www.nodeworks.com and Apache::ASP
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   589
http://www.apache-asp.org
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   590
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   591
This program is free software; you can redistribute it
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   592
and/or modify it under the same terms as Perl itself.
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   593
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   594
=head1 SEE ALSO
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   595
3145852acc89 add releasing to new structure
jjkang
parents:
diff changeset
   596
 MLDBM(3), SDBM_File(3), DB_File(3), GDBM_File(3)