/[webpac]/trunk2/lib/WebPAC.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 /trunk2/lib/WebPAC.pm

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

revision 418 by dpavlin, Thu Sep 9 18:08:38 2004 UTC revision 609 by dpavlin, Fri Dec 31 02:19:24 2004 UTC
# Line 9  use Config::IniFiles; Line 9  use Config::IniFiles;
9  use XML::Simple;  use XML::Simple;
10  use Template;  use Template;
11  use Log::Log4perl qw(get_logger :levels);  use Log::Log4perl qw(get_logger :levels);
12    use Time::HiRes qw(time);
13    
14  use Data::Dumper;  use Data::Dumper;
15    
# Line 29  This module implements methods used by W Line 30  This module implements methods used by W
30    
31  =head2 new  =head2 new
32    
33  This will create new instance of WebPAC using configuration specified by C<config_file>.  Create new instance of WebPAC using configuration specified by C<config_file>.
34    
35   my $webpac = new WebPAC(   my $webpac = new WebPAC(
36          config_file => 'name.conf',          config_file => 'name.conf',
37          [code_page => 'ISO-8859-2',]          code_page => 'ISO-8859-2',
38            low_mem => 1,
39            filter => {
40                    'lower' => sub { lc($_[0]) },
41            },
42   );   );
43    
44  Default C<code_page> is C<ISO-8859-2>.  Default C<code_page> is C<ISO-8859-2>.
45    
46  It will also read configuration files  Default is not to use C<low_mem> options (see L<MEMORY USAGE> below).
47    
48    There is optinal parametar C<filter> which specify different filters which
49    can be applied using C<filter{name}> notation.
50    Same filters can be used in Template Toolkit files.
51    
52    This method will also read configuration files
53  C<global.conf> (used by indexer and Web font-end)  C<global.conf> (used by indexer and Web font-end)
54  and configuration file specified by C<config_file>  and configuration file specified by C<config_file>
55  which describes databases to be indexed.  which describes databases to be indexed.
# Line 59  sub new { Line 70  sub new {
70          my $self = {@_};          my $self = {@_};
71          bless($self, $class);          bless($self, $class);
72    
73            $self->{'start_t'} = time();
74    
75          my $log_file = $self->{'log'} || "log.conf";          my $log_file = $self->{'log'} || "log.conf";
76          Log::Log4perl->init($log_file);          Log::Log4perl->init($log_file);
77    
# Line 100  sub new { Line 113  sub new {
113          # create Template toolkit instance          # create Template toolkit instance
114          $self->{'tt'} = Template->new(          $self->{'tt'} = Template->new(
115                  INCLUDE_PATH => ($self->{'global_config_file'}->{'output_template'} || './output_template'),                  INCLUDE_PATH => ($self->{'global_config_file'}->{'output_template'} || './output_template'),
116  #               FILTERS => {                  FILTERS => $self->{'filter'},
 #                       'foo' => \&foo_filter,  
 #               },  
117                  EVAL_PERL => 1,                  EVAL_PERL => 1,
118          );          );
119    
120            # running with low_mem flag? well, use DBM::Deep then.
121            if ($self->{'low_mem'}) {
122                    $log->info("running with low_mem which impacts performance (<32 Mb memory usage)");
123    
124                    my $db_file = "data.db";
125    
126                    if (-e $db_file) {
127                            unlink $db_file or $log->logdie("can't remove '$db_file' from last run");
128                            $log->debug("removed '$db_file' from last run");
129                    }
130    
131                    require DBM::Deep;
132    
133                    my $db = new DBM::Deep $db_file;
134    
135                    $log->logdie("DBM::Deep error: $!") unless ($db);
136    
137                    if ($db->error()) {
138                            $log->logdie("can't open '$db_file' under low_mem: ",$db->error());
139                    } else {
140                            $log->debug("using file '$db_file' for DBM::Deep");
141                    }
142    
143                    $self->{'db'} = $db;
144            }
145    
146            $log->debug("filters defined: ",Dumper($self->{'filter'}));
147    
148          return $self;          return $self;
149  }  }
150    
151  =head2 open_isis  =head2 open_isis
152    
153  Open CDS/ISIS database using OpenIsis module and read all records to memory.  Open CDS/ISIS, WinISIS or IsisMarc database using IsisDB or OpenIsis module
154    and read all records to memory.
155    
156   $webpac->open_isis(   $webpac->open_isis(
157          filename => '/data/ISIS/ISIS',          filename => '/data/ISIS/ISIS',
158          code_page => '852',          code_page => '852',
159          limit_mfn => '500',          limit_mfn => 500,
160            start_mfn => 6000,
161          lookup => [ ... ],          lookup => [ ... ],
162   );   );
163    
164  By default, ISIS code page is assumed to be C<852>.  By default, ISIS code page is assumed to be C<852>.
165    
166    If optional parametar C<start_mfn> is set, this will be first MFN to read
167    from database (so you can skip beginning of your database if you need to).
168    
169  If optional parametar C<limit_mfn> is set, it will read just 500 records  If optional parametar C<limit_mfn> is set, it will read just 500 records
170  from database in example above.  from database in example above.
171    
# Line 149  sub open_isis { Line 193  sub open_isis {
193          $log->logcroak("need filename") if (! $arg->{'filename'});          $log->logcroak("need filename") if (! $arg->{'filename'});
194          my $code_page = $arg->{'code_page'} || '852';          my $code_page = $arg->{'code_page'} || '852';
195    
196          use OpenIsis;          $log->logdie("can't find database ",$arg->{'filename'}) unless (glob($arg->{'filename'}.'.*'));
197    
198            # store data in object
199            $self->{'isis_filename'} = $arg->{'filename'};
200            $self->{'isis_code_page'} = $code_page;
201    
202          #$self->{'isis_code_page'} = $code_page;          #$self->{'isis_code_page'} = $code_page;
203    
# Line 157  sub open_isis { Line 205  sub open_isis {
205          my $cp = Text::Iconv->new($code_page,$self->{'code_page'});          my $cp = Text::Iconv->new($code_page,$self->{'code_page'});
206    
207          $log->info("reading ISIS database '",$arg->{'filename'},"'");          $log->info("reading ISIS database '",$arg->{'filename'},"'");
208            $log->debug("isis code page: $code_page");
209    
210            my $use_openisis = 1;
211    
212            eval { use IsisDB 0.06; };
213            $use_openisis = 0 unless ($@);
214    
215            my ($isis_db,$maxmfn);
216    
217          my $isis_db = OpenIsis::open($arg->{'filename'});          if ($use_openisis) {
218                    use OpenIsis;
219                    $isis_db = OpenIsis::open($arg->{'filename'});
220                    $maxmfn = OpenIsis::maxRowid( $isis_db ) || 1;
221            } else {
222                    $isis_db = new IsisDB(
223                            isisdb => $arg->{'filename'},
224                            include_deleted => 1,
225                            hash_filter => sub {
226                                    my $l = shift || return;
227                                    $l = $cp->convert($l);
228                                    return $l;
229                            },
230                    );
231                    $maxmfn = $isis_db->{'maxmfn'};
232            }
233    
234    
235            my $startmfn = 1;
236    
237            if (my $s = $self->{'start_mfn'}) {
238                    $log->info("skipping to MFN $s");
239                    $startmfn = $s;
240            } else {
241                    $self->{'start_mfn'} = $startmfn;
242            }
243    
244          my $maxmfn = OpenIsis::maxRowid( $isis_db ) || 1;          $maxmfn = $startmfn + $self->{limit_mfn} if ($self->{limit_mfn});
245    
246          $maxmfn = $self->{limit_mfn} if ($self->{limit_mfn});          $log->info("processing ",($maxmfn-$startmfn)." records using ",( $use_openisis ? 'OpenIsis' : 'IsisDB'));
247    
         $log->info("processing $maxmfn records...");  
