/[BackupPC]/trunk/bin/BackupPC_updatedb
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/bin/BackupPC_updatedb

Parent Directory Parent Directory | Revision Log Revision Log


Revision 130 - (show annotations)
Fri Sep 23 08:54:10 2005 UTC (18 years, 7 months ago) by dpavlin
File size: 16167 byte(s)
 r8205@llin:  dpavlin | 2005-09-23 10:52:33 +0200
 fix partial import (using "part")

1 #!/usr/local/bin/perl -w
2
3 use strict;
4 use lib "__INSTALLDIR__/lib";
5
6 use DBI;
7 use BackupPC::Lib;
8 use BackupPC::View;
9 use Data::Dumper;
10 use Getopt::Std;
11 use Time::HiRes qw/time/;
12 use File::Pid;
13 use POSIX qw/strftime/;
14 use BackupPC::SearchLib;
15
16 use constant BPC_FTYPE_DIR => 5;
17 use constant EST_CHUNK => 100000;
18
19 my $debug = 0;
20 $|=1;
21
22 my $start_t = time();
23
24 my $pidfile = new File::Pid;
25
26 if (my $pid = $pidfile->running ) {
27 die "$0 already running: $pid\n";
28 } elsif ($pidfile->pid ne $$) {
29 $pidfile->remove;
30 $pidfile = new File::Pid;
31 }
32 $pidfile->write;
33 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
34
35 my $t_fmt = '%Y-%m-%d %H:%M:%S';
36
37 my $hosts;
38 my $bpc = BackupPC::Lib->new || die;
39 my %Conf = $bpc->Conf();
40 my $TopDir = $bpc->TopDir();
41 my $beenThere = {};
42
43 my $dsn = $Conf{SearchDSN} || die "Need SearchDSN in config.pl\n";
44 my $user = $Conf{SearchUser} || '';
45
46 my $use_hest = $Conf{HyperEstraierIndex};
47 my ($index_path, $index_node_url) = BackupPC::SearchLib::getHyperEstraier_url($use_hest);
48
49 my $dbh = DBI->connect($dsn, $user, "", { RaiseError => 1, AutoCommit => 0 });
50
51 my %opt;
52
53 if ( !getopts("cdm:v:i", \%opt ) ) {
54 print STDERR <<EOF;
55 usage: $0 [-c|-d] [-m num] [-v|-v level] [-i]
56
57 Options:
58 -c create database on first use
59 -d delete database before import
60 -m num import just num increments for one host
61 -v num set verbosity (debug) level (default $debug)
62 -i update HyperEstraier full text index
63 EOF
64 exit 1;
65 }
66
67 if ($opt{v}) {
68 print "Debug level at $opt{v}\n";
69 $debug = $opt{v};
70 }
71
72 #---- subs ----
73
74 sub fmt_time {
75 my $t = shift || return;
76 my $out = "";
77 my ($ss,$mm,$hh) = gmtime($t);
78 $out .= "${hh}h" if ($hh);
79 $out .= sprintf("%02d:%02d", $mm,$ss);
80 return $out;
81 }
82
83 sub curr_time {
84 return strftime($t_fmt,localtime());
85 }
86
87 my $hest_db;
88 my $hest_node;
89
90 sub signal {
91 my($sig) = @_;
92 if ($hest_db) {
93 print "\nCaught a SIG$sig--syncing database and shutting down\n";
94 $hest_db->sync();
95 $hest_db->close();
96 }
97 exit(0);
98 }
99
100 $SIG{'INT'} = \&signal;
101 $SIG{'QUIT'} = \&signal;
102
103 sub hest_update {
104
105 my ($host_id, $share_id, $num) = @_;
106
107 unless ($use_hest) {
108 print STDERR "HyperEstraier support not enabled in configuration\n";
109 return;
110 }
111
112 print curr_time," updating HyperEstraier:";
113
114 my $t = time();
115
116 my $offset = 0;
117 my $added = 0;
118
119 print " opening index $use_hest";
120 if ($index_path) {
121 $hest_db = HyperEstraier::Database->new();
122 $hest_db->open($TopDir . $index_path, $HyperEstraier::Database::DBWRITER | $HyperEstraier::Database::DBCREAT);
123 print " directly";
124 } elsif ($index_node_url) {
125 $hest_node ||= HyperEstraier::Node->new($index_node_url);
126 $hest_node->set_auth('admin', 'admin');
127 print " via node URL";
128 } else {
129 die "don't know how to use HyperEstraier Index $use_hest";
130 }
131 print " increment is " . EST_CHUNK . " files:";
132
133 my $results = 0;
134
135 do {
136
137 my $where = '';
138 my @data;
139 if ($host_id && $share_id && $num) {
140 $where = qq{
141 WHERE
142 hosts.id = ? AND
143 shares.id = ? AND
144 files.backupnum = ?
145 };
146 @data = ( $host_id, $share_id, $num );
147 }
148
149 my $limit = sprintf('LIMIT '.EST_CHUNK.' OFFSET %d', $offset);
150
151 my $sth = $dbh->prepare(qq{
152 SELECT
153 files.id AS fid,
154 hosts.name AS hname,
155 shares.name AS sname,
156 -- shares.share AS sharename,
157 files.backupnum AS backupnum,
158 -- files.name AS filename,
159 files.path AS filepath,
160 files.date AS date,
161 files.type AS type,
162 files.size AS size,
163 files.shareid AS shareid,
164 backups.date AS backup_date
165 FROM files
166 INNER JOIN shares ON files.shareID=shares.ID
167 INNER JOIN hosts ON hosts.ID = shares.hostID
168 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
169 $where
170 $limit
171 });
172
173 $sth->execute(@data);
174 $results = $sth->rows;
175
176 if ($results == 0) {
177 print " - no new files\n";
178 last;
179 }
180
181 sub fmt_date {
182 my $t = shift || return;
183 my $iso = BackupPC::Lib::timeStamp($t);
184 $iso =~ s/\s/T/;
185 return $iso;
186 }
187
188 while (my $row = $sth->fetchrow_hashref()) {
189
190 my $fid = $row->{'fid'} || die "no fid?";
191 my $uri = 'file:///' . $fid;
192
193 my $id = ($hest_db || $hest_node)->uri_to_id($uri);
194 next unless ($id == -1);
195
196 # create a document object
197 my $doc = HyperEstraier::Document->new;
198
199 # add attributes to the document object
200 $doc->add_attr('@uri', $uri);
201
202 foreach my $c (@{ $sth->{NAME} }) {
203 $doc->add_attr($c, $row->{$c}) if ($row->{$c});
204 }
205
206 #$doc->add_attr('@cdate', fmt_date($row->{'date'}));
207
208 # add the body text to the document object
209 my $path = $row->{'filepath'};
210 $doc->add_text($path);
211 $path =~ s/(.)/$1 /g;
212 $doc->add_hidden_text($path);
213
214 print STDERR $doc->dump_draft,"\n" if ($debug > 1);
215
216 # register the document object to the database
217 if ($hest_db) {
218 $hest_db->put_doc($doc, $HyperEstraier::Database::PDCLEAN);
219 } elsif ($hest_node) {
220 $hest_node->put_doc($doc);
221 } else {
222 die "not supported";
223 }
224 $added++;
225 }
226
227 print " $added";
228 $hest_db->sync() if ($index_path);
229
230 $offset += EST_CHUNK;
231
232 } while ($results == EST_CHUNK);
233
234 if ($index_path) {
235 print ", close";
236 $hest_db->close();
237 }
238
239 my $dur = (time() - $t) || 1;
240 printf(" [%.2f/s dur: %s]\n",
241 ( $added / $dur ),
242 fmt_time($dur)
243 );
244 }
245
246 #---- /subs ----
247
248
249 ## update index ##
250 if (($opt{i} || ($index_path && ! -e $index_path)) && !$opt{c}) {
251 # update all
252 print "force update of HyperEstraier index ";
253 print "importing existing data" unless (-e $index_path);
254 print "by -i flag" if ($opt{i});
255 print "\n";
256 hest_update();
257 }
258
259 ## create tables ##
260 if ($opt{c}) {
261 sub do_index {
262 my $index = shift || return;
263 my ($table,$col,$unique) = split(/_/, $index);
264 $unique ||= '';
265 $index =~ s/,/_/g;
266 $dbh->do(qq{ create $unique index $index on $table($col) });
267 }
268
269 print "creating tables...\n";
270
271 $dbh->do(qq{
272 create table hosts (
273 ID SERIAL PRIMARY KEY,
274 name VARCHAR(30) NOT NULL,
275 IP VARCHAR(15)
276 );
277 });
278
279 $dbh->do(qq{
280 create table shares (
281 ID SERIAL PRIMARY KEY,
282 hostID INTEGER NOT NULL references hosts(id),
283 name VARCHAR(30) NOT NULL,
284 share VARCHAR(200) NOT NULL,
285 localpath VARCHAR(200)
286 );
287 });
288
289 $dbh->do(qq{
290 create table dvds (
291 ID SERIAL PRIMARY KEY,
292 num INTEGER NOT NULL,
293 name VARCHAR(255) NOT NULL,
294 mjesto VARCHAR(255)
295 );
296 });
297
298 $dbh->do(qq{
299 create table backups (
300 hostID INTEGER NOT NULL references hosts(id),
301 num INTEGER NOT NULL,
302 date integer NOT NULL,
303 type CHAR(4) not null,
304 shareID integer not null references shares(id),
305 size integer not null,
306 PRIMARY KEY(hostID, num, shareID)
307 );
308 });
309
310 #do_index('backups_hostid,num_unique');
311
312
313 $dbh->do(qq{
314 create table files (
315 ID SERIAL PRIMARY KEY,
316 shareID INTEGER NOT NULL references shares(id),
317 backupNum INTEGER NOT NULL,
318 name VARCHAR(255) NOT NULL,
319 path VARCHAR(255) NOT NULL,
320 date integer NOT NULL,
321 type INTEGER NOT NULL,
322 size INTEGER NOT NULL
323 );
324 });
325
326
327 $dbh->do( qq{
328 create table archive
329 (
330 id int not null,
331 dvd_nr int not null,
332 note text,
333 username varchar(20) not null,
334 date timestamp,
335 primary key(id)
336 );
337 }
338 );
339
340 $dbh->do( qq{
341 create table archive_backup
342 (
343 archive_id int not null,
344 backup_id int not null,
345 status text,
346 primary key(archive_id, backup_id)
347 );
348 });
349
350 $dbh->do( qq{
351 create table workflows(
352 id int not null,
353 step_id int not null,
354 start timestamp,
355 stop timestamp,
356 username varchar(20),
357 archive_id int not null,
358 running boolean default true,
359 primary key(id)
360 );
361 });
362
363 $dbh->do( qq{
364 create table workflow_step
365 (
366 step_id int not null,
367 code text,
368 next_step int,
369 stop boolean default false,
370 primary key(step_id)
371 );
372 });
373
374 $dbh->do( qq{
375 alter table workflow_step
376 add constraint fk_workflow_next_step
377 foreign key(next_step)
378 references workflow_step(step_id);
379 });
380
381 $dbh->do( qq{
382 alter table workflows
383 add constraint fk_workflows_step_id
384 foreign key(step_id)
385 references workflow_step(step_id);
386 });
387
388 $dbh->do( qq{
389 alter table workflows
390 add constraint fk_workflows_archive_id
391 foreign key(archive_id)
392 references archive(id);
393 });
394
395 $dbh->do( qq{
396 create table workflow_log
397 (
398 workflow_id int not null,
399 step_id int not null,
400 date timestamp not null,
401 status text,
402 primary key(workflow_id, step_id)
403 );
404 });
405
406 $dbh->do( qq{
407 alter table workflow_log
408 add constraint fk_workflow_log_workflow_id
409 foreign key (workflow_id)
410 references workflows(id);
411 });
412
413 $dbh->do( qq{
414 alter table workflow_log
415 add constraint fk_workflow_log_step_id
416 foreign key (step_id)
417 references workflow_step(step_id);
418 });
419
420 print "creating indexes:";
421
422 foreach my $index (qw(
423 hosts_name
424 backups_hostID
425 backups_num
426 shares_hostID
427 shares_name
428 files_shareID
429 files_path
430 files_name
431 files_date
432 files_size
433 )) {
434 print " $index";
435 do_index($index);
436 }
437 print "...\n";
438
439 $dbh->commit;
440
441 }
442
443 ## delete data before inseting ##
444 if ($opt{d}) {
445 print "deleting ";
446 foreach my $table (qw(files dvds backups shares hosts)) {
447 print "$table ";
448 $dbh->do(qq{ DELETE FROM $table });
449 }
450 print " done...\n";
451
452 $dbh->commit;
453 }
454
455 ## insert new values ##
456
457 # get hosts
458 $hosts = $bpc->HostInfoRead();
459 my $hostID;
460 my $shareID;
461
462 my $sth;
463
464 $sth->{insert_hosts} = $dbh->prepare(qq{
465 INSERT INTO hosts (name, IP) VALUES (?,?)
466 });
467
468 $sth->{hosts_by_name} = $dbh->prepare(qq{
469 SELECT ID FROM hosts WHERE name=?
470 });
471
472 $sth->{backups_count} = $dbh->prepare(qq{
473 SELECT COUNT(*)
474 FROM backups
475 WHERE hostID=? AND num=? AND shareid=?
476 });
477
478 $sth->{insert_backups} = $dbh->prepare(qq{
479 INSERT INTO backups (hostID, num, date, type, shareid, size)
480 VALUES (?,?,?,?,?,?)
481 });
482
483 $sth->{insert_files} = $dbh->prepare(qq{
484 INSERT INTO files
485 (shareID, backupNum, name, path, date, type, size)
486 VALUES (?,?,?,?,?,?,?)
487 });
488
489 foreach my $host_key (keys %{$hosts}) {
490
491 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
492
493 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
494
495 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
496 $sth->{insert_hosts}->execute(
497 $hosts->{$host_key}->{'host'},
498 $hosts->{$host_key}->{'ip'}
499 );
500
501 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
502 }
503
504 print "host ".$hosts->{$host_key}->{'host'}.": ";
505
506 # get backups for a host
507 my @backups = $bpc->BackupInfoRead($hostname);
508 my $incs = scalar @backups;
509 print "$incs increments\n";
510
511 my $inc_nr = 0;
512 $beenThere = {};
513
514 foreach my $backup (@backups) {
515
516 $inc_nr++;
517 last if ($opt{m} && $inc_nr > $opt{m});
518
519 my $backupNum = $backup->{'num'};
520 my @backupShares = ();
521
522 printf("%-10s %2d/%-2d #%-2d %s %5s/%5s files (date: %s dur: %s)\n",
523 $hosts->{$host_key}->{'host'},
524 $inc_nr, $incs, $backupNum,
525 $backup->{type} || '?',
526 $backup->{nFilesNew} || '?', $backup->{nFiles} || '?',
527 strftime($t_fmt,localtime($backup->{startTime})),
528 fmt_time($backup->{endTime} - $backup->{startTime})
529 );
530
531 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
532 foreach my $share ($files->shareList($backupNum)) {
533
534 my $t = time();
535
536 $shareID = getShareID($share, $hostID, $hostname);
537
538 $sth->{backups_count}->execute($hostID, $backupNum, $shareID);
539 my ($count) = $sth->{backups_count}->fetchrow_array();
540 # skip if allready in database!
541 next if ($count > 0);
542
543 # dump some log
544 print curr_time," ", $share;
545
546 my ($f, $nf, $d, $nd, $size) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
547
548 $sth->{insert_backups}->execute(
549 $hostID,
550 $backupNum,
551 $backup->{'endTime'},
552 substr($backup->{'type'},0,4),
553 $shareID,
554 $size,
555 );
556
557 print " commit";
558 $dbh->commit();
559
560 my $dur = (time() - $t) || 1;
561 printf(" %d/%d files %d/%d dirs %0.2f MB [%.2f/s dur: %s]\n",
562 $nf, $f, $nd, $d,
563 ($size / 1024 / 1024),
564 ( ($f+$d) / $dur ),
565 fmt_time($dur)
566 );
567
568 hest_update($hostID, $shareID, $backupNum) if ($nf + $nd > 0);
569 }
570
571 }
572 }
573 undef $sth;
574 $dbh->commit();
575 $dbh->disconnect();
576
577 print "total duration: ",fmt_time(time() - $start_t),"\n";
578
579 $pidfile->remove;
580
581 sub getShareID() {
582
583 my ($share, $hostID, $hostname) = @_;
584
585 $sth->{share_id} ||= $dbh->prepare(qq{
586 SELECT ID FROM shares WHERE hostID=? AND name=?
587 });
588
589 $sth->{share_id}->execute($hostID,$share);
590
591 my ($id) = $sth->{share_id}->fetchrow_array();
592
593 return $id if (defined($id));
594
595 $sth->{insert_share} ||= $dbh->prepare(qq{
596 INSERT INTO shares
597 (hostID,name,share,localpath)
598 VALUES (?,?,?,?)
599 });
600
601 my $drop_down = $hostname . '/' . $share;
602 $drop_down =~ s#//+#/#g;
603
604 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
605 return $dbh->last_insert_id(undef,undef,'shares',undef);
606 }
607
608 sub found_in_db {
609
610 my @data = @_;
611 shift @data;
612
613 my ($key, $shareID,undef,$name,$path,$date,undef,$size) = @_;
614
615 return $beenThere->{$key} if (defined($beenThere->{$key}));
616
617 $sth->{file_in_db} ||= $dbh->prepare(qq{
618 SELECT 1 FROM files
619 WHERE shareID = ? and
620 path = ? and
621 date = ? and
622 size = ?
623 LIMIT 1
624 });
625
626 my @param = ($shareID,$path,$date,$size);
627 $sth->{file_in_db}->execute(@param);
628 my $rows = $sth->{file_in_db}->rows;
629 print STDERR "## found_in_db($shareID,$path,$date,$size) ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
630
631 $beenThere->{$key}++;
632
633 $sth->{'insert_files'}->execute(@data) unless ($rows);
634 return $rows;
635 }
636
637 ####################################################
638 # recursing through filesystem structure and #
639 # and returning flattened files list #
640 ####################################################
641 sub recurseDir($$$$$$$$) {
642
643 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
644
645 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
646
647 my ($nr_files, $new_files, $nr_dirs, $new_dirs, $size) = (0,0,0,0,0);
648
649 { # scope
650 my @stack;
651
652 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
653 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
654
655 # first, add all the entries in current directory
656 foreach my $path_key (keys %{$filesInBackup}) {
657 print STDERR "# file ",Dumper($filesInBackup->{$path_key}),"\n" if ($debug >= 3);
658 my @data = (
659 $shareID,
660 $backupNum,
661 $path_key,
662 $filesInBackup->{$path_key}->{'relPath'},
663 $filesInBackup->{$path_key}->{'mtime'},
664 $filesInBackup->{$path_key}->{'type'},
665 $filesInBackup->{$path_key}->{'size'}
666 );
667
668 my $key = join(" ", (
669 $shareID,
670 $dir,
671 $path_key,
672 $filesInBackup->{$path_key}->{'mtime'},
673 $filesInBackup->{$path_key}->{'size'}
674 ));
675
676 my $found;
677 if (! defined($beenThere->{$key}) && ! ($found = found_in_db($key, @data)) ) {
678 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
679
680 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
681 $new_dirs++ unless ($found);
682 print STDERR " dir\n" if ($debug >= 2);
683 } else {
684 $new_files++ unless ($found);
685 print STDERR " file\n" if ($debug >= 2);
686 }
687 $size += $filesInBackup->{$path_key}->{'size'} || 0;
688 }
689
690 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
691 $nr_dirs++;
692
693 my $full_path = $dir . '/' . $path_key;
694 push @stack, $full_path;
695 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
696
697 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
698 #
699 # $nr_files += $f;
700 # $new_files += $nf;
701 # $nr_dirs += $d;
702 # $new_dirs += $nd;
703
704 } else {
705 $nr_files++;
706 }
707 }
708
709 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
710
711 while ( my $dir = shift @stack ) {
712 my ($f,$nf,$d,$nd, $s) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
713 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
714 $nr_files += $f;
715 $new_files += $nf;
716 $nr_dirs += $d;
717 $new_dirs += $nd;
718 $size += $s;
719 }
720 }
721
722 return ($nr_files, $new_files, $nr_dirs, $new_dirs, $size);
723 }
724

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26