/[wait]/trunk/lib/WAIT/Table.pm
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/lib/WAIT/Table.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

branches/CPAN/lib/WAIT/Table.pm revision 13 by ulpfr, Fri Apr 28 15:42:44 2000 UTC cvs-head/lib/WAIT/Table.pm revision 31 by laperla, Sun Nov 12 01:26:10 2000 UTC
# Line 4  Line 4 
4  # Author          : Ulrich Pfeifer  # Author          : Ulrich Pfeifer
5  # Created On      : Thu Aug  8 13:05:10 1996  # Created On      : Thu Aug  8 13:05:10 1996
6  # Last Modified By: Ulrich Pfeifer  # Last Modified By: Ulrich Pfeifer
7  # Last Modified On: Sun May 30 20:42:30 1999  # Last Modified On: Fri May 19 14:51:14 2000
8  # Language        : CPerl  # Language        : CPerl
9  # Update Count    : 56  # Update Count    : 133
10  # Status          : Unknown, Use with caution!  # Status          : Unknown, Use with caution!
11  #  #
12  # Copyright (c) 1996-1997, Ulrich Pfeifer  # Copyright (c) 1996-1997, Ulrich Pfeifer
# Line 34  use Carp; Line 34  use Carp;
34  # use autouse Carp => qw( croak($) );  # use autouse Carp => qw( croak($) );
35  use DB_File;  use DB_File;
36  use Fcntl;  use Fcntl;
37    use LockFile::Simple ();
38    
39  my $USE_RECNO = 0;  my $USE_RECNO = 0;
40    
# Line 163  sub new { Line 164  sub new {
164    } elsif (!mkdir($self->{file}, 0775)) {    } elsif (!mkdir($self->{file}, 0775)) {
165      croak "Could not 'mkdir $self->{file}': $!\n";      croak "Could not 'mkdir $self->{file}': $!\n";
166    }    }
167    
168      my $lockmgr = LockFile::Simple->make(-autoclean => 1);
169      # aquire a write lock
170      $self->{write_lock} = $lockmgr->lock($self->{file} . '/write')
171        or die "Can't lock '$self->{file}/write'";
172    
173    $self->{djk}      = $parm{djk}      if defined $parm{djk};    $self->{djk}      = $parm{djk}      if defined $parm{djk};
174    $self->{layout}   = $parm{layout} || new WAIT::Parse::Base;    $self->{layout}   = $parm{layout} || new WAIT::Parse::Base;
175    $self->{access}   = $parm{access} if defined $parm{access};    $self->{access}   = $parm{access} if defined $parm{access};
# Line 188  sub new { Line 195  sub new {
195      }      }
196      $self->create_inverted_index(attribute => $att, pipeline  => \@spec, @opt);      $self->create_inverted_index(attribute => $att, pipeline  => \@spec, @opt);
197    }    }
198    
199    $self;    $self;
200    # end of backwarn compatibility stuff    # end of backwarn compatibility stuff
201  }  }
# Line 323  sub drop { Line 331  sub drop {
331        $_->drop;        $_->drop;
332      }      }
333      unlink "$file/records";      unlink "$file/records";
334        # $self->unlock;
335      ! (!-e $file or rmdir $file);      ! (!-e $file or rmdir $file);
336    } else {    } else {
337      croak ref($self)."::drop called directly";      croak ref($self)."::drop called directly";
# Line 373  sub open { Line 382  sub open {
382                           $self->{mode}, 0664, $DB_BTREE);                           $self->{mode}, 0664, $DB_BTREE);
383      }      }
384    }    }
385    
386      # Locking
387      #
388      # We allow multiple readers to coexists.  But write access excludes
389      # all read access vice versa.  In practice read access on tables
390      # open for writing will mostly work ;-)
391    
392      my $lockmgr = LockFile::Simple->make(-autoclean => 1);
393    
394      # aquire a write lock. We might hold one acquired in create() already
395      $self->{write_lock} ||= $lockmgr->lock($self->{file} . '/write')
396        or die "Can't lock '$self->{file}/write'";
397    
398      my $lockdir = $self->{file} . '/read';
399      unless (-d $lockdir) {
400        mkdir $lockdir, 0755 or die "Could not mkdir $lockdir: $!";
401      }
402    
403      if ($self->{mode} & O_RDWR) {
404        # this is a hack.  We do not check for reopening ...
405        return $self if $self->{write_lock};
406        
407        # If we actually want to write we must check if there are any readers
408        local *DIR;
409        opendir DIR, $lockdir or
410          die "Could not opendir '$lockdir': $!";
411        for my $lockfile (grep { -f "$lockdir/$_" } readdir DIR) {
412          # check if the locks are still valid.
413          # Since we are protected by a write lock, we could use a pline file.
414          # But we want to use the stale testing from LockFile::Simple.
415          if (my $lck = $lockmgr->trylock("$lockdir/$lockfile")) {
416            warn "Removing stale lockfile '$lockdir/$lockfile'";
417            $lck->release;
418          } else {
419            $self->{write_lock}->release;
420            die "Cannot write table '$file' while it's in use";
421          }
422        }
423        closedir DIR;
424      } else {
425        # this is a hack.  We do not check for reopening ...
426        return $self if $self->{read_lock};
427        
428        # We are a reader. So we release the write lock
429        my $id = time;
430        while (-f "$lockdir/$id.lock") { # here assume ".lock" format!
431          $id++;
432        }
433        $self->{read_lock} = $lockmgr->lock("$lockdir/$id");
434        $self->{write_lock}->release;
435        delete $self->{write_lock};
436      }
437    
438    $self;    $self;
439  }  }
440    
# Line 432  sub insert { Line 494  sub insert {
494    my $tuple = join($;, map($parm{$_} || '', @{$self->{attr}}));    my $tuple = join($;, map($parm{$_} || '', @{$self->{attr}}));
495    my $key;    my $key;
496    my @deleted = keys %{$self->{deleted}};    my @deleted = keys %{$self->{deleted}};
497      my $gotkey = 0;
498    
499    if (@deleted) {    if (@deleted) {
500      $key = pop @deleted;      $key = pop @deleted;
501      delete $self->{deleted}->{$key};      delete $self->{deleted}->{$key};
502        # Sanity check
503        if ($key && $key>0) {
504          $gotkey=1;
505    } else {    } else {
506          warn(sprintf("WAIT database inconsistency during insert ".
507                       "key[%s]: Please rebuild index\n",
508                       $key
509                      ));
510        }
511      }
512      unless ($gotkey) {
513      $key = $self->{nextk}++;      $key = $self->{nextk}++;
514    }    }
515    if ($USE_RECNO) {    if ($USE_RECNO) {
# Line 450  sub insert { Line 523  sub insert {
523        if ($key == $self->{nextk}-1) {        if ($key == $self->{nextk}-1) {
524          $self->{nextk}--;          $self->{nextk}--;
525        } else {        } else {
526            # warn "setting key[$key] deleted during insert";
527          $self->{deleted}->{$key}=1;          $self->{deleted}->{$key}=1;
528        }        }
529        my $idx;        my $idx;
# Line 504  sub delete_by_key { Line 578  sub delete_by_key {
578    my $self  = shift;    my $self  = shift;
579    my $key   = shift;    my $key   = shift;
580    
581      unless ($key) {
582        Carp::cluck "Warning: delete_by_key called without key. Looks like a bug in WAIT?";
583        return;
584      }
585    
586    return $self->{deleted}->{$key} if defined $self->{deleted}->{$key};    return $self->{deleted}->{$key} if defined $self->{deleted}->{$key};
587    my %tuple = $self->fetch($key);    my %tuple = $self->fetch($key);
588    for (values %{$self->{indexes}}) {    for (values %{$self->{indexes}}) {
# Line 520  sub delete_by_key { Line 599  sub delete_by_key {
599        }        }
600      }      }
601    }    }
602      # warn "setting key[$key] deleted during delete_by_key";
603    ++$self->{deleted}->{$key};    ++$self->{deleted}->{$key};
604  }  }
605    
606  sub delete {  sub delete {
607    my $self  = shift;    my $self  = shift;
608    my $tkey = $self->have(@_);    my $tkey = $self->have(@_);
609      # warn "tkey[$tkey]\@_[@_]";
610    defined $tkey && $self->delete_by_key($tkey, @_);    defined $tkey && $self->delete_by_key($tkey, @_);
611  }  }
612    
613  sub unpack {  sub unpack {
614    my $self = shift;    my($self, $tuple) = @_;
615    my $tuple = shift;  
616      unless (defined $tuple){
617        # require Carp; # unfortunately gives us "bizarre copy...." :-(((((
618        warn("Debug: somebody called unpack without argument tuple!");
619        return;
620      }
621    
622    my $att;    my $att;
623    my @result;    my @result;
# Line 544  sub unpack { Line 629  sub unpack {
629    @result;    @result;
630  }  }
631    
632    sub set {
633      my ($self, $iattr, $value) = @_;
634      
635      unless ($self->{write_lock}){
636        warn "Cannot set iattr[$iattr] without write lock. Nothing done";
637        return;
638      }
639      for my $att (keys %{$self->{inverted}}) {
640        if ($] > 5.003) {         # avoid bug in perl up to 5.003_05
641          my $idx;
642          for $idx (@{$self->{inverted}->{$att}}) {
643            $idx->set($iattr, $value);
644          }
645        } else {
646          map $_->set($iattr, $value), @{$self->{inverted}->{$att}};
647        }
648      }
649    
650      1;
651    }
652    
653  sub close {  sub close {
654    my $self = shift;    my $self = shift;
655    
656    if (exists $self->{'access'}) {    if (exists $self->{'access'}) {
657      eval {$self->{'access'}->close}; # dont bother if not opened      eval {$self->{'access'}->close}; # dont bother if not opened
658    }    }
659    for (values %{$self->{indexes}}) {    if ($WAIT::Index::VERSION) {
660      $_->close();      for (values %{$self->{indexes}}) {
661          $_->close();
662        }
663    }    }
664    if (defined $self->{inverted}) {    if (defined $self->{inverted} && $WAIT::InvertedIndex::VERSION) {
665        # require WAIT::InvertedIndex; Uli: we can avoid closing indexes:
666        # if WAIT::InvertedIndex has not been loaded, they cannot have
667        # been altered so far
668      my $att;      my $att;
669      for $att (keys %{$self->{inverted}}) {      for $att (keys %{$self->{inverted}}) {
670        if ($] > 5.003) {         # avoid bug in perl up to 5.003_05        if ($] > 5.003) {         # avoid bug in perl up to 5.003_05
# Line 577  sub close { Line 688  sub close {
688      delete $self->{db};      delete $self->{db};
689    }    }
690    
691      $self->unlock;
692      
693    1;    1;
694  }  }
695    
696    sub unlock {
697      my $self = shift;
698    
699      # Either we have a read or a write lock (or we close the table already)
700      # unless ($self->{read_lock} || $self->{write_lock}) {
701      #   warn "WAIT::Table::unlock: Table aparently hold's no lock"
702      # }
703      if ($self->{write_lock}) {
704        $self->{write_lock}->release();
705        delete $self->{write_lock};
706      }
707      if ($self->{read_lock}) {
708        $self->{read_lock}->release();
709        delete $self->{read_lock};
710      }
711    
712    }
713    
714  sub DESTROY {  sub DESTROY {
715    my $self = shift;    my $self = shift;
716    
717    warn "Table handle destroyed without closing it first"    warn "Table handle destroyed without closing it first"
718      if $self->{db} and $self->{mode}&O_RDWR;      if $self->{write_lock} || $self->{read_lock};
719  }  }
720    
721  sub open_scan {  sub open_scan {
# Line 642  sub intervall { Line 773  sub intervall {
773  }  }
774    
775  sub search {  sub search {
776    my $self = shift;    my $self  = shift;
777    my $attr = shift;    my ($query, $attr, $cont, $raw);
778    my $cont = shift;    if (ref $_[0]) {
779    my $raw  = shift;      $query = shift;
780      
781        $attr = $query->{attr};
782        $cont = $query->{cont};
783        $raw  = $query->{raw};
784      } else {
785        require Carp;
786        Carp::cluck("Using three argument search interface is deprecated, use hashref interface instead");
787        $attr = shift;
788        $cont = shift;
789        $raw  = shift;
790        $query = {
791                  attr => $attr,
792                  cont => $cont,
793                  raw  => $raw,
794                 };
795      }
796    
797    my %result;    my %result;
798    
799    defined $self->{db} or $self->open; # require layout    defined $self->{db} or $self->open; # require layout
# Line 655  sub search { Line 803  sub search {
803        my $name = $_->name;        my $name = $_->name;
804        if (exists $raw->{$name} and @{$raw->{$name}}) {        if (exists $raw->{$name} and @{$raw->{$name}}) {
805          my $scale = 1/scalar(@{$raw->{$name}});          my $scale = 1/scalar(@{$raw->{$name}});
806          my %r = $_->search_raw(@{$raw->{$name}});          my %r = $_->search_raw($query, @{$raw->{$name}});
807          my ($key, $val);          my ($key, $val);
808          while (($key, $val) = each %r) {          while (($key, $val) = each %r) {
809            if (exists $result{$key}) {            if (exists $result{$key}) {
# Line 669  sub search { Line 817  sub search {
817    }    }
818    if (defined $cont and $cont ne '') {    if (defined $cont and $cont ne '') {
819      for (@{$self->{inverted}->{$attr}}) {      for (@{$self->{inverted}->{$attr}}) {
820        my %r = $_->search($cont);        my %r = $_->search($query, $cont);
821        my ($key, $val);        my ($key, $val);
822        while (($key, $val) = each %r) {        while (($key, $val) = each %r) {
823          if (exists $result{$key}) {          if (exists $result{$key}) {

Legend:
Removed from v.13  
changed lines
  Added in v.31

  ViewVC Help
Powered by ViewVC 1.1.26