248    
249          # read database          # read database
250          for (my $mfn = 1; $mfn <= $maxmfn; $mfn++) {          for (my $mfn = $startmfn; $mfn <= $maxmfn; $mfn++) {
251    
252    
253                  $log->debug("mfn: $mfn\n");                  $log->debug("mfn: $mfn\n");
254    
255                  # read record                  my $rec;
256                  my $row = OpenIsis::read( $isis_db, $mfn );  
257                  foreach my $k (keys %{$row}) {                  if ($use_openisis) {
258                          if ($k ne "mfn") {  
259                                  foreach my $l (@{$row->{$k}}) {                          # read record using OpenIsis
260                                          $l = $cp->convert($l);                          my $row = OpenIsis::read( $isis_db, $mfn );
261                                          # has subfields?                          foreach my $k (keys %{$row}) {
262                                          my $val;                                  if ($k ne "mfn") {
263                                          if ($l =~ m/\^/) {                                          foreach my $l (@{$row->{$k}}) {
264                                                  foreach my $t (split(/\^/,$l)) {                                                  $l = $cp->convert($l);
265                                                          next if (! $t);                                                  # has subfields?
266                                                          $val->{substr($t,0,1)} = substr($t,1);                                                  my $val;
267                                                    if ($l =~ m/\^/) {
268                                                            foreach my $t (split(/\^/,$l)) {
269                                                                    next if (! $t);
270                                                                    $val->{substr($t,0,1)} = substr($t,1);
271                                                            }
272                                                    } else {
273                                                            $val = $l;
274                                                  }                                                  }
                                         } else {  
                                                 $val = $l;  
                                         }  
275    
276                                          push @{$self->{'data'}->{$mfn}->{$k}}, $val;                                                  push @{$rec->{$k}}, $val;
277                                            }
278                                    } else {
279                                            push @{$rec->{'000'}}, $mfn;
280                                  }                                  }
                         } else {  
                                 push @{$self->{'data'}->{$mfn}->{'000'}}, $mfn;  
281                          }                          }
282    
283                    } else {
284                            $rec = $isis_db->to_hash($mfn);
285                    }
286    
287                    $log->confess("record $mfn empty?") unless ($rec);
288    
289                    # store
290                    if ($self->{'low_mem'}) {
291                            $self->{'db'}->put($mfn, $rec);
292                    } else {
293                            $self->{'data'}->{$mfn} = $rec;
294                  }                  }
295    
296                  # create lookup                  # create lookup
                 my $rec = $self->{'data'}->{$mfn} || $log->confess("record $mfn empty?");  
297                  $self->create_lookup($rec, @{$arg->{'lookup'}});                  $self->create_lookup($rec, @{$arg->{'lookup'}});
298    
299                  $self->progress_bar($mfn,$maxmfn);                  $self->progress_bar($mfn,$maxmfn);
300    
301          }          }
302    
303          $self->{'current_mfn'} = 1;          $self->{'current_mfn'} = -1;
304          $self->{'last_pcnt'} = 0;          $self->{'last_pcnt'} = 0;
305    
306          $log->debug("max mfn: $maxmfn");          $log->debug("max mfn: $maxmfn");
# Line 228  sub fetch_rec { Line 323  sub fetch_rec {
323    
324          my $log = $self->_get_logger();          my $log = $self->_get_logger();
325    
326          my $mfn = $self->{'current_mfn'}++ || $log->logconfess("it seems that you didn't load database!");          $log->logconfess("it seems that you didn't load database!") unless ($self->{'current_mfn'});
327    
328            if ($self->{'current_mfn'} == -1) {
329                    $self->{'current_mfn'} = $self->{'start_mfn'};
330            } else {
331                    $self->{'current_mfn'}++;
332            }
333    
334            my $mfn = $self->{'current_mfn'};
335    
336          if ($mfn > $self->{'max_mfn'}) {          if ($mfn > $self->{'max_mfn'}) {
337                  $self->{'current_mfn'} = $self->{'max_mfn'};                  $self->{'current_mfn'} = $self->{'max_mfn'};
# Line 238  sub fetch_rec { Line 341  sub fetch_rec {
341    
342          $self->progress_bar($mfn,$self->{'max_mfn'});          $self->progress_bar($mfn,$self->{'max_mfn'});
343    
344          return $self->{'data'}->{$mfn};          if ($self->{'low_mem'}) {
345                    return $self->{'db'}->get($mfn);
346            } else {
347                    return $self->{'data'}->{$mfn};
348            }
349    }
350    
351    =head2 mfn
352    
353    Returns current record number (MFN).
354    
355     print $webpac->mfn;
356    
357    =cut
358    
359    sub mfn {
360            my $self = shift;
361            return $self->{'current_mfn'};
362  }  }
363    
364  =head2 progress_bar  =head2 progress_bar
# Line 266  sub progress_bar { Line 386  sub progress_bar {
386    
387          $self->{'last_pcnt'} ||= 1;          $self->{'last_pcnt'} ||= 1;
388    
389          $self->{'last_pcnt'} = $curr if ($curr < $self->{'last_pcnt'});          my $p = int($curr * 100 / $max) || 1;
390    
391            # reset on re-run
392            if ($p < $self->{'last_pcnt'}) {
393                    $self->{'last_pcnt'} = $p;
394                    $self->{'start_t'} = time();
395            }
396    
         my $p = int($curr * 100 / $max);  
