/[webpac2]/trunk/lib/WebPAC/Input.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/WebPAC/Input.pm

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

revision 760 by dpavlin, Wed Oct 25 15:56:44 2006 UTC revision 1304 by dpavlin, Sun Sep 20 21:38:15 2009 UTC
# Line 3  package WebPAC::Input; Line 3  package WebPAC::Input;
3  use warnings;  use warnings;
4  use strict;  use strict;
5    
6  use blib;  use lib 'lib';
7    
8  use WebPAC::Common;  use WebPAC::Common;
9  use base qw/WebPAC::Common/;  use base qw/WebPAC::Common/;
10  use Data::Dumper;  use Data::Dump qw/dump/;
11  use Encode qw/from_to/;  use Encode qw/decode from_to/;
12    use YAML;
13    
14  =head1 NAME  =head1 NAME
15    
16  WebPAC::Input - read different file formats into WebPAC  WebPAC::Input - read different file formats into WebPAC
17    
 =head1 VERSION  
   
 Version 0.13  
   
18  =cut  =cut
19    
20  our $VERSION = '0.13';  our $VERSION = '0.19';
21    
22  =head1 SYNOPSIS  =head1 SYNOPSIS
23    
# Line 43  Perhaps a little code snippet. Line 40  Perhaps a little code snippet.
40    
41          my $db = WebPAC::Input->new(          my $db = WebPAC::Input->new(
42                  module => 'WebPAC::Input::ISIS',                  module => 'WebPAC::Input::ISIS',
                 low_mem => 1,  
43          );          );
44    
45          $db->open( path => '/path/to/database' );          $db->open( path => '/path/to/database' );
# Line 62  Create new input database object. Line 58  Create new input database object.
58    
59    my $db = new WebPAC::Input(    my $db = new WebPAC::Input(
60          module => 'WebPAC::Input::MARC',          module => 'WebPAC::Input::MARC',
         encoding => 'ISO-8859-2',  
         low_mem => 1,  
61          recode => 'char pairs',          recode => 'char pairs',
62          no_progress_bar => 1,          no_progress_bar => 1,
63            input_config => {
64                    mapping => [ 'foo', 'bar', 'baz' ],
65            },
66    );    );
67    
68  C<module> is low-level file format module. See L<WebPAC::Input::ISIS> and  C<module> is low-level file format module. See L<WebPAC::Input::ISIS> and
69  L<WebPAC::Input::MARC>.  L<WebPAC::Input::MARC>.
70    
 Optional parametar C<encoding> specify application code page (which will be  
 used internally). This should probably be your terminal encoding, and by  
 default, it C<ISO-8859-2>.  
   
 Default is not to use C<low_mem> options (see L<MEMORY USAGE> below).  
   
71  C<recode> is optional string constisting of character or words pairs that  C<recode> is optional string constisting of character or words pairs that
72  should be replaced in input stream.  should be replaced in input stream.
73    
# Line 94  sub new { Line 85  sub new {
85    
86          my $log = $self->_get_logger;          my $log = $self->_get_logger;
87    
88          $log->logconfess("code_page argument is not suppored any more. change it to encoding") if ($self->{lookup});          $log->logconfess("code_page argument is not suppored any more.") if $self->{code_page};
89          $log->logconfess("lookup argument is not suppored any more. rewrite call to lookup_ref") if ($self->{lookup});          $log->logconfess("encoding argument is not suppored any more.") if $self->{encoding};
90            $log->logconfess("lookup argument is not suppored any more. rewrite call to lookup_ref") if $self->{lookup};
91            $log->logconfess("low_mem argument is not suppored any more. rewrite it to load_row and save_row") if $self->{low_mem};
92    
93          $log->logconfess("specify low-level file format module") unless ($self->{module});          $log->logconfess("specify low-level file format module") unless ($self->{module});
94          my $module_path = $self->{module};          my $module_path = $self->{module};
# Line 105  sub new { Line 98  sub new {
98    
99          require $module_path;          require $module_path;
100    
         # check if required subclasses are implemented  
         foreach my $subclass (qw/open_db fetch_rec init dump_rec/) {  
                 # FIXME  
         }  
   
         $self->{'encoding'} ||= 'ISO-8859-2';  
   
