final move of files
[web.mtrack] / MTrackWeb / Cron / update-search-index.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3 die("make a class of me");
4 if (function_exists('date_default_timezone_set')) {
5   date_default_timezone_set('UTC');
6 }
7
8 include dirname(__FILE__) . '/../inc/common.php';
9 MTrackSearchDB::setBatchMode();
10
11 $vardir = MTrackConfig::get('core', 'vardir');
12
13 /* only allow one instance to run concurrently */
14 $fp = fopen("$vardir/.indexer.lock", 'w');
15 if (!$fp) {
16   exit(1);
17 }
18 if (!flock($fp, LOCK_EX|LOCK_NB)) {
19   echo "Another instance is already running\n";
20   exit(1);
21 }
22 /* "leak" $fp, so that the lock is held while we continue to run */
23
24 /* log to a file in the var dir */
25 function log_output($buffer)
26 {
27   global $log_file;
28   fwrite($log_file, $buffer);
29   fflush($log_file);
30 }
31 $log_file = fopen("$vardir/indexer.log", 'w');
32 if ($log_file) {
33   ob_start('log_output');
34 }
35 function log_flush() {
36   flush();
37   ob_flush();
38   flush();
39 }
40
41 $start_time = time();
42 echo "Indexing started at " . date('c') . "\n";
43 log_flush();
44
45 $last = '1990-01-01T00:00:00';
46 $ALL = true;
47 foreach (MTrackDB::q('select last_run from search_engine_state')->fetchAll()
48     as $row) {
49   $last = $row[0];
50   $ALL = false;
51 }
52 $LATEST = strtotime($last);
53 $FIRST = $LATEST;
54 $ITEMS = 0;
55 $DONE = array();
56
57 function index_and_measure($object)
58 {
59   global $DONE;
60   if (isset($DONE[$object])) {
61     return true;
62   }
63   $DONE[$object] = true;
64
65   echo "Examine: $object\n";
66   log_flush();
67   $start = time();
68   $res = MTrackSearchDB::index_object($object);
69   $elapsed = time() - $start;
70   printf("Indexed $object in %f seconds\n", $elapsed);
71   log_flush();
72   return $res;
73 }
74
75 function index_items($lower)
76 {
77   global $LATEST;
78   global $ITEMS;
79   global $start_time;
80   global $DONE;
81   global $FIRST;
82
83   /* do the work here */
84
85   foreach (MTrackDB::q('select object, max(changedate) from changes where changedate > ? group by object order by max(changedate)', $lower)->fetchAll(PDO::FETCH_NUM)
86       as $row) {
87
88     if ($LATEST > ($FIRST + 3) && time() - $start_time > 280) {
89       // Step back 1 second on the next run, otherwise we may miss out
90       // a couple of items from the current second
91       $LATEST--;
92       break;
93     }
94
95     list($object, $when) = $row;
96
97     if (true) {
98       $ITEMS++;
99       $res = index_and_measure($object);
100     } else {
101       $res = true;
102     }
103     if ($res === false) {
104       echo "Don't know how to index $object\n";
105     } else {
106       echo "Processed $object $when > $lower\n";
107     }
108     $t = strtotime($when);
109     if ($t > $LATEST) {
110       $LATEST = $t;
111     }
112   }
113 }
114
115 if ($ALL) {
116   // walk all the wiki pages, in case someone checked in against the
117   // wiki repo outside of the app
118   $repo = null;
119   $root = MTrackWikiItem::getRepoAndRoot($repo);
120   $suf = MTrackConfig::get('core', 'wikifilenamesuffix');
121   function walk_wiki($repo, $dir, $suf)
122   {
123     global $DONE;
124
125     $items = $repo->readdir($dir);
126     foreach ($items as $file) {
127       if ($file->is_dir) {
128         walk_wiki($repo, $file->name, $suf);
129       } else {
130         if (!strlen($suf) || substr($file->name, -strlen($suf)) == $suf) {
131           //echo "Going to index wiki:$file->name\n";
132           $object = "wiki:$file->name";
133           index_and_measure($object);
134         } else {
135           //echo "NO: wiki:$file->name\n";
136         }
137       }
138     }
139   }
140   walk_wiki($repo, $root, $suf);
141 }
142
143 index_items($last);
144
145 $db = MTrackDB::get();
146 $db->beginTransaction();
147 $db->exec("delete from search_engine_state");
148 $insert = $db->prepare("insert into search_engine_state (last_run) values (?)");
149 $insert->execute(array(MTrackDB::unixtime($LATEST)));
150 $db->commit();
151
152 if ($ITEMS > 0) {
153   MTrackSearchDB::commit();
154 }
155
156 $end_time = time();
157 $elapsed = $end_time - $start_time;
158 echo "$ITEMS items processed (in $elapsed seconds)\n";
159