1 #!/usr/local/bin/perl -w
4 use lib "__INSTALLDIR__/lib";
11 use Time::HiRes qw/time/;
13 use POSIX qw/strftime/;
15 use constant BPC_FTYPE_DIR => 5;
22 my $pidfile = new File::Pid;
24 if (my $pid = $pidfile->running ) {
25 die "$0 already running: $pid\n";
26 } elsif ($pidfile->pid ne $$) {
28 $pidfile = new File::Pid;
31 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
33 my $t_fmt = '%Y-%m-%d %H:%M:%S';
36 my $bpc = BackupPC::Lib->new || die;
37 my %Conf = $bpc->Conf();
38 my $TopDir = $bpc->TopDir();
41 my $dsn = $Conf{SearchDSN} || die "Need SearchDSN in config.pl\n";
42 my $user = $Conf{SearchUser} || '';
43 my $index_path = $Conf{HyperEstraierIndex};
45 my $dbh = DBI->connect($dsn, $user, "", { RaiseError => 1, AutoCommit => 0 });
49 if ( !getopts("cdm:v:i", \%opt ) ) {
51 usage: $0 [-c|-d] [-m num] [-v|-v level] [-i]
54 -c create database on first use
55 -d delete database before import
56 -m num import just num increments for one host
57 -v num set verbosity (debug) level (default $debug)
58 -i update HyperEstraier full text index
64 print "Debug level at $opt{v}\n";
71 my $t = shift || return;
73 my ($ss,$mm,$hh) = gmtime($t);
74 $out .= "${hh}h" if ($hh);
75 $out .= sprintf("%02d:%02d", $mm,$ss);
80 return strftime($t_fmt,localtime());
88 print curr_time," updating HyperEstraier: files";
92 my $sth = $dbh->prepare(qq{
97 -- shares.share AS sharename,
98 files.backupnum AS backupnum,
99 -- files.name AS filename,
100 files.path AS filepath,
102 files.type AS filetype,
104 files.shareid AS shareid,
105 backups.date AS backup_date
107 INNER JOIN shares ON files.shareID=shares.ID
108 INNER JOIN hosts ON hosts.ID = shares.hostID
109 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
113 my $results = $sth->rows;
115 my $dot = int($results / 15);
117 print " $results ($dot/#)";
120 my $t = shift || return;
121 my $iso = BackupPC::Lib::timeStamp($t);
127 my $max = int($results / $dot);
129 $index_path = $TopDir . '/' . $index_path;
130 $index_path =~ s#//#/#g;
132 print " index $index_path...";
134 my $db = HyperEstraier::Database->new();
135 $db->open($index_path, $HyperEstraier::Database::DBWRITER | $HyperEstraier::Database::DBCREAT);
138 while (my $row = $sth->fetchrow_hashref()) {
140 # create a document object
141 my $doc = HyperEstraier::Document->new;
143 # add attributes to the document object
144 $doc->add_attr('@uri', 'file:///' . $row->{'fid'});
146 foreach my $c (@{ $sth->{NAME} }) {
147 $doc->add_attr($c, $row->{$c}) if ($row->{$c});
150 #$doc->add_attr('@cdate', fmt_date($row->{'date'}));
152 # add the body text to the document object
153 my $path = $row->{'filepath'};
154 $doc->add_text($path);
155 $path =~ s/(.)/$1 /g;
156 $doc->add_hidden_text($path);
158 print STDERR $doc->dump_draft,"\n" if ($debug > 1);
160 # register the document object to the database
161 $db->put_doc($doc, $HyperEstraier::Database::PDCLEAN);
164 if ($i % $dot == 0) {
176 my $dur = (time() - $t) || 1;
177 printf(" [%.2f/s dur: %s]\n",
185 ###################################create tables############################3
189 my $index = shift || return;
190 my ($table,$col,$unique) = split(/_/, $index);
193 $dbh->do(qq{ create $unique index $index on $table($col) });
196 print "creating tables...\n";
200 ID SERIAL PRIMARY KEY,
201 name VARCHAR(30) NOT NULL,
207 create table shares (
208 ID SERIAL PRIMARY KEY,
209 hostID INTEGER NOT NULL references hosts(id),
210 name VARCHAR(30) NOT NULL,
211 share VARCHAR(200) NOT NULL,
212 localpath VARCHAR(200)
217 create table backups (
218 hostID INTEGER NOT NULL references hosts(id),
219 num INTEGER NOT NULL,
220 date integer NOT NULL,
221 type CHAR(4) not null,
222 shareID integer not null references shares(id),
223 size integer not null,
224 PRIMARY KEY(hostID, num, shareID)
228 #do_index('backups_hostid,num_unique');
232 ID SERIAL PRIMARY KEY,
233 num INTEGER NOT NULL,
234 name VARCHAR(255) NOT NULL,
241 ID SERIAL PRIMARY KEY,
242 shareID INTEGER NOT NULL references shares(id),
243 backupNum INTEGER NOT NULL,
244 name VARCHAR(255) NOT NULL,
245 path VARCHAR(255) NOT NULL,
246 date integer NOT NULL,
247 type INTEGER NOT NULL,
248 size INTEGER NOT NULL,
249 dvdid INTEGER references dvds(id)
253 print "creating indexes:";
255 foreach my $index (qw(
278 foreach my $table (qw(files dvds backups shares hosts)) {
280 $dbh->do(qq{ DELETE FROM $table });
287 #################################INSERT VALUES#############################
290 $hosts = $bpc->HostInfoRead();
296 $sth->{insert_hosts} = $dbh->prepare(qq{
297 INSERT INTO hosts (name, IP) VALUES (?,?)
300 $sth->{hosts_by_name} = $dbh->prepare(qq{
301 SELECT ID FROM hosts WHERE name=?
304 $sth->{backups_count} = $dbh->prepare(qq{
307 WHERE hostID=? AND num=? AND shareid=?
310 $sth->{insert_backups} = $dbh->prepare(qq{
311 INSERT INTO backups (hostID, num, date, type, shareid, size)
315 $sth->{insert_files} = $dbh->prepare(qq{
317 (shareID, backupNum, name, path, date, type, size)
318 VALUES (?,?,?,?,?,?,?)
321 foreach my $host_key (keys %{$hosts}) {
323 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
325 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
327 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
328 $sth->{insert_hosts}->execute(
329 $hosts->{$host_key}->{'host'},
330 $hosts->{$host_key}->{'ip'}
333 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
336 print "host ".$hosts->{$host_key}->{'host'}.": ";
338 # get backups for a host
339 my @backups = $bpc->BackupInfoRead($hostname);
340 my $incs = scalar @backups;
341 print "$incs increments\n";
346 foreach my $backup (@backups) {
349 last if ($opt{m} && $inc_nr > $opt{m});
351 my $backupNum = $backup->{'num'};
352 my @backupShares = ();
354 printf("%-10s %2d/%-2d #%-2d %s %5s/%5s files (date: %s dur: %s)\n",
355 $hosts->{$host_key}->{'host'},
356 $inc_nr, $incs, $backupNum,
357 $backup->{type} || '?',
358 $backup->{nFilesNew} || '?', $backup->{nFiles} || '?',
359 strftime($t_fmt,localtime($backup->{startTime})),
360 fmt_time($backup->{endTime} - $backup->{startTime})
363 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
364 foreach my $share ($files->shareList($backupNum)) {
368 $shareID = getShareID($share, $hostID, $hostname);
370 $sth->{backups_count}->execute($hostID, $backupNum, $shareID);
371 my ($count) = $sth->{backups_count}->fetchrow_array();
372 # skip if allready in database!
373 next if ($count > 0);
376 print curr_time," ", $share;
378 my ($f, $nf, $d, $nd, $size) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
380 $sth->{insert_backups}->execute(
383 $backup->{'endTime'},
392 my $dur = (time() - $t) || 1;
393 printf(" %d/%d files %d/%d dirs %0.2f MB [%.2f/s dur: %s]\n",
395 ($size / 1024 / 1024),
407 print "total duration: ",fmt_time(time() - $start_t),"\n";
413 my ($share, $hostID, $hostname) = @_;
415 $sth->{share_id} ||= $dbh->prepare(qq{
416 SELECT ID FROM shares WHERE hostID=? AND name=?
419 $sth->{share_id}->execute($hostID,$share);
421 my ($id) = $sth->{share_id}->fetchrow_array();
423 return $id if (defined($id));
425 $sth->{insert_share} ||= $dbh->prepare(qq{
427 (hostID,name,share,localpath)
431 my $drop_down = $hostname . '/' . $share;
432 $drop_down =~ s#//+#/#g;
434 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
435 return $dbh->last_insert_id(undef,undef,'shares',undef);
443 my ($key, $shareID,undef,$name,$path,$date,undef,$size) = @_;
445 return $beenThere->{$key} if (defined($beenThere->{$key}));
447 $sth->{file_in_db} ||= $dbh->prepare(qq{
449 WHERE shareID = ? and
456 my @param = ($shareID,$path,$date,$size);
457 $sth->{file_in_db}->execute(@param);
458 my $rows = $sth->{file_in_db}->rows;
459 print STDERR "## found_in_db($shareID,$path,$date,$size) ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
461 $beenThere->{$key}++;
463 $sth->{'insert_files'}->execute(@data) unless ($rows);
467 ####################################################
468 # recursing through filesystem structure and #
469 # and returning flattened files list #
470 ####################################################
471 sub recurseDir($$$$$$$$) {
473 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
475 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
477 my ($nr_files, $new_files, $nr_dirs, $new_dirs, $size) = (0,0,0,0,0);
482 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
483 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
485 # first, add all the entries in current directory
486 foreach my $path_key (keys %{$filesInBackup}) {
487 print STDERR "# file ",Dumper($filesInBackup->{$path_key}),"\n" if ($debug >= 3);
492 $filesInBackup->{$path_key}->{'relPath'},
493 $filesInBackup->{$path_key}->{'mtime'},
494 $filesInBackup->{$path_key}->{'type'},
495 $filesInBackup->{$path_key}->{'size'}
498 my $key = join(" ", (
502 $filesInBackup->{$path_key}->{'mtime'},
503 $filesInBackup->{$path_key}->{'size'}
507 if (! defined($beenThere->{$key}) && ! ($found = found_in_db($key, @data)) ) {
508 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
510 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
511 $new_dirs++ unless ($found);
512 print STDERR " dir\n" if ($debug >= 2);
514 $new_files++ unless ($found);
515 print STDERR " file\n" if ($debug >= 2);
517 $size += $filesInBackup->{$path_key}->{'size'} || 0;
520 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
523 my $full_path = $dir . '/' . $path_key;
524 push @stack, $full_path;
525 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
527 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
539 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
541 while ( my $dir = shift @stack ) {
542 my ($f,$nf,$d,$nd, $s) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
543 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
552 return ($nr_files, $new_files, $nr_dirs, $new_dirs, $size);