101          $self ? return $self : return undef;          $self ? return $self : return undef;
102  }  }
103    
# Line 119  sub new { Line 105  sub new {
105    
106  This function will read whole database in memory and produce lookups.  This function will read whole database in memory and produce lookups.
107    
108     my $store;     # simple in-memory hash
109    
110   $input->open(   $input->open(
111          path => '/path/to/database/file',          path => '/path/to/database/file',
112          code_page => 'cp852',          input_encoding => 'cp852',
113            strict_encoding => 0,
114          limit => 500,          limit => 500,
115          offset => 6000,          offset => 6000,
116          stats => 1,          stats => 1,
# Line 134  This function will read whole database i Line 123  This function will read whole database i
123                  901 => { '*' => { '^b' => ' ; ' } },                  901 => { '*' => { '^b' => ' ; ' } },
124          },          },
125          modify_file => 'conf/modify/mapping.map',          modify_file => 'conf/modify/mapping.map',
126            save_row => sub {
127                    my $a = shift;
128                    $store->{ $a->{id} } = $a->{row};
129            },
130            load_row => sub {
131                    my $a = shift;
132                    return defined($store->{ $a->{id} }) &&
133                            $store->{ $a->{id} };
134            },
135    
136   );   );
137    
138  By default, C<code_page> is assumed to be C<cp852>.  By default, C<input_encoding> is assumed to be C<cp852>.
139    
140  C<offset> is optional parametar to position at some offset before reading from database.  C<offset> is optional parametar to skip records at beginning.
141    
142  C<limit> is optional parametar to read just C<limit> records from database  C<limit> is optional parametar to read just C<limit> records from database
143    
# Line 154  C<modify_file> is alternative for C<modi Line 153  C<modify_file> is alternative for C<modi
153  (hopefully) simplier sintax than YAML or perl (see L</modify_file_regex>). This option  (hopefully) simplier sintax than YAML or perl (see L</modify_file_regex>). This option
154  overrides C<modify_records> if both exists for same input.  overrides C<modify_records> if both exists for same input.
155    
156    C<save_row> and C<load_row> are low-level implementation of store engine. Calling convention
157    is documented in example above.
158    
159    C<strict_encoding> should really default to 1, but it doesn't for now.
160    
161  Returns size of database, regardless of C<offset> and C<limit>  Returns size of database, regardless of C<offset> and C<limit>
162  parametars, see also C<size>.  parametars, see also C<size>.
163    
# Line 164  sub open { Line 168  sub open {
168          my $arg = {@_};          my $arg = {@_};
169    
170          my $log = $self->_get_logger();          my $log = $self->_get_logger();
171            $log->debug( "arguments: ",dump( $arg ));
172    
173            $log->logconfess("encoding argument is not suppored any more.") if $self->{encoding};
174            $log->logconfess("code_page argument is not suppored any more.") if $self->{code_page};
175          $log->logconfess("lookup argument is not suppored any more. rewrite call to lookup_coderef") if ($arg->{lookup});          $log->logconfess("lookup argument is not suppored any more. rewrite call to lookup_coderef") if ($arg->{lookup});
176          $log->logconfess("lookup_coderef must be CODE, not ",ref($arg->{lookup_coderef}))          $log->logconfess("lookup_coderef must be CODE, not ",ref($arg->{lookup_coderef}))
177                  if ($arg->{lookup_coderef} && ref($arg->{lookup_coderef}) ne 'CODE');                  if ($arg->{lookup_coderef} && ref($arg->{lookup_coderef}) ne 'CODE');
# Line 172  sub open { Line 179  sub open {
179          $log->debug( $arg->{lookup_coderef} ? '' : 'not ', "using lookup_coderef");          $log->debug( $arg->{lookup_coderef} ? '' : 'not ', "using lookup_coderef");
180    
181          $log->logcroak("need path") if (! $arg->{'path'});          $log->logcroak("need path") if (! $arg->{'path'});
182          my $code_page = $arg->{'code_page'} || 'cp852';          my $input_encoding = $arg->{'input_encoding'} || $self->{'input_encoding'} || 'cp852';
183    
184          # store data in object          # store data in object
         $self->{'input_code_page'} = $code_page;  