397          if ($p != $self->{'last_pcnt'}) {          if ($p != $self->{'last_pcnt'}) {
398                  printf STDERR ("%5d / %5d [%-51s] %-2d %% \r",$curr,$max,"=" x ($p/2).">", $p );  
399                    my $t = time();
400                    my $rate = ($curr / ($t - $self->{'start_t'} || 1));
401                    my $eta = ($max-$curr) / ($rate || 1);
402                    printf STDERR ("%5d [%-38s] %-5d %0.1f/s %s\r",$curr,"=" x ($p/3)."$p%>", $max, $rate, $self->fmt_time($eta));
403                  $self->{'last_pcnt'} = $p;                  $self->{'last_pcnt'} = $p;
404                    $self->{'last_t'} = time();
405                    $self->{'last_curr'} = $curr;
406          }          }
407          print STDERR "\n" if ($p == 100);          print STDERR "\n" if ($p == 100);
408  }  }
409    
410    =head2 fmt_time
411    
412    Format time (in seconds) for display.
413    
414     print $webpac->fmt_time(time());
415    
416    This method is called by L<progress_bar> to display remaining time.
417    
418    =cut
419    
420    sub fmt_time {
421            my $self = shift;
422    
423            my $t = shift || 0;
424            my $out = "";
425    
426            my ($ss,$mm,$hh) = gmtime($t);
427            $out .= "${hh}h" if ($hh);
428            $out .= sprintf("%02d:%02d", $mm,$ss);
429            $out .= "  " if ($hh == 0);
430            return $out;
431    }
432    
433  =head2 open_import_xml  =head2 open_import_xml
434    
435  Read file from C<import_xml/> directory and parse it.  Read file from C<import_xml/> directory and parse it.
# Line 438  sub fill_in { Line 592  sub fill_in {
592          # iteration (for repeatable fields)          # iteration (for repeatable fields)
593          my $i = shift || 0;          my $i = shift || 0;
594    
595            $log->logdie("infitite loop in format $format") if ($i > ($self->{'max_mfn'} || 9999));
596    
597          # FIXME remove for speedup?          # FIXME remove for speedup?
598          $log->logconfess("need HASH as first argument!") if ($rec !~ /HASH/o);          $log->logconfess("need HASH as first argument!") if ($rec !~ /HASH/o);
599    
# Line 451  sub fill_in { Line 607  sub fill_in {
607          # remove eval{...} from beginning          # remove eval{...} from beginning
608          $eval_code = $1 if ($format =~ s/^eval{([^}]+)}//s);          $eval_code = $1 if ($format =~ s/^eval{([^}]+)}//s);
609    
610            my $filter_name;
611            # remove filter{...} from beginning
612            $filter_name = $1 if ($format =~ s/^filter{([^}]+)}//s);
613    
614          # do actual replacement of placeholders          # do actual replacement of placeholders
615            # repeatable fields
616          $format =~ s/v(\d+)(?:\^(\w))?/$self->get_data(\$rec,$1,$2,$i,\$found)/ges;          $format =~ s/v(\d+)(?:\^(\w))?/$self->get_data(\$rec,$1,$2,$i,\$found)/ges;
617            # non-repeatable fields
618            $format =~ s/s(\d+)(?:\^(\w))?/$self->get_data(\$rec,$1,$2,0,\$found)/ges;
619    
620          if ($found) {          if ($found) {
621                  $log->debug("format: $format");                  $log->debug("format: $format");
# Line 460  sub fill_in { Line 623  sub fill_in {
623                          my $eval = $self->fill_in($rec,$eval_code,$i);                          my $eval = $self->fill_in($rec,$eval_code,$i);
624                          return if (! $self->_eval($eval));                          return if (! $self->_eval($eval));
625                  }                  }
626                    if ($filter_name && $self->{'filter'}->{$filter_name}) {
627                            $log->debug("filter '$filter_name' for $format");
628                            $format = $self->{'filter'}->{$filter_name}->($format);
629                            return unless(defined($format));
630                            $log->debug("filter result: $format");
631                    }
632                  # do we have lookups?                  # do we have lookups?
633                  if ($format =~ /$LOOKUP_REGEX/o) {                  if ($format =~ /$LOOKUP_REGEX/o) {
634                          $log->debug("format '$format' has lookup");                          $log->debug("format '$format' has lookup");
# Line 552  sub parse { Line 721  sub parse {
721          # remove eval{...} from beginning          # remove eval{...} from beginning
722          $eval_code = $1 if ($format =~ s/^eval{([^}]+)}//s);          $eval_code = $1 if ($format =~ s/^eval{([^}]+)}//s);
723    
724            my $filter_name;
725            # remove filter{...} from beginning
726            $filter_name = $1 if ($format =~ s/^filter{([^}]+)}//s);
727    
728          my $prefix;          my $prefix;
729          my $all_found=0;          my $all_found=0;
730    
731          while ($format =~ s/^(.*?)v(\d+)(?:\^(\w))?//s) {          while ($format =~ s/^(.*?)(v|s)(\d+)(?:\^(\w))?//s) {
732    
733                  my $del = $1 || '';                  my $del = $1 || '';
734                  $prefix ||= $del if ($all_found == 0);                  $prefix ||= $del if ($all_found == 0);
735    
736                    # repeatable index
737                    my $r = $i;
738                    $r = 0 if (lc("$2") eq 's');
739    
740                  my $found = 0;                  my $found = 0;
741                  my $tmp = $self->get_data(\$rec,$2,$3,$i,\$found);                  my $tmp = $self->get_data(\$rec,$3,$4,$r,\$found);
742    
743                  if ($found) {                  if ($found) {
744                          push @out, $del;                          push @out, $del;
# Line 585  sub parse { Line 762  sub parse {
762          }          }
763    
764          if ($eval_code) {          if ($eval_code) {
765                  my $eval = $self->fill_in($rec,$eval_code,$i);                  my $eval = $self->fill_in($rec,$eval_code,$i) || return;
766                  $log->debug("about to eval{",$eval,"} format: $out");                  $log->debug("about to eval{$eval} format: $out");
767                  return if (! $self->_eval($eval));                  return if (! $self->_eval($eval));
768          }          }
769            
770            if ($filter_name && $self->{'filter'}->{$filter_name}) {
771                    $log->debug("about to filter{$filter_name} format: $out");
772                    $out = $self->{'filter'}->{$filter_name}->($out);
773                    return unless(defined($out));
774                    $log->debug("filter result: $out");
775            }
776    
777          return $out;          return $out;
778  }  }
# Line 655  sub fill_in_to_arr { Line 839  sub fill_in_to_arr {
839          return @arr;          return @arr;
840  }  }
841    
842    =head2 sort_arr
843    
844    Sort array ignoring case and html in data
845    
846     my @sorted = $webpac->sort_arr(@unsorted);
847    
848    =cut
849    
850    sub sort_arr {
851            my $self = shift;
852    
853            my $log = $self->_get_logger();
854    
855            # FIXME add Schwartzian Transformation?
856    
857            my @sorted = sort {
858                    $a =~ s#<[^>]+/*>##;
859                    $b =~ s#<[^>]+/*>##;
860                    lc($b) cmp lc($a)
861            } @_;
862            $log->debug("sorted values: ",sub { join(", ",@sorted) });
863    
864            return @sorted;
865    }
866    
867    
868  =head2 data_structure  =head2 data_structure
869    
# Line 711  sub data_structure { Line 920  sub data_structure {
920                          }                          }
921                          next if (! @v);                          next if (! @v);
922    
923                            if ($tag->{'sort'}) {
924                                    @v = $self->sort_arr(@v);
925                            }
926    
927                          # use format?                          # use format?
928                          if ($tag->{'format_name'}) {                          if ($tag->{'format_name'}) {
929                                  @v = map { $self->apply_format($tag->{'format_name'},$tag->{'format_delimiter'},$_) } @v;                                  @v = map { $self->apply_format($tag->{'format_name'},$tag->{'format_delimiter'},$_) } @v;
# Line 725  sub data_structure { Line 938  sub data_structure {
938                                  next; # don't return headline in data_structure!                                  next; # don't return headline in data_structure!
939                          }                          }
940    
941                          # does tag have type?                          # delimiter will join repeatable fields
942                          if ($tag->{'type'}) {                          if ($tag->{'delimiter'}) {
943                                  push @{$row->{$tag->{'type'}}}, @v;                                  @v = ( join($tag->{'delimiter'}, @v) );
944                          } else {                          }
945                                  push @{$row->{'display'}}, @v;  
946                                  push @{$row->{'swish'}}, @v;                          # default types
947                            my @types = qw(display swish);
948                            # override by type attribute
949                            @types = ( $tag->{'type'} ) if ($tag->{'type'});
950    
951                            foreach my $type (@types) {
952                                    # append to previous line?
953                                    $log->debug("type: $type ",sub { join(" ",@v) }, $row->{'append'} || 'no append');
954                                    if ($tag->{'append'}) {
955    
956                                            # I will delimit appended part with
957                                            # delimiter (or ,)
958                                            my $d = $tag->{'delimiter'};
959                                            # default delimiter
960                                            $d ||= " ";
961    
962                                            my $last = pop @{$row->{$type}};
963                                            $d = "" if (! $last);
964                                            $last .= $d . join($d, @v);
965                                            push @{$row->{$type}}, $last;
966    
967                                    } else {
968                                            push @{$row->{$type}}, @v;
969                                    }
970                          }                          }
971    
972    
# Line 743  sub data_structure { Line 979  sub data_structure {
979                          my $name = $self->{'import_xml'}->{'indexer'}->{$field}->{'name'};                          my $name = $self->{'import_xml'}->{'indexer'}->{$field}->{'name'};
980                          $row->{'name'} = $name ? $self->_x($name) : $field;                          $row->{'name'} = $name ? $self->_x($name) : $field;
981    
982                            # post-sort all values in field
983                            if ($self->{'import_xml'}->{'indexer'}->{$field}->{'sort'}) {
984                                    $log->warn("sort at field tag not implemented");
985                            }
986    
987                          push @ds, $row;                          push @ds, $row;
988    
989                          $log->debug("row $field: ",sub { Dumper($row) });                          $log->debug("row $field: ",sub { Dumper($row) });
# Line 803  sub output_file { Line 1044  sub output_file {
1044    
1045          my $log = $self->_get_logger();          my $log = $self->_get_logger();
1046    
1047          $log->logconfess("need file name") if (! $args->{'file'});          my $file = $args->{'file'} || $log->logconfess("need file name");
1048    
1049          $log->debug("creating file ",$args->{'file'});          $log->debug("creating file ",$file);
1050    
1051          open(my $fh, ">", $args->{'file'}) || $log->logdie("can't open output file '$self->{'file'}': $!");          open(my $fh, ">", $file) || $log->logdie("can't open output file '$file': $!");
1052          print $fh $self->output(          print $fh $self->output(
1053                  template => $args->{'template'},                  template => $args->{'template'},
1054                  data => $args->{'data'},                  data => $args->{'data'},
# Line 888  sub _eval { Line 1129  sub _eval {
1129    
1130          $log->debug("eval: ",$code," [",$ret,"]");          $log->debug("eval: ",$code," [",$ret,"]");
1131    
1132          return $ret || 0;          return $ret || undef;
1133  }  }
1134    
1135  =head2 _sort_by_order  =head2 _sort_by_order
# Line 958  B<This is different from normal Log4perl Line 1199  B<This is different from normal Log4perl
1199  also use method names, and not only classes (which are just few)  also use method names, and not only classes (which are just few)
1200  to filter logging.  to filter logging.
1201    
1202    
1203    =head1 MEMORY USAGE
1204    
1205    C<low_mem> options is double-edged sword. If enabled, WebPAC
1206    will run on memory constraint machines (which doesn't have enough
1207    physical RAM to create memory structure for whole source database).
1208    
1209    If your machine has 512Mb or more of RAM and database is around 10000 records,
1210    memory shouldn't be an issue. If you don't have enough physical RAM, you
1211    might consider using virtual memory (if your operating system is handling it
1212    well, like on FreeBSD or Linux) instead of dropping to L<DBD::Deep> to handle
1213    parsed structure of ISIS database (this is what C<low_mem> option does).
1214    
1215    Hitting swap at end of reading source database is probably o.k. However,
1216    hitting swap before 90% will dramatically decrease performance and you will
1217    be better off with C<low_mem> and using rest of availble memory for
1218    operating system disk cache (Linux is particuallary good about this).
1219    However, every access to database record will require disk access, so
1220    generation phase will be slower 10-100 times.
1221    
1222    Parsed structures are essential - you just have option to trade RAM memory
1223    (which is fast) for disk space (which is slow). Be sure to have planty of
1224    disk space if you are using C<low_mem> and thus L<DBD::Deep>.
1225    
1226    However, when WebPAC is running on desktop machines (or laptops :-), it's
1227    highly undesireable for system to start swapping. Using C<low_mem> option can
1228    reduce WecPAC memory usage to around 64Mb for same database with lookup
1229    fields and sorted indexes which stay in RAM. Performance will suffer, but
1230    memory usage will really be minimal. It might be also more confortable to
1231    run WebPAC reniced on those machines.
1232    
1233  =cut  =cut
1234    
1235  1;  1;

Legend:
Removed from v.418  
changed lines
  Added in v.609

  ViewVC Help
Powered by ViewVC 1.1.26