/[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 183 - (show annotations)
Wed Oct 12 11:15:19 2005 UTC (18 years, 7 months ago) by dpavlin
File size: 15442 byte(s)
 r8481@llin:  dpavlin | 2005-10-12 13:15:12 +0200
 added archive_burned to -c

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26