--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/releasing/cbrtools/perl/MLDBM/Sync/SDBM_File.pm Fri Jun 25 18:37:20 2010 +0800
@@ -0,0 +1,163 @@
+# Copyright (c) 2001-2002 Joshua Chamas, Chamas Enterprises Inc. All rights reserved.
+# Sponsored by development on NodeWorks http://www.nodeworks.com and Apache::ASP
+# http://www.apache-asp.org
+#
+# This program is free software; you can redistribute it
+# and/or modify it under the same terms as Perl itself.
+
+package MLDBM::Sync::SDBM_File;
+$VERSION = .17;
+
+use SDBM_File;
+use strict;
+use vars qw(@ISA $MaxSegments $MaxSegmentLength %KEYS $Zlib $VERSION);
+
+@ISA = qw(SDBM_File);
+$MaxSegments = 8192; # to a 1M limit
+# leave room for key index pad
+$MaxSegmentLength = 128;
+eval "use Compress::Zlib";
+$Zlib = $@ ? 0 : 1;
+
+sub FETCH {
+ my($self, $key) = @_;
+ my $segment_length = $MaxSegmentLength;
+
+ my $total_rv;
+ for(my $index = 0; $index < $MaxSegments; $index++) {
+ my $rv = $self->SUPER::FETCH(_index_key($key, $index));
+ if(defined $rv) {
+ $total_rv ||= '';
+ $total_rv .= $rv;
+ last if length($rv) < $segment_length;
+ } else {
+ last;
+ }
+ }
+
+ if(defined $total_rv) {
+ $total_rv =~ s/^(..)//s;
+ my $type = $1;
+ if($type eq 'G}') {
+ $total_rv = uncompress($total_rv);
+ } elsif ($type eq 'N}') {
+ # nothing
+ } else {
+ # old SDBM_File ?
+ $total_rv = $type . $total_rv;
+ }
+ }
+
+ $total_rv;
+}
+
+sub STORE {
+ my($self, $key, $value) = @_;
+ my $segment_length = $MaxSegmentLength;
+
+ # DELETE KEYS FIRST
+ for(my $index = 0; $index < $MaxSegments; $index++) {
+ my $index_key = _index_key($key, $index);
+ my $rv = $self->SUPER::FETCH($index_key);
+ if(defined $rv) {
+ $self->SUPER::DELETE($index_key);
+ } else {
+ last;
+ }
+ last if length($rv) < $segment_length;
+ }
+
+ # G - Gzip compression
+ # N - No compression
+ #
+ my $old_value = $value;
+ $value = ($Zlib && (length($value) >= $segment_length/2)) ? "G}".compress($value) : "N}".$value;
+
+ my($total_rv, $last_index);
+ for(my $index = 0; $index < $MaxSegments; $index++) {
+ if($index == $MaxSegments) {
+ die("can't store more than $MaxSegments segments of $MaxSegmentLength bytes per key in ".__PACKAGE__);
+ }
+ $value =~ s/^(.{0,$segment_length})//so;
+ my $segment = $1;
+
+ last if length($segment) == 0;
+# print "STORING "._index_key($key, $index)." $segment\n";
+ my $rv = $self->SUPER::STORE(_index_key($key, $index), $segment);
+ $total_rv .= $segment;
+ $last_index = $index;
+ }
+
+# use Time::HiRes;
+# print "[".&Time::HiRes::time()."] STORED ".($last_index+1)." segments for length ".
+# length($total_rv)." bytes for value ".length($old_value)."\n";
+
+ $old_value;
+}
+
+sub DELETE {
+ my($self, $key) = @_;
+ my $segment_length = $MaxSegmentLength;
+
+ my $total_rv;
+ for(my $index = 0; $index < $MaxSegments; $index++) {
+ my $index_key = _index_key($key, $index);
+ my $rv = $self->SUPER::FETCH($index_key) || '';
+ $self->SUPER::DELETE($index_key);
+ $total_rv ||= '';
+ $total_rv .= $rv;
+ last if length($rv) < $segment_length;
+ }
+
+ $total_rv =~ s/^(..)//s;
+ my $type = $1;
+ if($type eq 'G}') {
+ $total_rv = uncompress($total_rv);
+ } elsif ($type eq 'N}') {
+ # normal
+ } else {
+ # old SDBM_File
+ $total_rv = $type.$total_rv;
+ }
+
+ $total_rv;
+}
+
+sub FIRSTKEY {
+ my $self = shift;
+
+ my $key = $self->SUPER::FIRSTKEY();
+ my @keys = ();
+ if (defined $key) {
+ do {
+ if($key !~ /\*\*\d+$/s) {
+ if(my $new_key = _decode_key($key)) {
+ push(@keys, $new_key);
+ }
+ }
+ } while($key = $self->SUPER::NEXTKEY($key));
+ }
+ $KEYS{$self} = \@keys;
+
+ $self->NEXTKEY;
+}
+
+sub NEXTKEY {
+ my $self = shift;
+ shift(@{$KEYS{$self}});
+}
+
+sub _index_key {
+ my($key, $index) = @_;
+ $key =~ s/([\%\*])/uc sprintf("%%%02x",ord($1))/esg;
+ $index ? $key.'**'.$index : $key;
+}
+
+sub _decode_key {
+ my $key = shift;
+ $key =~ s/%([0-9a-fA-F]{2})/pack("c",hex($1))/ge;
+ $key;
+}
+
+1;
+