185          foreach my $v (qw/path offset limit/) {          foreach my $v (qw/path offset limit/) {
186                  $self->{$v} = $arg->{$v} if ($arg->{$v});                  $self->{$v} = $arg->{$v} if defined $arg->{$v};
187            }
188    
189            if ($arg->{load_row} || $arg->{save_row}) {
190                    $log->logconfess("save_row and load_row must be defined in pair and be CODE") unless (
191                            ref($arg->{load_row}) eq 'CODE' &&
192                            ref($arg->{save_row}) eq 'CODE'
193                    );
194                    $self->{load_row} = $arg->{load_row};
195                    $self->{save_row} = $arg->{save_row};
196                    $log->debug("using load_row and save_row instead of in-memory hash");
197          }          }
198    
199          my $filter_ref;          my $filter_ref;
# Line 207  sub open { Line 223  sub open {
223                  $log->debug("using modify_file $p");                  $log->debug("using modify_file $p");
224                  $rec_regex = $self->modify_file_regexps( $p );                  $rec_regex = $self->modify_file_regexps( $p );
225          } elsif (my $h = $arg->{modify_records}) {          } elsif (my $h = $arg->{modify_records}) {
226                  $log->debug("using modify_records ", Dumper( $h ));                  $log->debug("using modify_records ", sub { dump( $h ) });
227                  $rec_regex = $self->modify_record_regexps(%{ $h });                  $rec_regex = $self->modify_record_regexps(%{ $h });
228          }          }
229          $log->debug("rec_regex: ", Dumper($rec_regex)) if ($rec_regex);          $log->debug("rec_regex: ", sub { dump($rec_regex) }) if ($rec_regex);
230    
231          my $class = $self->{module} || $log->logconfess("can't get low-level module name!");          my $class = $self->{module} || $log->logconfess("can't get low-level module name!");
232    
233            $arg->{$_} = $self->{$_} foreach qw(offset limit);
234    
235          my $ll_db = $class->new(          my $ll_db = $class->new(
236                  path => $arg->{path},                  path => $arg->{path},
237                    input_config => $arg->{input_config} || $self->{input_config},
238  #               filter => sub {  #               filter => sub {
239  #                       my ($l,$f_nr) = @_;  #                       my ($l,$f_nr) = @_;
240  #                       return unless defined($l);  #                       return unless defined($l);
241  #                       from_to($l, $code_page, $self->{'encoding'});  #                       $l = decode($input_encoding, $l);
242  #                       $l =~ s/($recode_regex)/$recode_map->{$1}/g if ($recode_regex && $recode_map);  #                       $l =~ s/($recode_regex)/$recode_map->{$1}/g if ($recode_regex && $recode_map);
243  #                       return $l;  #                       return $l;
244  #               },  #               },
245                  %{ $arg },                  %{ $arg },
246          );          );
247    
248            # save for dump and input_module
249            $self->{ll_db} = $ll_db;
250    
251          unless (defined($ll_db)) {          unless (defined($ll_db)) {
252                  $log->logwarn("can't open database $arg->{path}, skipping...");                  $log->logwarn("can't open database $arg->{path}, skipping...");
253                  return;                  return;
# Line 242  sub open { Line 264  sub open {
264          my $to_rec = $size;          my $to_rec = $size;
265    
266          if (my $s = $self->{offset}) {          if (my $s = $self->{offset}) {
267                  $log->debug("skipping to MFN $s");                  $log->debug("offset $s records");
268                  $from_rec = $s;                  $from_rec = $s + 1;
269          } else {          } else {
270                  $self->{offset} = $from_rec;                  $self->{offset} = $from_rec - 1;
271          }          }
272    
273          if ($self->{limit}) {          if ($self->{limit}) {
# Line 255  sub open { Line 277  sub open {
277          }          }
278    
279          # store size for later          # store size for later
280          $self->{size} = ($to_rec - $from_rec) ? ($to_rec - $from_rec + 1) : 0;          $self->{size} = $to_rec - $from_rec + 1;
   
         $log->info("processing $self->{size}/$size records [$from_rec-$to_rec] convert $code_page -> $self->{encoding}", $self->{stats} ? ' [stats]' : '');  
   
         # turn on low_mem for databases with more than 100000 records!  
         if (! $self->{low_mem} && $size > 100000) {  
                 $log->warn("Using on-disk storage instead of memory for input data. This will affect performance.");  
                 $self->{low_mem}++;  
         }  
   
         # running with low_mem flag? well, use DBM::Deep then.  
         if ($self->{'low_mem'}) {  
                 $log->info("running with low_mem which impacts performance (<32 Mb memory usage)");  
   
                 my $db_file = "data.db";  
   
                 if (-e $db_file) {  
                         unlink $db_file or $log->logdie("can't remove '$db_file' from last run");  
                         $log->debug("removed '$db_file' from last run");  
                 }  
281    
282                  require DBM::Deep;          my $strict_encoding = $arg->{strict_encoding} || $self->{strict_encoding}; ## FIXME should be 1 really
283    
284                  my $db = new DBM::Deep $db_file;          $log->info("processing $self->{size}/$size records [$from_rec-$to_rec]",
285                    " encoding $input_encoding ", $strict_encoding ? ' [strict]' : '',
286                  $log->logdie("DBM::Deep error: $!") unless ($db);                  $self->{stats} ? ' [stats]' : '',
287            );
                 if ($db->error()) {  
                         $log->logdie("can't open '$db_file' under low_mem: ",$db->error());  
                 } else {  
                         $log->debug("using file '$db_file' for DBM::Deep");  
                 }  
   
                 $self->{'db'} = $db;  
         }  
288    
289          # read database          # read database
290          for (my $pos = $from_rec; $pos <= $to_rec; $pos++) {          for (my $pos = $from_rec; $pos <= $to_rec; $pos++) {
# Line 297  sub open { Line 292  sub open {
292                  $log->debug("position: $pos\n");                  $log->debug("position: $pos\n");
293    
294                  my $rec = $ll_db->fetch_rec($pos, sub {                  my $rec = $ll_db->fetch_rec($pos, sub {
295                                  my ($l,$f_nr) = @_;                                  my ($l,$f_nr,$debug) = @_;
296  #                               return unless defined($l);  #                               return unless defined($l);
297  #                               return $l unless ($rec_regex && $f_nr);  #                               return $l unless ($rec_regex && $f_nr);
298    
299                                    return unless ( defined($l) && defined($f_nr) );
300    
301                                    warn "-=> $f_nr ## |$l|\n" if ($debug);
302                                  $log->debug("-=> $f_nr ## $l");                                  $log->debug("-=> $f_nr ## $l");
303    
304                                  # codepage conversion and recode_regex                                  # codepage conversion and recode_regex
305                                  from_to($l, $code_page, $self->{'encoding'});                                  $l = decode($input_encoding, $l, 1);
306                                  $l =~ s/($recode_regex)/$recode_map->{$1}/g if ($recode_regex && $recode_map);                                  $l =~ s/($recode_regex)/$recode_map->{$1}/g if ($recode_regex && $recode_map);
307    
308                                  # apply regexps                                  # apply regexps
# Line 313  sub open { Line 311  sub open {
311                                          my $c = 0;                                          my $c = 0;
312                                          foreach my $r (@{ $rec_regex->{$f_nr} }) {                                          foreach my $r (@{ $rec_regex->{$f_nr} }) {
313                                                  my $old_l = $l;                                                  my $old_l = $l;
314                                                  eval '$l =~ ' . $r;                                                  $log->logconfess("expected regex in ", dump( $r )) unless defined($r->{regex});
315                                                    eval '$l =~ ' . $r->{regex};
316                                                  if ($old_l ne $l) {                                                  if ($old_l ne $l) {
317                                                          $log->debug("REGEX on $f_nr eval \$l =~ $r\n## old l: [$old_l]\n## new l: [$l]");                                                          my $d = "|$old_l| -> |$l| "; # . $r->{regex};
318                                                            $d .= ' +' . $r->{line} . ' ' . $r->{file} if defined($r->{line});
319                                                            $d .= ' ' . $r->{debug} if defined($r->{debug});
320                                                            $log->debug("MODIFY $d");
321                                                            warn "*** $d\n" if ($debug);
322    
323                                                  }                                                  }
324                                                  $log->error("error applying regex: $r") if ($@);                                                  $log->error("error applying regex: ",dump($r), $@) if $@;
325                                          }                                          }
326                                  }                                  }
327    
328                                  $log->debug("<=- $f_nr ## $l");                                  $log->debug("<=- $f_nr ## |$l|");
329                                    warn "<=- $f_nr ## $l\n" if ($debug);
330                                  return $l;                                  return $l;
331                  });                  });
332    
333                  $log->debug(sub { Dumper($rec) });                  $log->debug(sub { dump($rec) });
334    
335                  if (! $rec) {                  if (! $rec) {
336                          $log->warn("record $pos empty? skipping...");                          $log->warn("record $pos empty? skipping...");
# Line 333  sub open { Line 338  sub open {
338                  }                  }
339    
340                  # store                  # store
341                  if ($self->{low_mem}) {                  if ($self->{save_row}) {
342                          $self->{db}->put($pos, $rec);                          $self->{save_row}->({
343                                    id => $pos,
344                                    row => $rec,
345                            });
346                  } else {                  } else {
347                          $self->{data}->{$pos} = $rec;                          $self->{data}->{$pos} = $rec;
348                  }                  }
# Line 351  sub open { Line 359  sub open {
359                          foreach my $fld (keys %{ $rec }) {                          foreach my $fld (keys %{ $rec }) {
360                                  $self->{_stats}->{fld}->{ $fld }++;                                  $self->{_stats}->{fld}->{ $fld }++;
361    
362                                  $log->logdie("invalid record fild $fld, not ARRAY")                                  #$log->logdie("invalid record fild $fld, not ARRAY")
363                                          unless (ref($rec->{ $fld }) eq 'ARRAY');                                  next unless (ref($rec->{ $fld }) eq 'ARRAY');
364                    
365                                  foreach my $row (@{ $rec->{$fld} }) {                                  foreach my $row (@{ $rec->{$fld} }) {
366    
# Line 383  sub open { Line 391  sub open {
391          $self->{max_pos} = $to_rec;          $self->{max_pos} = $to_rec;
392          $log->debug("max_pos: $to_rec");          $log->debug("max_pos: $to_rec");
393    
         # save for dump  
         $self->{ll_db} = $ll_db;  
   
394          return $size;          return $size;
395  }  }
396    
397    sub input_module { $_[0]->{ll_db} }
398    
399  =head2 fetch  =head2 fetch
400    
401  Fetch next record from database. It will also displays progress bar.  Fetch next record from database. It will also displays progress bar.
# Line 408  sub fetch { Line 415  sub fetch {
415          $log->logconfess("it seems that you didn't load database!") unless ($self->{pos});          $log->logconfess("it seems that you didn't load database!") unless ($self->{pos});
416    
417          if ($self->{pos} == -1) {          if ($self->{pos} == -1) {
418                  $self->{pos} = $self->{offset};                  $self->{pos} = $self->{offset} + 1;
419          } else {          } else {
420                  $self->{pos}++;                  $self->{pos}++;
421          }          }
# Line 425  sub fetch { Line 432  sub fetch {
432    
433          my $rec;          my $rec;
434    
435          if ($self->{low_mem}) {          if ($self->{load_row}) {
436                  $rec = $self->{db}->get($mfn);                  $rec = $self->{load_row}->({ id => $mfn });
437          } else {          } else {
438                  $rec = $self->{data}->{$mfn};                  $rec = $self->{data}->{$mfn};
439          }          }
# Line 481  First record in database has position 1. Line 488  First record in database has position 1.
488    
489  sub seek {  sub seek {
490          my $self = shift;          my $self = shift;
491          my $pos = shift || return;          my $pos = shift;
492    
493          my $log = $self->_get_logger();          my $log = $self->_get_logger();
494    
495            $log->logconfess("called without pos") unless defined($pos);
496    
497          if ($pos < 1) {          if ($pos < 1) {
498                  $log->warn("seek before first record");                  $log->warn("seek before first record");
499                  $pos = 1;                  $pos = 1;
# Line 519  sub stats { Line 528  sub stats {
528    
529          my $out = join("\n",          my $out = join("\n",
530                  map {                  map {
531                          my $f = $_ || die "no field";                          my $f = $_;
532                            die "no field in ", dump( $s->{fld} ) unless defined( $f );
533                          my $v = $s->{fld}->{$f} || die "no s->{fld}->{$f}";                          my $v = $s->{fld}->{$f} || die "no s->{fld}->{$f}";
534                          $max_fld = $v if ($v > $max_fld);                          $max_fld = $v if ($v > $max_fld);
535    
536                          my $o = sprintf("%4s %d ~", $f, $v);                          my $o = sprintf("%4s %d ~", $f, $v);
537    
538                          if (defined($s->{sf}->{$f})) {                          if (defined($s->{sf}->{$f})) {
539                                    my @subfields = keys %{ $s->{sf}->{$f} };
540                                  map {                                  map {
541                                          $o .= sprintf(" %s:%d%s", $_,                                          $o .= sprintf(" %s:%d%s", $_,
542                                                  $s->{sf}->{$f}->{$_}->{count},                                                  $s->{sf}->{$f}->{$_}->{count},
543                                                  $s->{sf}->{$f}->{$_}->{repeatable} ? '*' : '',                                                  $s->{sf}->{$f}->{$_}->{repeatable} ? '*' : '',
544                                          );                                          );
545                                  } sort keys %{ $s->{sf}->{$f} };                                  } (
546                                            # first indicators and other special subfields
547                                            sort( grep { length($_)  > 1 } @subfields ),
548                                            # then subfileds (single char)
549                                            sort( grep { length($_) == 1 } @subfields ),
550                                    );
551                          }                          }
552    
553                          if (my $v_r = $s->{repeatable}->{$f}) {                          if (my $v_r = $s->{repeatable}->{$f}) {
# Line 539  sub stats { Line 555  sub stats {
555                          }                          }
556    
557                          $o;                          $o;
558                  } sort { $a cmp $b } keys %{ $s->{fld} }                  } sort {
559                            if ( $a =~ m/^\d+$/ && $b =~ m/^\d+$/ ) {
560                                    $a <=> $b
561                            } else {
562                                    $a cmp $b
563                            }
564                    } keys %{ $s->{fld} }
565          );          );
566    
567          $log->debug( sub { Dumper($s) } );          $log->debug( sub { dump($s) } );
568    
569            my $path = 'var/stats.yml';
570            YAML::DumpFile( $path, $s );
571            $log->info( 'created ', $path, ' with ', -s $path, ' bytes' );
572    
573          return $out;          return $out;
574  }  }
575    
576  =head2 dump  =head2 dump_ascii
577    
578  Display humanly readable dump of record  Display humanly readable dump of record
579    
580  =cut  =cut
581    
582  sub dump {  sub dump_ascii {
583          my $self = shift;          my $self = shift;
584    
585          return $self->{ll_db}->dump_rec( $self->{pos} );          return unless $self->{ll_db};
586    
587            if ($self->{ll_db}->can('dump_ascii')) {
588                    return $self->{ll_db}->dump_ascii( $self->{pos} );
589            } else {
590                    return dump( $self->{ll_db}->fetch_rec( $self->{pos} ) );
591            }
592  }  }
593    
594  =head2 modify_record_regexps  =head2 _get_regex
595    
596  Generate hash with regexpes to be applied using l<filter>.  Helper function called which create regexps to be execute on code.
597    
598    my $regexpes = $input->modify_record_regexps(    _get_regex( 900, 'regex:[0-9]+' ,'numbers' );
599                  900 => { '^a' => { ' : ' => '^b' } },    _get_regex( 900, '^b', ' : ^b' );
600                  901 => { '*' => { '^b' => ' ; ' } },  
601    );  It supports perl regexps with C<regex:> prefix to from value and has
602    additional logic to skip empty subfields.
603    
604  =cut  =cut
605    
606  sub _get_regex {  sub _get_regex {
607          my ($sf,$from,$to) = @_;          my ($sf,$from,$to) = @_;
608    
609            # protect /
610            $from =~ s!/!\\/!gs;
611            $to =~ s!/!\\/!gs;
612    
613            if ($from =~ m/^regex:(.+)$/) {
614                    $from = $1;
615            } else {
616                    $from = '\Q' . $from . '\E';
617            }
618          if ($sf =~ /^\^/) {          if ($sf =~ /^\^/) {
619                    my $need_subfield_data = '*';   # no
620                    # if from is also subfield, require some data in between
621                    # to correctly skip empty subfields
622                    $need_subfield_data = '+' if ($from =~ m/^\\Q\^/);
623                  return                  return
624                          's/\Q'. $sf .'\E([^\^]*?)\Q'. $from .'\E([^\^]*?)/'. $sf .'$1'. $to .'$2/';                          's/\Q'. $sf .'\E([^\^]' . $need_subfield_data . '?)'. $from .'([^\^]*?)/'. $sf .'$1'. $to .'$2/';
625          } else {          } else {
626                  return                  return
627                          's/\Q'. $from .'\E/'. $to .'/g';                          's/'. $from .'/'. $to .'/g';
628          }          }
629  }  }
630    
631    
632    =head2 modify_record_regexps
633    
634    Generate hash with regexpes to be applied using L<filter>.
635    
636      my $regexpes = $input->modify_record_regexps(
637                    900 => { '^a' => { ' : ' => '^b' } },
638                    901 => { '*' => { '^b' => ' ; ' } },
639      );
640    
641    =cut
642    
643  sub modify_record_regexps {  sub modify_record_regexps {
644          my $self = shift;          my $self = shift;
645          my $modify_record = {@_};          my $modify_record = {@_};
# Line 599  sub modify_record_regexps { Line 657  sub modify_record_regexps {
657                          foreach my $from (keys %{ $modify_record->{$f}->{$sf} }) {                          foreach my $from (keys %{ $modify_record->{$f}->{$sf} }) {
658                                  my $to = $modify_record->{$f}->{$sf}->{$from};                                  my $to = $modify_record->{$f}->{$sf}->{$from};
659                                  #die "no field?" unless defined($to);                                  #die "no field?" unless defined($to);
660                                  $log->debug("transform: |$from| -> |$to|");                                  my $d = "|$from| -> |$to|";
661                                    $log->debug("transform: $d");
662    
663                                  my $regex = _get_regex($sf,$from,$to);                                  my $regex = _get_regex($sf,$from,$to);
664                                  push @{ $regexpes->{$f} }, $regex;                                  push @{ $regexpes->{$f} }, { regex => $regex, debug => $d };
665                                  $log->debug("regex: $regex");                                  $log->debug("regex: $regex");
666                          }                          }
667                  }                  }
# Line 613  sub modify_record_regexps { Line 672  sub modify_record_regexps {
672    
673  =head2 modify_file_regexps  =head2 modify_file_regexps
674    
675  Generate hash with regexpes to be applied using l<filter> from  Generate hash with regexpes to be applied using L<filter> from
676  pseudo hash/yaml format for regex mappings.  pseudo hash/yaml format for regex mappings.
677    
678  It should be obvious:  It should be obvious:
# Line 663  sub modify_file_regexps { Line 722  sub modify_file_regexps {
722                          $log->debug("transform: |$from| -> |$to|");                          $log->debug("transform: |$from| -> |$to|");
723    
724                          my $regex = _get_regex($sf,$from,$to);                          my $regex = _get_regex($sf,$from,$to);
725                          push @{ $regexpes->{$f} }, $regex;                          push @{ $regexpes->{$f} }, {
726                                    regex => $regex,
727                                    file => $modify_path,
728                                    line => $.,
729                            };
730                          $log->debug("regex: $regex");                          $log->debug("regex: $regex");
731                    } else {
732                            die "can't parse: $_";
733                  }                  }
734          }          }
735    
736          return $regexpes;          return $regexpes;
737  }  }
738    
 =head1 MEMORY USAGE  
   
 C<low_mem> options is double-edged sword. If enabled, WebPAC  
 will run on memory constraint machines (which doesn't have enough  
 physical RAM to create memory structure for whole source database).  
   
 If your machine has 512Mb or more of RAM and database is around 10000 records,  
 memory shouldn't be an issue. If you don't have enough physical RAM, you  
 might consider using virtual memory (if your operating system is handling it  
 well, like on FreeBSD or Linux) instead of dropping to L<DBM::Deep> to handle  
 parsed structure of ISIS database (this is what C<low_mem> option does).  
   
 Hitting swap at end of reading source database is probably o.k. However,  
 hitting swap before 90% will dramatically decrease performance and you will  
 be better off with C<low_mem> and using rest of availble memory for  
 operating system disk cache (Linux is particuallary good about this).  
 However, every access to database record will require disk access, so  
 generation phase will be slower 10-100 times.  
   
 Parsed structures are essential - you just have option to trade RAM memory  
 (which is fast) for disk space (which is slow). Be sure to have planty of  
 disk space if you are using C<low_mem> and thus L<DBM::Deep>.  
   
 However, when WebPAC is running on desktop machines (or laptops :-), it's  
 highly undesireable for system to start swapping. Using C<low_mem> option can  
 reduce WecPAC memory usage to around 64Mb for same database with lookup  
 fields and sorted indexes which stay in RAM. Performance will suffer, but  
 memory usage will really be minimal. It might be also more confortable to  
 run WebPAC reniced on those machines.  
   
   
739  =head1 AUTHOR  =head1 AUTHOR
740    
741  Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>  Dobrica Pavlinusic, C<< <dpavlin@rot13.org> >>

Legend:
Removed from v.760  
changed lines
  Added in v.1304

  ViewVC Help
Powered by ViewVC 1.1.26