/[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 97 - (show annotations)
Tue Aug 30 09:55:55 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 13878 byte(s)
added EST_SYNC_EVERY => 10000 to sync HyperEstraier database every 10000
entries. Catching SIGINT and SIGQUIT and sync HyperEstraier database.

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
15 use constant BPC_FTYPE_DIR => 5;
16 use constant EST_SYNC_EVERY => 10000;
17
18 my $debug = 0;
19 $|=1;
20
21 my $start_t = time();
22
23 my $pidfile = new File::Pid;
24
25 if (my $pid = $pidfile->running ) {
26 die "$0 already running: $pid\n";
27 } elsif ($pidfile->pid ne $$) {
28 $pidfile->remove;
29 $pidfile = new File::Pid;
30 }
31 $pidfile->write;
32 print STDERR "$0 using pid ",$pidfile->pid," file ",$pidfile->file,"\n";
33
34 my $t_fmt = '%Y-%m-%d %H:%M:%S';
35
36 my $hosts;
37 my $bpc = BackupPC::Lib->new || die;
38 my %Conf = $bpc->Conf();
39 my $TopDir = $bpc->TopDir();
40 my $beenThere = {};
41
42 my $dsn = $Conf{SearchDSN} || die "Need SearchDSN in config.pl\n";
43 my $user = $Conf{SearchUser} || '';
44 my $index_path = $Conf{HyperEstraierIndex};
45 $index_path = $TopDir . '/' . $index_path;
46 $index_path =~ s#//#/#g;
47
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
89 sub signal {
90 my($sig) = @_;
91 if ($hest_db) {
92 print "\nCaught a SIG$sig--syncing database and shutting down\n";
93 $hest_db->sync();
94 $hest_db->close();
95 }
96 exit(0);
97 }
98
99 $SIG{'INT'} = \&signal;
100 $SIG{'QUIT'} = \&signal;
101
102 sub hest_update {
103
104 my ($host_id, $share_id, $num) = @_;
105
106 print curr_time," updating HyperEstraier: select files";
107
108 my $t = time();
109
110 my $where = '';
111 if ($host_id && $share_id && $num) {
112 $where = qq{
113 WHERE
114 hosts.id = ? AND
115 shares.id = ? AND
116 files.backupnum = ?
117 };
118 }
119
120 my $sth = $dbh->prepare(qq{
121 SELECT
122 files.id AS fid,
123 hosts.name AS hname,
124 shares.name AS sname,
125 -- shares.share AS sharename,
126 files.backupnum AS backupnum,
127 -- files.name AS filename,
128 files.path AS filepath,
129 files.date AS date,
130 files.type AS type,
131 files.size AS size,
132 files.shareid AS shareid,
133 backups.date AS backup_date
134 FROM files
135 INNER JOIN shares ON files.shareID=shares.ID
136 INNER JOIN hosts ON hosts.ID = shares.hostID
137 INNER JOIN backups ON backups.num = files.backupNum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
138 $where
139 });
140
141 $sth->execute(@_);
142 my $results = $sth->rows;
143
144 if ($results == 0) {
145 print " - no files, skipping\n";
146 return;
147 }
148
149 my $dot = int($results / 15) || 1;
150
151 print " $results ($dot/#)";
152
153 sub fmt_date {
154 my $t = shift || return;
155 my $iso = BackupPC::Lib::timeStamp($t);
156 $iso =~ s/\s/T/;
157 return $iso;
158 }
159
160 my $max = int($results / $dot);
161
162 print ", opening index $index_path...";
163 use HyperEstraier;
164 my $db = HyperEstraier::Database->new();
165
166 # unless ($hest_db) {
167 # print " open reader";
168 # $hest_db = HyperEstraier::Database->new();
169 #
170 # }
171
172
173 $db->open($index_path, $HyperEstraier::Database::DBWRITER | $HyperEstraier::Database::DBCREAT);
174
175 my $added = 0;
176
177 while (my $row = $sth->fetchrow_hashref()) {
178
179 my $fid = $row->{'fid'} || die "no fid?";
180 my $uri = 'file:///' . $fid;
181
182 my $id = $db->uri_to_id($uri);
183 next unless ($id == -1);
184
185 # create a document object
186 my $doc = HyperEstraier::Document->new;
187
188 # add attributes to the document object
189 $doc->add_attr('@uri', $uri);
190
191 foreach my $c (@{ $sth->{NAME} }) {
192 $doc->add_attr($c, $row->{$c}) if ($row->{$c});
193 }
194
195 #$doc->add_attr('@cdate', fmt_date($row->{'date'}));
196
197 # add the body text to the document object
198 my $path = $row->{'filepath'};
199 $doc->add_text($path);
200 $path =~ s/(.)/$1 /g;
201 $doc->add_hidden_text($path);
202
203 print STDERR $doc->dump_draft,"\n" if ($debug > 1);
204
205 # register the document object to the database
206 $db->put_doc($doc, $HyperEstraier::Database::PDCLEAN);
207
208 $added++;
209 if ($added % $dot == 0) {
210 print "$max ";
211 $max--;
212 }
213
214 if ($added % EST_SYNC_EVERY == 0) {
215 print "sync ";
216 $db->sync();
217 }
218
219 }
220
221 print "sync $added new files";
222 $db->sync();
223 print ", close";
224 $db->close();
225
226 my $dur = (time() - $t) || 1;
227 printf(" [%.2f/s new %.2f/s dur: %s]\n",
228 ( $results / $dur ),
229 ( $added / $dur ),
230 fmt_time($dur)
231 );
232 }
233
234 #---- /subs ----
235
236
237 ## update index ##
238 if (($opt{i} || ($index_path && ! -e $index_path)) && !$opt{c}) {
239 # update all
240 print "force update of HyperEstraier index ";
241 print "importing existing data" unless (-e $index_path);
242 print "by -i flag" if ($opt{i});
243 print "\n";
244 hest_update();
245 }
246
247 ## create tables ##
248 if ($opt{c}) {
249 sub do_index {
250 my $index = shift || return;
251 my ($table,$col,$unique) = split(/_/, $index);
252 $unique ||= '';
253 $index =~ s/,/_/g;
254 $dbh->do(qq{ create $unique index $index on $table($col) });
255 }
256
257 print "creating tables...\n";
258
259 $dbh->do(qq{
260 create table hosts (
261 ID SERIAL PRIMARY KEY,
262 name VARCHAR(30) NOT NULL,
263 IP VARCHAR(15)
264 );
265 });
266
267 $dbh->do(qq{
268 create table shares (
269 ID SERIAL PRIMARY KEY,
270 hostID INTEGER NOT NULL references hosts(id),
271 name VARCHAR(30) NOT NULL,
272 share VARCHAR(200) NOT NULL,
273 localpath VARCHAR(200)
274 );
275 });
276
277 $dbh->do(qq{
278 create table backups (
279 hostID INTEGER NOT NULL references hosts(id),
280 num INTEGER NOT NULL,
281 date integer NOT NULL,
282 type CHAR(4) not null,
283 shareID integer not null references shares(id),
284 size integer not null,
285 PRIMARY KEY(hostID, num, shareID)
286 );
287 });
288
289 #do_index('backups_hostid,num_unique');
290
291 $dbh->do(qq{
292 create table dvds (
293 ID SERIAL PRIMARY KEY,
294 num INTEGER NOT NULL,
295 name VARCHAR(255) NOT NULL,
296 mjesto VARCHAR(255)
297 );
298 });
299
300 $dbh->do(qq{
301 create table files (
302 ID SERIAL PRIMARY KEY,
303 shareID INTEGER NOT NULL references shares(id),
304 backupNum INTEGER NOT NULL,
305 name VARCHAR(255) NOT NULL,
306 path VARCHAR(255) NOT NULL,
307 date integer NOT NULL,
308 type INTEGER NOT NULL,
309 size INTEGER NOT NULL,
310 dvdid INTEGER references dvds(id)
311 );
312 });
313
314 print "creating indexes:";
315
316 foreach my $index (qw(
317 hosts_name
318 backups_hostID
319 backups_num
320 shares_hostID
321 shares_name
322 files_shareID
323 files_path
324 files_name
325 files_date
326 files_size
327 )) {
328 print " $index";
329 do_index($index);
330 }
331 print "...\n";
332
333 $dbh->commit;
334
335 }
336
337 ## delete data before inseting ##
338 if ($opt{d}) {
339 print "deleting ";
340 foreach my $table (qw(files dvds backups shares hosts)) {
341 print "$table ";
342 $dbh->do(qq{ DELETE FROM $table });
343 }
344 print " done...\n";
345
346 $dbh->commit;
347 }
348
349 ## insert new values ##
350
351 # get hosts
352 $hosts = $bpc->HostInfoRead();
353 my $hostID;
354 my $shareID;
355
356 my $sth;
357
358 $sth->{insert_hosts} = $dbh->prepare(qq{
359 INSERT INTO hosts (name, IP) VALUES (?,?)
360 });
361
362 $sth->{hosts_by_name} = $dbh->prepare(qq{
363 SELECT ID FROM hosts WHERE name=?
364 });
365
366 $sth->{backups_count} = $dbh->prepare(qq{
367 SELECT COUNT(*)
368 FROM backups
369 WHERE hostID=? AND num=? AND shareid=?
370 });
371
372 $sth->{insert_backups} = $dbh->prepare(qq{
373 INSERT INTO backups (hostID, num, date, type, shareid, size)
374 VALUES (?,?,?,?,?,?)
375 });
376
377 $sth->{insert_files} = $dbh->prepare(qq{
378 INSERT INTO files
379 (shareID, backupNum, name, path, date, type, size)
380 VALUES (?,?,?,?,?,?,?)
381 });
382
383 foreach my $host_key (keys %{$hosts}) {
384
385 my $hostname = $hosts->{$host_key}->{'host'} || die "can't find host for $host_key";
386
387 $sth->{hosts_by_name}->execute($hosts->{$host_key}->{'host'});
388
389 unless (($hostID) = $sth->{hosts_by_name}->fetchrow_array()) {
390 $sth->{insert_hosts}->execute(
391 $hosts->{$host_key}->{'host'},
392 $hosts->{$host_key}->{'ip'}
393 );
394
395 $hostID = $dbh->last_insert_id(undef,undef,'hosts',undef);
396 }
397
398 print "host ".$hosts->{$host_key}->{'host'}.": ";
399
400 # get backups for a host
401 my @backups = $bpc->BackupInfoRead($hostname);
402 my $incs = scalar @backups;
403 print "$incs increments\n";
404
405 my $inc_nr = 0;
406 $beenThere = {};
407
408 foreach my $backup (@backups) {
409
410 $inc_nr++;
411 last if ($opt{m} && $inc_nr > $opt{m});
412
413 my $backupNum = $backup->{'num'};
414 my @backupShares = ();
415
416 printf("%-10s %2d/%-2d #%-2d %s %5s/%5s files (date: %s dur: %s)\n",
417 $hosts->{$host_key}->{'host'},
418 $inc_nr, $incs, $backupNum,
419 $backup->{type} || '?',
420 $backup->{nFilesNew} || '?', $backup->{nFiles} || '?',
421 strftime($t_fmt,localtime($backup->{startTime})),
422 fmt_time($backup->{endTime} - $backup->{startTime})
423 );
424
425 my $files = BackupPC::View->new($bpc, $hostname, \@backups, 1);
426 foreach my $share ($files->shareList($backupNum)) {
427
428 my $t = time();
429
430 $shareID = getShareID($share, $hostID, $hostname);
431
432 $sth->{backups_count}->execute($hostID, $backupNum, $shareID);
433 my ($count) = $sth->{backups_count}->fetchrow_array();
434 # skip if allready in database!
435 next if ($count > 0);
436
437 # dump some log
438 print curr_time," ", $share;
439
440 my ($f, $nf, $d, $nd, $size) = recurseDir($bpc, $hostname, $files, $backupNum, $share, "", $shareID);
441
442 $sth->{insert_backups}->execute(
443 $hostID,
444 $backupNum,
445 $backup->{'endTime'},
446 $backup->{'type'},
447 $shareID,
448 $size,
449 );
450
451 print " commit";
452 $dbh->commit();
453
454 my $dur = (time() - $t) || 1;
455 printf(" %d/%d files %d/%d dirs %0.2f MB [%.2f/s dur: %s]\n",
456 $nf, $f, $nd, $d,
457 ($size / 1024 / 1024),
458 ( ($f+$d) / $dur ),
459 fmt_time($dur)
460 );
461
462 hest_update($hostID, $shareID, $backupNum);
463 }
464
465 }
466 }
467 undef $sth;
468 $dbh->commit();
469 $dbh->disconnect();
470
471 print "total duration: ",fmt_time(time() - $start_t),"\n";
472
473 $pidfile->remove;
474
475 sub getShareID() {
476
477 my ($share, $hostID, $hostname) = @_;
478
479 $sth->{share_id} ||= $dbh->prepare(qq{
480 SELECT ID FROM shares WHERE hostID=? AND name=?
481 });
482
483 $sth->{share_id}->execute($hostID,$share);
484
485 my ($id) = $sth->{share_id}->fetchrow_array();
486
487 return $id if (defined($id));
488
489 $sth->{insert_share} ||= $dbh->prepare(qq{
490 INSERT INTO shares
491 (hostID,name,share,localpath)
492 VALUES (?,?,?,?)
493 });
494
495 my $drop_down = $hostname . '/' . $share;
496 $drop_down =~ s#//+#/#g;
497
498 $sth->{insert_share}->execute($hostID,$share, $drop_down ,undef);
499 return $dbh->last_insert_id(undef,undef,'shares',undef);
500 }
501
502 sub found_in_db {
503
504 my @data = @_;
505 shift @data;
506
507 my ($key, $shareID,undef,$name,$path,$date,undef,$size) = @_;
508
509 return $beenThere->{$key} if (defined($beenThere->{$key}));
510
511 $sth->{file_in_db} ||= $dbh->prepare(qq{
512 SELECT 1 FROM files
513 WHERE shareID = ? and
514 path = ? and
515 date = ? and
516 size = ?
517 LIMIT 1
518 });
519
520 my @param = ($shareID,$path,$date,$size);
521 $sth->{file_in_db}->execute(@param);
522 my $rows = $sth->{file_in_db}->rows;
523 print STDERR "## found_in_db($shareID,$path,$date,$size) ",( $rows ? '+' : '-' ), join(" ",@param), "\n" if ($debug >= 3);
524
525 $beenThere->{$key}++;
526
527 $sth->{'insert_files'}->execute(@data) unless ($rows);
528 return $rows;
529 }
530
531 ####################################################
532 # recursing through filesystem structure and #
533 # and returning flattened files list #
534 ####################################################
535 sub recurseDir($$$$$$$$) {
536
537 my ($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID) = @_;
538
539 print STDERR "\nrecurse($hostname,$backupNum,$share,$dir,$shareID)\n" if ($debug >= 1);
540
541 my ($nr_files, $new_files, $nr_dirs, $new_dirs, $size) = (0,0,0,0,0);
542
543 { # scope
544 my @stack;
545
546 print STDERR "# dirAttrib($backupNum, $share, $dir)\n" if ($debug >= 2);
547 my $filesInBackup = $files->dirAttrib($backupNum, $share, $dir);
548
549 # first, add all the entries in current directory
550 foreach my $path_key (keys %{$filesInBackup}) {
551 print STDERR "# file ",Dumper($filesInBackup->{$path_key}),"\n" if ($debug >= 3);
552 my @data = (
553 $shareID,
554 $backupNum,
555 $path_key,
556 $filesInBackup->{$path_key}->{'relPath'},
557 $filesInBackup->{$path_key}->{'mtime'},
558 $filesInBackup->{$path_key}->{'type'},
559 $filesInBackup->{$path_key}->{'size'}
560 );
561
562 my $key = join(" ", (
563 $shareID,
564 $dir,
565 $path_key,
566 $filesInBackup->{$path_key}->{'mtime'},
567 $filesInBackup->{$path_key}->{'size'}
568 ));
569
570 my $found;
571 if (! defined($beenThere->{$key}) && ! ($found = found_in_db($key, @data)) ) {
572 print STDERR "# key: $key [", $beenThere->{$key},"]" if ($debug >= 2);
573
574 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
575 $new_dirs++ unless ($found);
576 print STDERR " dir\n" if ($debug >= 2);
577 } else {
578 $new_files++ unless ($found);
579 print STDERR " file\n" if ($debug >= 2);
580 }
581 $size += $filesInBackup->{$path_key}->{'size'} || 0;
582 }
583
584 if ($filesInBackup->{$path_key}->{'type'} == BPC_FTYPE_DIR) {
585 $nr_dirs++;
586
587 my $full_path = $dir . '/' . $path_key;
588 push @stack, $full_path;
589 print STDERR "### store to stack: $full_path\n" if ($debug >= 3);
590
591 # my ($f,$nf,$d,$nd) = recurseDir($bpc, $hostname, $backups, $backupNum, $share, $path_key, $shareID) unless ($beenThere->{$key});
592 #
593 # $nr_files += $f;
594 # $new_files += $nf;
595 # $nr_dirs += $d;
596 # $new_dirs += $nd;
597
598 } else {
599 $nr_files++;
600 }
601 }
602
603 print STDERR "## STACK ",join(", ", @stack),"\n" if ($debug >= 2);
604
605 while ( my $dir = shift @stack ) {
606 my ($f,$nf,$d,$nd, $s) = recurseDir($bpc, $hostname, $files, $backupNum, $share, $dir, $shareID);
607 print STDERR "# $dir f: $f nf: $nf d: $d nd: $nd\n" if ($debug >= 1);
608 $nr_files += $f;
609 $new_files += $nf;
610 $nr_dirs += $d;
611 $new_dirs += $nd;
612 $size += $s;
613 }
614 }
615
616 return ($nr_files, $new_files, $nr_dirs, $new_dirs, $size);
617 }
618

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26