package Numbers; use strict; use warnings; use IO::File; use Carp; use Fcntl ':flock'; use Tie::Hash; our @ISA = qw(Tie::StdHash); use Storable qw(fd_retrieve store_fd); # VARs intern my $fh = new IO::File; # LOCK_EX my $init = 0; # Constructor sub TIEHASH{ my $class = shift; my $ref = shift or return; croak "No ref HASH in Arg" if ref $ref ne 'HASH'; croak "No file is given, use {-file => \$file} in Args" if not exists $ref->{-file}; my $self = _initialize($ref->{-file}) or return; # IO-Error # apply autoincrement for custom keys like 'foo', 'bar' if(exists $ref->{-auto}){ if(ref $ref->{-auto} eq 'ARRAY'){ foreach my $k(@{$ref->{-auto}}){ $self->{$k}++; } } else{ carp "Second Arg must be a ARRAY-Ref ['foo','bar']" } } return bless $self, $class; } # hash from $file sub _initialize{ my $file = shift; return if $init == 1; $init = 1; $fh->open($file, O_CREAT|O_BINARY|O_RDWR) or return; flock($fh, LOCK_EX) or carp "Your system does not support flock()!"; binmode $fh, ':raw'; my $ref = {}; eval { $ref = fd_retrieve($fh) }; # caught exception: file is void if($@){ return {} } else { return $ref } } # hash to file sub _serialize{ my $ref = shift; seek $fh, 0, 0; truncate $fh, 0; store_fd($ref, $fh); undef $fh; } # Overload method, make sure that value is numeric sub STORE{ my $self = shift; my $key = shift; my $value = shift; if($value =~ /^\d+$/){ $self->{$key} = $value; } else{ carp "Value is not numeric"; } } sub DESTROY{ my $self = shift; _serialize($self); } ########################################################################### 1; ######################################################################## ########################################################################### package main; my $file = 'd:/tmp/storednumbers.bin'; tie my %h, 'Numbers', {-file => $file, -auto => ['foo','bar']} or die $!; foreach my $k(keys %h){ print "$k => $h{$k}\n"; }