/[BackupPC]/trunk/lib/BackupPC/SearchLib.pm
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/lib/BackupPC/SearchLib.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 88 - (show annotations)
Sun Aug 28 14:15:01 2005 UTC (18 years, 8 months ago) by dpavlin
File size: 13060 byte(s)
optimization: if there is no file pattern it will fallback on database
usages which is much faster than HyperEstraier (bacause it has indexes)

1 #!/usr/bin/perl
2 package BackupPC::SearchLib;
3
4 use strict;
5 use BackupPC::CGI::Lib qw(:all);
6 use BackupPC::Attrib qw(:all);
7 use DBI;
8 use DateTime;
9 use vars qw(%In $MyURL);
10 use Time::HiRes qw/time/;
11
12 my $on_page = 100;
13 my $pager_pages = 10;
14
15 my $dsn = $Conf{SearchDSN};
16 my $db_user = $Conf{SearchUser} || '';
17
18 my $index_path = $Conf{HyperEstraierIndex};
19 if ($index_path) {
20 $index_path = $TopDir . '/' . $index_path;
21 $index_path =~ s#//#/#g;
22 }
23
24 my $dbh;
25
26 sub get_dbh {
27 $dbh ||= DBI->connect($dsn, $db_user, "", { RaiseError => 1, AutoCommit => 1 } );
28 return $dbh;
29 }
30
31 sub getUnits() {
32 my @ret;
33
34 my $dbh = get_dbh();
35 my $sth = $dbh->prepare(qq{
36 SELECT
37 shares.id as id,
38 hosts.name || ':' || shares.name as share
39 FROM shares
40 JOIN hosts on hostid = hosts.id
41 ORDER BY share
42 } );
43 $sth->execute();
44 push @ret, { 'id' => '', 'share' => '-'}; # dummy any
45
46 while ( my $row = $sth->fetchrow_hashref() ) {
47 push @ret, $row;
48 }
49 return @ret;
50 }
51
52 sub epoch_to_iso {
53 my $t = shift || return;
54 my $iso = BackupPC::Lib::timeStamp(undef, $t);
55 $iso =~ s/\s/ /g;
56 return $iso;
57 }
58
59 sub dates_from_form($) {
60 my $param = shift || return;
61
62 sub mk_epoch_date($$) {
63 my ($name,$suffix) = @_;
64
65 my $yyyy = $param->{ $name . '_year_' . $suffix} || return undef;
66 my $mm .= $param->{ $name . '_month_' . $suffix} ||
67 ( $suffix eq 'from' ? 1 : 12);
68 my $dd .= $param->{ $name . '_day_' . $suffix} ||
69 ( $suffix eq 'from' ? 1 : 31);
70
71 $yyyy =~ s/\D//g;
72 $mm =~ s/\D//g;
73 $dd =~ s/\D//g;
74
75 my $dt = new DateTime(
76 year => $yyyy,
77 month => $mm,
78 day => $dd
79 );
80 print STDERR "mk_epoch_date($name,$suffix) [$yyyy-$mm-$dd] = " . $dt->ymd . " " . $dt->hms . "\n";
81 return $dt->epoch || 'NULL';
82 }
83
84 my @ret = (
85 mk_epoch_date('search_backup', 'from'),
86 mk_epoch_date('search_backup', 'to'),
87 mk_epoch_date('search', 'from'),
88 mk_epoch_date('search', 'to'),
89 );
90
91 return @ret;
92
93 }
94
95
96 sub getWhere($) {
97 my $param = shift || return;
98
99 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
100
101 my @conditions;
102 push @conditions, qq{ backups.date >= $backup_from } if ($backup_from);
103 push @conditions, qq{ backups.date <= $backup_to } if ($backup_to);
104 push @conditions, qq{ files.date >= $files_from } if ($files_from);
105 push @conditions, qq{ files.date <= $files_to } if ($files_to);
106
107 print STDERR "backup: $backup_from - $backup_to files: $files_from - $files_to cond:" . join(" | ",@conditions);
108
109 push( @conditions, ' files.shareid = ' . $param->{'search_share'} ) if ($param->{'search_share'});
110 push (@conditions, " upper(files.path) LIKE upper('%".$param->{'search_filename'}."%')") if ($param->{'search_filename'});
111
112 return join(" and ", @conditions);
113 }
114
115
116 sub getFiles($) {
117 my ($param) = @_;
118
119 my $offset = $param->{'offset'} || 0;
120 $offset *= $on_page;
121
122 my $dbh = get_dbh();
123
124 my $sql_cols = qq{
125 files.id AS fid,
126 hosts.name AS hname,
127 shares.name AS sname,
128 files.backupnum AS backupnum,
129 files.path AS filepath,
130 files.date AS date,
131 files.type AS type,
132 files.size AS size
133 };
134
135 my $sql_from = qq{
136 FROM files
137 INNER JOIN shares ON files.shareID=shares.ID
138 INNER JOIN hosts ON hosts.ID = shares.hostID
139 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = files.shareID
140 };
141
142 my $sql_where;
143 my $where = getWhere($param);
144 $sql_where = " WHERE ". $where if ($where);
145
146 my $sql_order = qq{
147 ORDER BY files.date
148 LIMIT $on_page
149 OFFSET ?
150 };
151
152 my $sql_count = qq{ select count(files.id) $sql_from $sql_where };
153 my $sql_results = qq{ select $sql_cols $sql_from $sql_where $sql_order };
154
155 my $sth = $dbh->prepare($sql_count);
156 $sth->execute();
157 my ($results) = $sth->fetchrow_array();
158
159 $sth = $dbh->prepare($sql_results);
160 $sth->execute( $offset );
161
162 if ($sth->rows != $results) {
163 my $bug = "$0 BUG: [[ $sql_count ]] = $results while [[ $sql_results ]] = " . $sth->rows;
164 $bug =~ s/\s+/ /gs;
165 print STDERR "$bug\n";
166 }
167
168 my @ret;
169
170 while (my $row = $sth->fetchrow_hashref()) {
171 push @ret, $row;
172 }
173
174 $sth->finish();
175 return ($results, \@ret);
176 }
177
178 sub getFilesHyperEstraier($) {
179 my ($param) = @_;
180
181 my $offset = $param->{'offset'} || 0;
182 $offset *= $on_page;
183
184 die "no index_path?" unless ($index_path);
185
186 use HyperEstraier;
187
188 # open the database
189 my $db = HyperEstraier::Database->new();
190 $db->open($index_path, $HyperEstraier::ESTDBREADER);
191
192 # create a search condition object
193 my $cond = HyperEstraier::Condition->new();
194
195 my $q = $param->{'search_filename'};
196 my $shareid = $param->{'search_share'};
197
198 if (length($q) > 0) {
199 $q =~ s/(.)/$1 /g;
200
201 # set the search phrase to the search condition object
202 $cond->set_phrase($q);
203 }
204
205 my ($backup_from, $backup_to, $files_from, $files_to) = dates_from_form($param);
206
207 $cond->add_attr("backup_date NUMGE $backup_from") if ($backup_from);
208 $cond->add_attr("backup_date NUMLE $backup_to") if ($backup_to);
209
210 $cond->add_attr("date NUMGE $files_from") if ($files_from);
211 $cond->add_attr("date NUMLE $files_to") if ($files_to);
212
213 $cond->add_attr("shareid NUMEQ $shareid") if ($shareid);
214
215 # $cond->set_max( $offset + $on_page );
216 $cond->set_options( $HyperEstraier::Condition::SURE );
217 $cond->set_order( 'date NUMA' );
218
219 # get the result of search
220 my $result = $db->search($cond, 0);
221
222 my @res;
223 my $hits = $result->size;
224
225 # for each document in result
226 for my $i ($offset .. ($offset + $on_page - 1)) {
227 last if ($i >= $hits);
228
229 my $id = $result->get($i);
230 my $doc = $db->get_doc($id, 0);
231
232 my $row;
233 foreach my $c (qw/fid hname sname backupnum fiilename filepath date type size/) {
234 $row->{$c} = $doc->attr($c);
235 }
236 push @res, $row;
237 }
238
239 return ($hits, \@res);
240 }
241
242 sub getBackupsNotBurned() {
243
244 my $dbh = get_dbh();
245 my $sql = q{
246 SELECT
247 backups.hostID AS hostid,
248 min(hosts.name) AS host,
249 backups.num AS backupnum,
250 min(backups.type) AS type,
251 min(backups.date) AS date,
252 min(backups.size) AS size
253 FROM files
254 INNER JOIN shares ON files.shareID=shares.ID
255 INNER JOIN hosts ON hosts.ID = shares.hostID
256 INNER JOIN backups ON backups.num = files.backupnum and backups.hostID = hosts.ID AND backups.shareID = shares.ID
257 GROUP BY
258 backups.hostID, backups.num
259 ORDER BY min(backups.date)
260 };
261 my $sth = $dbh->prepare( $sql );
262 my @ret;
263 $sth->execute();
264
265 while ( my $row = $sth->fetchrow_hashref() ) {
266 $row->{'age'} = sprintf("%0.1f", ( (time() - $row->{'date'}) / 86400 ) );
267 $row->{'size'} = sprintf("%0.2f", $row->{'size'} / 1024 / 1024);
268 push @ret, $row;
269 }
270
271 return @ret;
272 }
273
274 sub displayBackupsGrid()
275 {
276 my $retHTML = "";
277 my $addForm = 1;
278
279 if ($addForm) {
280
281 $retHTML .= <<EOF3;
282 <script language="javascript" type="text/javascript">
283 <!--
284
285 function checkAll(location)
286 {
287 for (var i=0;i<document.forma.elements.length;i++)
288 {
289 var e = document.forma.elements[i];
290 if ((e.checked || !e.checked) && e.name != \'all\') {
291 if (eval("document.forma."+location+".checked")) {
292 e.checked = true;
293 } else {
294 e.checked = false;
295 }
296 }
297 }
298 }
299 //-->
300 </script>
301 EOF3
302 $retHTML .= q{<form name="forma" method="GET" action="}."$MyURL"."?action=burn\"";
303 $retHTML.= q{<input type="hidden" value="burn" name="action">};
304 $retHTML .= q{<input type="hidden" value="results" name="search_results">};
305 }
306 $retHTML .= qq{
307 <table style="fview" border="1" cellspacing="0" cellpadding="3">
308 <tr class="tableheader">
309 };
310
311 if ($addForm) {
312 $retHTML .= "<td class=\"tableheader\"><input type=\"checkbox\" name=\"allFiles\" onClick=\"checkAll('allFiles');\"></td>";
313 }
314 $retHTML .= qq{
315 <td align="center">Host</td>
316 <td align="center">Backup no</td>
317 <td align="center">Type</td>
318 <td align="center">date</td>
319 <td align="center">age/days</td>
320 <td align="center">size/MB</td>
321 </tr>
322 };
323
324 my @backups = getBackupsNotBurned();
325 my $backup;
326
327 if ($addForm) {
328 $retHTML .= qq{
329 <tr><td colspan=7 style="tableheader">
330 <input type="submit" value="Burn selected backups on medium" name="submitBurner">
331 </td></tr>
332 };
333 }
334
335 foreach $backup(@backups) {
336
337 my $ftype = "";
338
339 $retHTML .= "<tr>";
340 if ($addForm) {
341 $retHTML .= '<td class="fview"><input type="checkbox" name="fcb' .
342 $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
343 '" value="' . $backup->{'hostid'}.'_'.$backup->{'backupnum'} .
344 '"></td>';
345 }
346
347 $retHTML .= '<td class="fviewborder">' . $backup->{'host'} . '</td>' .
348 '<td class="fviewborder">' . $backup->{'backupnum'} . '</td>' .
349 '<td class="fviewborder">' . $backup->{'type'} . '</td>' .
350 '<td class="fviewborder">' . epoch_to_iso( $backup->{'date'} ) . '</td>' .
351 '<td class="fviewborder">' . $backup->{'age'} . '</td>' .
352 '<td class="fviewborder">' . $backup->{'size'} . '</td>' .
353 '</tr>';
354 }
355
356 $retHTML .= "</table>";
357
358 if ($addForm) {
359 $retHTML .= "</form>";
360 }
361
362 return $retHTML;
363 }
364
365 sub displayGrid($) {
366 my ($param) = @_;
367
368 my $offset = $param->{'offset'};
369 my $hilite = $param->{'search_filename'};
370
371 my $retHTML = "";
372
373 my $start_t = time();
374
375 my ($results, $files);
376 if ($param->{'use_hest'} && length($hilite) > 0) {
377 ($results, $files) = getFilesHyperEstraier($param);
378 } else {
379 ($results, $files) = getFiles($param);
380 }
381
382 my $dur_t = time() - $start_t;
383 my $dur = sprintf("%0.4fs", $dur_t);
384
385 my ($from, $to) = (($offset * $on_page) + 1, ($offset * $on_page) + $on_page);
386
387 if ($results <= 0) {
388 $retHTML .= qq{
389 <p style="color: red;">No results found...</p>
390 };
391 return $retHTML;
392 } else {
393 # DEBUG
394 #use Data::Dumper;
395 #$retHTML .= '<pre>' . Dumper($files) . '</pre>';
396 }
397
398
399 $retHTML .= qq{
400 <div>
401 Found <b>$results files</b> showing <b>$from - $to</b> (took $dur)
402 </div>
403 <table style="fview" width="100%" border="0" cellpadding="2" cellspacing="0">
404 <tr class="fviewheader">
405 <td></td>
406 <td align="center">Share</td>
407 <td align="center">Type and Name</td>
408 <td align="center">#</td>
409 <td align="center">Size</td>
410 <td align="center">Date</td>
411 <td align="center">Media</td>
412 </tr>
413 };
414
415 my $file;
416
417 sub hilite_html($$) {
418 my ($html, $search) = @_;
419 $html =~ s#($search)#<b>$1</b>#gis;
420 return $html;
421 }
422
423 sub restore_link($$$$$$) {
424 my $type = shift;
425 my $action = 'RestoreFile';
426 $action = 'browse' if (lc($type) eq 'dir');
427 return sprintf(qq{<a href="?action=%s&host=%s&num=%d&share=%s&dir=%s">%s</a>}, $action, @_);
428 }
429
430 my $i = $offset * $on_page;
431
432 foreach $file (@{ $files }) {
433 $i++;
434
435 my $typeStr = BackupPC::Attrib::fileType2Text(undef, $file->{'type'});
436 $retHTML .= qq{<tr class="fviewborder">};
437
438 $retHTML .= qq{<td class="fviewborder">$i</td>};
439
440 $retHTML .=
441 qq{<td class="fviewborder" align="right">} . $file->{'hname'} . ':' . $file->{'sname'} . qq{</td>} .
442 qq{<td class="fviewborder"><img src="$Conf{CgiImageDirURL}/icon-$typeStr.gif" alt="$typeStr" align="middle">&nbsp;} . hilite_html( $file->{'filepath'}, $hilite ) . qq{</td>} .
443 qq{<td class="fviewborder" align="center">} . restore_link( $typeStr, ${EscURI( $file->{'hname'} )}, $file->{'backupnum'}, ${EscURI( $file->{'sname'})}, ${EscURI( $file->{'filepath'} )}, $file->{'backupnum'} ) . qq{</td>} .
444 qq{<td class="fviewborder" align="right">} . $file->{'size'} . qq{</td>} .
445 qq{<td class="fviewborder">} . epoch_to_iso( $file->{'date'} ) . qq{</td>} .
446 qq{<td class="fviewborder">} . '?' . qq{</td>};
447
448 $retHTML .= "</tr>";
449 }
450 $retHTML .= "</table>";
451
452 # all variables which has to be transfered
453 foreach my $n (qw/search_day_from search_month_from search_year_from search_day_to search_month_to search_year_to search_backup_day_from search_backup_month_from search_backup_year_from search_backup_day_to search_backup_month_to search_backup_year_to search_filename offset/) {
454 $retHTML .= qq{<INPUT TYPE="hidden" NAME="$n" VALUE="$In{$n}">\n};
455 }
456
457 my $del = '';
458 my $max_page = int( $results / $on_page );
459 my $page = 0;
460
461 sub page_link($$$) {
462 my ($param,$page,$display) = @_;
463
464 $param->{'offset'} = $page;
465
466 my $html = '<a href = "' . $MyURL;
467 my $del = '?';
468 foreach my $k (keys %{ $param }) {
469 if ($param->{$k}) {
470 $html .= $del . $k . '=' . ${EscURI( $param->{$k} )};
471 $del = '&';
472 }
473 }
474 $html .= '">' . $display . '</a>';
475 }
476
477 $retHTML .= '<div style="text-align: center;">';
478
479 if ($offset > 0) {
480 $retHTML .= page_link($param, $offset - 1, '&lt;&lt;') . ' ';
481 }
482
483 while ($page <= $max_page) {
484 if ($page == $offset) {
485 $retHTML .= $del . '<b>' . ($page + 1) . '</b>';
486 } else {
487 $retHTML .= $del . page_link($param, $page, $page + 1);
488 }
489
490 if ($page < $offset - $pager_pages && $page != 0) {
491 $retHTML .= " ... ";
492 $page = $offset - $pager_pages;
493 $del = '';
494 } elsif ($page > $offset + $pager_pages && $page != $max_page) {
495 $retHTML .= " ... ";
496 $page = $max_page;
497 $del = '';
498 } else {
499 $del = ' | ';
500 $page++;
501 }
502 }
503
504 if ($offset < $max_page) {
505 $retHTML .= ' ' . page_link($param, $offset + 1, '&gt;&gt;');
506 }
507
508 $retHTML .= "</div>";
509
510 return $retHTML;
511 }
512
513 1;

  ViewVC Help
Powered by ViewVC 1.1.26