Initial code for generating CD contents database
[debian-cd-search.git] / update-lists-db.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Fcntl qw(:flock SEEK_END);
5 use File::stat;
6 use File::Find;
7 use File::Basename;
8 use Compress::Zlib;
9 use POSIX qw(ENOENT EROFS ENOSYS EEXIST EPERM EBUSY O_RDONLY O_RDWR O_APPEND O_CREAT);
10 use Fcntl qw(O_RDWR O_WRONLY);
11 use DB_File;
12
13 my $dbdir = "/home/debian-cd/search-db";
14 my $lock = "$dbdir/.update.lock";
15 my @areas = qw(daily-builds release weekly-builds archive);
16 #my @areas = qw(weekly-builds);
17 my $update_needed = 0;
18 my $num_list_files;
19 my $db_mtime = 0;
20 my $db_file_name;
21 my $list_file_name;
22 my $list_file;
23 my $verbose = 0;
24
25 while (1) {
26     my $arg = shift;
27     if (!defined($arg)) {
28         last;
29     }
30     if ("-v" eq $arg) {
31         $verbose++;
32     }
33 }
34
35 sub print_log {
36     my $level = shift;
37     my $msg = shift;
38     if ($level <= $verbose) {
39         print $msg;
40     }
41 }
42
43 sub lock {
44     my ($fh) = @_;
45     flock($fh, LOCK_EX) or die "Cannot lock lockfile - $!\n";
46     
47     # and, in case someone appended while we were waiting...
48     seek($fh, 0, SEEK_END) or die "Cannot seek - $!\n";
49 }
50
51 sub unlock {
52     my ($fh) = @_;
53     flock($fh, LOCK_UN) or die "Cannot unlock lockfile - $!\n";
54 }
55
56 sub file_mtime {
57     my ($file) = shift;
58     my $sb = lstat($file);
59     if (! -e $file) {
60         print "ENOENT $file!\n";
61     }
62     return $sb->mtime;
63 }
64
65 sub check_newer {
66     my ($filename);
67     $filename = $File::Find::name;
68     if ($filename =~ m/\.list\.gz$/) {
69         my $mtime = file_mtime("/mnt/nfs-cdimage/$filename");
70         print_log(4, "  check_newer: found $filename\n");
71         print LISTS "$filename\n";
72         if ($mtime > $db_mtime) {
73             $update_needed = 1;
74         }
75         $num_list_files++;
76         if (!($num_list_files % 1000)) {
77             print_log(3, "  check_newer: found $num_list_files list files\n");
78         }
79     }
80 }
81
82 chdir "/mnt/nfs-cdimage";
83
84 open(my $lockfile, ">>", "$lock") or die "Can't open lockfile: $!";
85 print_log(1, "waiting on lock for $lock\n");
86 lock($lockfile);
87 print_log(1, "lock acquired for $lock\n");
88
89 foreach my $area (@areas) {
90     $update_needed = 0;
91     $num_list_files = 0;
92     $db_file_name = "$dbdir/$area.db";
93     $list_file_name = "$dbdir/$area.lists";
94
95     print_log(1, "Working on area $area:\n");
96     unlink "$list_file_name.new";
97     open(LISTS, ">> $list_file_name.new") or die ("Can't open lists file $list_file_name.new for writing: $!\n");
98     if (-f $db_file_name) {
99         $db_mtime = file_mtime($db_file_name);
100     } else {
101         $db_mtime = 0;
102     }
103     find (\&check_newer,  "$area");
104     close LISTS;
105     print_log(2, "  found $num_list_files list files total, update_needed $update_needed\n");
106
107     if ($update_needed) {
108         my $current_list_num = 0;
109         my $num_files = 0;
110         my $current_file = 0;
111         my $unique_files = 0;
112         my %fileinfo;
113         my %dbinfo;
114
115         # Two passes; work in memory first, then push to the DB
116         # file. Will this work better?
117         undef %fileinfo;
118         undef %dbinfo;
119
120         unlink "$db_file_name.new";
121
122         open(LISTS, "< $list_file_name.new") or die ("Can't open lists file $list_file_name.new for reading: $!\n");
123         while (my $listfile = <LISTS>) {
124             $current_list_num++;
125             chomp $listfile;
126             my $gz = gzopen($listfile, "rb") or die "Cannot open $listfile: $gzerrno\n";
127             my $file;
128             while ($gz->gzreadline($file) > 0) {
129                 chomp $file;
130                 $num_files++;
131                 if (defined($fileinfo{$file})) {
132                     $fileinfo{$file} = "$fileinfo{$file} $listfile";
133                 } else {
134                     $fileinfo{$file} = "$listfile";
135                     $unique_files++;
136                 }
137             }
138             $gz->gzclose();
139             if (!($current_list_num % 100)) {
140                 print_log(3, "    processing $area in memory: $current_list_num/$num_list_files list files done, $num_files files ($unique_files unique)\n");
141             }
142         }
143
144         # now push to the db
145         tie %dbinfo, 'DB_File', "$db_file_name.new";
146         foreach my $file (keys %fileinfo) {
147             $dbinfo{$file} = $fileinfo{$file};      
148             $current_file++;
149             if (!($current_file % 10000)) {
150                 print_log(3, "    storing $area to db: $current_file/$unique_files files added\n");
151             }
152         }
153         untie %dbinfo;
154         
155         rename("$db_file_name.new", "$db_file_name");
156         print_log(2, "  $db_file_name created: $num_list_files list files, $num_files files referenced\n");
157     }
158     rename("$list_file_name.new", "$list_file_name");
159 }
160 print_log(1, "dropping lock for $lock\n");
161 unlock($lockfile);
162 close($lockfile);