]> git.openstreetmap.org Git - nominatim.git/blob - utils/update.php
Merge pull request #1829 from krahulreddy/websiteSetup
[nominatim.git] / utils / update.php
1 <?php
2
3 require_once(CONST_BasePath.'/lib/init-cmd.php');
4 require_once(CONST_BasePath.'/lib/setup_functions.php');
5 require_once(CONST_BasePath.'/lib/setup/SetupClass.php');
6 require_once(CONST_BasePath.'/lib/setup/AddressLevelParser.php');
7
8 ini_set('memory_limit', '800M');
9
10 use Nominatim\Setup\SetupFunctions as SetupFunctions;
11
12 // (long-opt, short-opt, min-occurs, max-occurs, num-arguments, num-arguments, type, help)
13 $aCMDOptions
14 = array(
15    'Import / update / index osm data',
16    array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
17    array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
18    array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
19
20    array('init-updates', '', 0, 1, 0, 0, 'bool', 'Set up database for updating'),
21    array('check-for-updates', '', 0, 1, 0, 0, 'bool', 'Check if new updates are available'),
22    array('no-update-functions', '', 0, 1, 0, 0, 'bool', 'Do not update trigger functions to support differential updates (assuming the diff update logic is already present)'),
23    array('import-osmosis', '', 0, 1, 0, 0, 'bool', 'Import updates once'),
24    array('import-osmosis-all', '', 0, 1, 0, 0, 'bool', 'Import updates forever'),
25    array('no-index', '', 0, 1, 0, 0, 'bool', 'Do not index the new data'),
26
27    array('calculate-postcodes', '', 0, 1, 0, 0, 'bool', 'Update postcode centroid table'),
28
29    array('import-file', '', 0, 1, 1, 1, 'realpath', 'Re-import data from an OSM file'),
30    array('import-diff', '', 0, 1, 1, 1, 'realpath', 'Import a diff (osc) file from local file system'),
31    array('osm2pgsql-cache', '', 0, 1, 1, 1, 'int', 'Cache size used by osm2pgsql'),
32
33    array('import-node', '', 0, 1, 1, 1, 'int', 'Re-import node'),
34    array('import-way', '', 0, 1, 1, 1, 'int', 'Re-import way'),
35    array('import-relation', '', 0, 1, 1, 1, 'int', 'Re-import relation'),
36    array('import-from-main-api', '', 0, 1, 0, 0, 'bool', 'Use OSM API instead of Overpass to download objects'),
37
38    array('index', '', 0, 1, 0, 0, 'bool', 'Index'),
39    array('index-rank', '', 0, 1, 1, 1, 'int', 'Rank to start indexing from'),
40    array('index-instances', '', 0, 1, 1, 1, 'int', 'Number of indexing instances (threads)'),
41
42    array('deduplicate', '', 0, 1, 0, 0, 'bool', 'Deduplicate tokens'),
43    array('recompute-word-counts', '', 0, 1, 0, 0, 'bool', 'Compute frequency of full-word search terms'),
44    array('update-address-levels', '', 0, 1, 0, 0, 'bool', 'Reimport address level configuration (EXPERT)'),
45    array('recompute-importance', '', 0, 1, 0, 0, 'bool', 'Recompute place importances'),
46    array('no-npi', '', 0, 1, 0, 0, 'bool', '(obsolete)'),
47   );
48
49 getCmdOpt($_SERVER['argv'], $aCMDOptions, $aResult, true, true);
50
51 if (!isset($aResult['index-instances'])) $aResult['index-instances'] = 1;
52 if (!isset($aResult['index-rank'])) $aResult['index-rank'] = 0;
53
54 date_default_timezone_set('Etc/UTC');
55
56 $oDB = new Nominatim\DB();
57 $oDB->connect();
58 $fPostgresVersion = $oDB->getPostgresVersion();
59
60 $aDSNInfo = Nominatim\DB::parseDSN(CONST_Database_DSN);
61 if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
62
63 // cache memory to be used by osm2pgsql, should not be more than the available memory
64 $iCacheMemory = (isset($aResult['osm2pgsql-cache'])?$aResult['osm2pgsql-cache']:2000);
65 if ($iCacheMemory + 500 > getTotalMemoryMB()) {
66     $iCacheMemory = getCacheMemoryMB();
67     echo "WARNING: resetting cache memory to $iCacheMemory\n";
68 }
69
70 $oOsm2pgsqlCmd = (new \Nominatim\Shell(CONST_Osm2pgsql_Binary))
71                  ->addParams('--hstore')
72                  ->addParams('--latlong')
73                  ->addParams('--append')
74                  ->addParams('--slim')
75                  ->addParams('--number-processes', 1)
76                  ->addParams('--cache', $iCacheMemory)
77                  ->addParams('--output', 'gazetteer')
78                  ->addParams('--style', CONST_Import_Style)
79                  ->addParams('--database', $aDSNInfo['database'])
80                  ->addParams('--port', $aDSNInfo['port']);
81
82 if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
83     $oOsm2pgsqlCmd->addParams('--host', $aDSNInfo['hostspec']);
84 }
85 if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
86     $oOsm2pgsqlCmd->addParams('--user', $aDSNInfo['username']);
87 }
88 if (isset($aDSNInfo['password']) && $aDSNInfo['password']) {
89     $oOsm2pgsqlCmd->addEnvPair('PGPASSWORD', $aDSNInfo['password']);
90 }
91 if (!is_null(CONST_Osm2pgsql_Flatnode_File) && CONST_Osm2pgsql_Flatnode_File) {
92     $oOsm2pgsqlCmd->addParams('--flat-nodes', CONST_Osm2pgsql_Flatnode_File);
93 }
94 if ($fPostgresVersion >= 11.0) {
95     $oOsm2pgsqlCmd->addEnvPair(
96         'PGOPTIONS',
97         '-c jit=off -c max_parallel_workers_per_gather=0'
98     );
99 }
100
101
102 $oIndexCmd = (new \Nominatim\Shell(CONST_BasePath.'/nominatim/nominatim.py'))
103              ->addParams('--database', $aDSNInfo['database'])
104              ->addParams('--port', $aDSNInfo['port'])
105              ->addParams('--threads', $aResult['index-instances']);
106
107 if ($aResult['verbose']) {
108     $oIndexCmd->addParams('--verbose');
109 }
110 if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
111     $oIndexCmd->addParams('--host', $aDSNInfo['hostspec']);
112 }
113 if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
114     $oIndexCmd->addParams('--username', $aDSNInfo['username']);
115 }
116 if (isset($aDSNInfo['password']) && $aDSNInfo['password']) {
117     $oIndexCmd->addEnvPair('PGPASSWORD', $aDSNInfo['password']);
118 }
119
120
121 if ($aResult['init-updates']) {
122     // sanity check that the replication URL is correct
123     $sBaseState = file_get_contents(CONST_Replication_Url.'/state.txt');
124     if ($sBaseState === false) {
125         echo "\nCannot find state.txt file at the configured replication URL.\n";
126         echo "Does the URL point to a directory containing OSM update data?\n\n";
127         fail('replication URL not reachable.');
128     }
129     // sanity check for pyosmium-get-changes
130     if (!CONST_Pyosmium_Binary) {
131         echo "\nCONST_Pyosmium_Binary not configured.\n";
132         echo "You need to install pyosmium and set up the path to pyosmium-get-changes\n";
133         echo "in your local settings file.\n\n";
134         fail('CONST_Pyosmium_Binary not configured');
135     }
136
137     $aOutput = 0;
138     $oCMD = new \Nominatim\Shell(CONST_Pyosmium_Binary, '--help');
139     exec($oCMD->escapedCmd(), $aOutput, $iRet);
140
141     if ($iRet != 0) {
142         echo "Cannot execute pyosmium-get-changes.\n";
143         echo "Make sure you have pyosmium installed correctly\n";
144         echo "and have set up CONST_Pyosmium_Binary to point to pyosmium-get-changes.\n";
145         fail('pyosmium-get-changes not found or not usable');
146     }
147
148     if (!$aResult['no-update-functions']) {
149         // instantiate setupClass to use the function therein
150         $cSetup = new SetupFunctions(array(
151                                       'enable-diff-updates' => true,
152                                       'verbose' => $aResult['verbose']
153                                      ));
154         $cSetup->connect();
155         $cSetup->createFunctions();
156     }
157
158     $sDatabaseDate = getDatabaseDate($oDB);
159     if (!$sDatabaseDate) {
160         fail('Cannot determine date of database.');
161     }
162     $sWindBack = strftime('%Y-%m-%dT%H:%M:%SZ', strtotime($sDatabaseDate) - (3*60*60));
163
164     // get the appropriate state id
165     $aOutput = 0;
166     $oCMD = (new \Nominatim\Shell(CONST_Pyosmium_Binary))
167             ->addParams('--start-date', $sWindBack)
168             ->addParams('--server', CONST_Replication_Url);
169
170     exec($oCMD->escapedCmd(), $aOutput, $iRet);
171     if ($iRet != 0 || $aOutput[0] == 'None') {
172         fail('Error running pyosmium tools');
173     }
174
175     $oDB->exec('TRUNCATE import_status');
176     $sSQL = "INSERT INTO import_status (lastimportdate, sequence_id, indexed) VALUES('";
177     $sSQL .= $sDatabaseDate."',".$aOutput[0].', true)';
178
179     try {
180         $oDB->exec($sSQL);
181     } catch (\Nominatim\DatabaseError $e) {
182         fail('Could not enter sequence into database.');
183     }
184
185     echo "Done. Database updates will start at sequence $aOutput[0] ($sWindBack)\n";
186 }
187
188 if ($aResult['check-for-updates']) {
189     $aLastState = $oDB->getRow('SELECT sequence_id FROM import_status');
190
191     if (!$aLastState['sequence_id']) {
192         fail('Updates not set up. Please run ./utils/update.php --init-updates.');
193     }
194
195     $oCmd = (new \Nominatim\Shell(CONST_BasePath.'/utils/check_server_for_updates.py'))
196             ->addParams(CONST_Replication_Url)
197             ->addParams($aLastState['sequence_id']);
198     $iRet = $oCmd->run();
199
200     exit($iRet);
201 }
202
203 if (isset($aResult['import-diff']) || isset($aResult['import-file'])) {
204     // import diffs and files directly (e.g. from osmosis --rri)
205     $sNextFile = isset($aResult['import-diff']) ? $aResult['import-diff'] : $aResult['import-file'];
206
207     if (!file_exists($sNextFile)) {
208         fail("Cannot open $sNextFile\n");
209     }
210
211     // Import the file
212     $oCMD = (clone $oOsm2pgsqlCmd)->addParams($sNextFile);
213     echo $oCMD->escapedCmd()."\n";
214     $iRet = $oCMD->run();
215
216     if ($iRet) {
217         fail("Error from osm2pgsql, $iRet\n");
218     }
219
220     // Don't update the import status - we don't know what this file contains
221 }
222
223 if ($aResult['calculate-postcodes']) {
224     info('Update postcodes centroids');
225     $sTemplate = file_get_contents(CONST_BasePath.'/sql/update-postcodes.sql');
226     runSQLScript($sTemplate, true, true);
227 }
228
229 $sTemporaryFile = CONST_BasePath.'/data/osmosischange.osc';
230 $bHaveDiff = false;
231 $bUseOSMApi = isset($aResult['import-from-main-api']) && $aResult['import-from-main-api'];
232 $sContentURL = '';
233 if (isset($aResult['import-node']) && $aResult['import-node']) {
234     if ($bUseOSMApi) {
235         $sContentURL = 'https://www.openstreetmap.org/api/0.6/node/'.$aResult['import-node'];
236     } else {
237         $sContentURL = 'https://overpass-api.de/api/interpreter?data=node('.$aResult['import-node'].');out%20meta;';
238     }
239 }
240
241 if (isset($aResult['import-way']) && $aResult['import-way']) {
242     if ($bUseOSMApi) {
243         $sContentURL = 'https://www.openstreetmap.org/api/0.6/way/'.$aResult['import-way'].'/full';
244     } else {
245         $sContentURL = 'https://overpass-api.de/api/interpreter?data=(way('.$aResult['import-way'].');node(w););out%20meta;';
246     }
247 }
248
249 if (isset($aResult['import-relation']) && $aResult['import-relation']) {
250     if ($bUseOSMApi) {
251         $sContentURLsModifyXMLstr = 'https://www.openstreetmap.org/api/0.6/relation/'.$aResult['import-relation'].'/full';
252     } else {
253         $sContentURL = 'https://overpass-api.de/api/interpreter?data=((rel('.$aResult['import-relation'].');way(r);node(w));node(r));out%20meta;';
254     }
255 }
256
257 if ($sContentURL) {
258     file_put_contents($sTemporaryFile, file_get_contents($sContentURL));
259     $bHaveDiff = true;
260 }
261
262 if ($bHaveDiff) {
263     // import generated change file
264
265     $oCMD = (clone $oOsm2pgsqlCmd)->addParams($sTemporaryFile);
266     echo $oCMD->escapedCmd()."\n";
267
268     $iRet = $oCMD->run();
269     if ($iRet) {
270         fail("osm2pgsql exited with error level $iRet\n");
271     }
272 }
273
274 if ($aResult['deduplicate']) {
275     $oDB = new Nominatim\DB();
276     $oDB->connect();
277
278     if ($oDB->getPostgresVersion() < 9.3) {
279         fail('ERROR: deduplicate is only currently supported in postgresql 9.3');
280     }
281
282     $sSQL = 'select partition from country_name order by country_code';
283     $aPartitions = $oDB->getCol($sSQL);
284     $aPartitions[] = 0;
285
286     // we don't care about empty search_name_* partitions, they can't contain mentions of duplicates
287     foreach ($aPartitions as $i => $sPartition) {
288         $sSQL = 'select count(*) from search_name_'.$sPartition;
289         $nEntries = $oDB->getOne($sSQL);
290         if ($nEntries == 0) {
291             unset($aPartitions[$i]);
292         }
293     }
294
295     $sSQL = "select word_token,count(*) from word where substr(word_token, 1, 1) = ' '";
296     $sSQL .= ' and class is null and type is null and country_code is null';
297     $sSQL .= ' group by word_token having count(*) > 1 order by word_token';
298     $aDuplicateTokens = $oDB->getAll($sSQL);
299     foreach ($aDuplicateTokens as $aToken) {
300         if (trim($aToken['word_token']) == '' || trim($aToken['word_token']) == '-') continue;
301         echo 'Deduping '.$aToken['word_token']."\n";
302         $sSQL = 'select word_id,';
303         $sSQL .= ' (select count(*) from search_name where nameaddress_vector @> ARRAY[word_id]) as num';
304         $sSQL .= " from word where word_token = '".$aToken['word_token'];
305         $sSQL .= "' and class is null and type is null and country_code is null order by num desc";
306         $aTokenSet = $oDB->getAll($sSQL);
307
308         $aKeep = array_shift($aTokenSet);
309         $iKeepID = $aKeep['word_id'];
310
311         foreach ($aTokenSet as $aRemove) {
312             $sSQL = 'update search_name set';
313             $sSQL .= ' name_vector = array_replace(name_vector,'.$aRemove['word_id'].','.$iKeepID.'),';
314             $sSQL .= ' nameaddress_vector = array_replace(nameaddress_vector,'.$aRemove['word_id'].','.$iKeepID.')';
315             $sSQL .= ' where name_vector @> ARRAY['.$aRemove['word_id'].']';
316             $oDB->exec($sSQL);
317
318             $sSQL = 'update search_name set';
319             $sSQL .= ' nameaddress_vector = array_replace(nameaddress_vector,'.$aRemove['word_id'].','.$iKeepID.')';
320             $sSQL .= ' where nameaddress_vector @> ARRAY['.$aRemove['word_id'].']';
321             $oDB->exec($sSQL);
322
323             $sSQL = 'update location_area_country set';
324             $sSQL .= ' keywords = array_replace(keywords,'.$aRemove['word_id'].','.$iKeepID.')';
325             $sSQL .= ' where keywords @> ARRAY['.$aRemove['word_id'].']';
326             $oDB->exec($sSQL);
327
328             foreach ($aPartitions as $sPartition) {
329                 $sSQL = 'update search_name_'.$sPartition.' set';
330                 $sSQL .= ' name_vector = array_replace(name_vector,'.$aRemove['word_id'].','.$iKeepID.')';
331                 $sSQL .= ' where name_vector @> ARRAY['.$aRemove['word_id'].']';
332                 $oDB->exec($sSQL);
333
334                 $sSQL = 'update location_area_country set';
335                 $sSQL .= ' keywords = array_replace(keywords,'.$aRemove['word_id'].','.$iKeepID.')';
336                 $sSQL .= ' where keywords @> ARRAY['.$aRemove['word_id'].']';
337                 $oDB->exec($sSQL);
338             }
339
340             $sSQL = 'delete from word where word_id = '.$aRemove['word_id'];
341             $oDB->exec($sSQL);
342         }
343     }
344 }
345
346 if ($aResult['recompute-word-counts']) {
347     info('Recompute frequency of full-word search terms');
348     $sTemplate = file_get_contents(CONST_BasePath.'/sql/words_from_search_name.sql');
349     runSQLScript($sTemplate, true, true);
350 }
351
352 if ($aResult['index']) {
353     $oCmd = (clone $oIndexCmd)
354             ->addParams('--minrank', $aResult['index-rank']);
355
356     // echo $oCmd->escapedCmd()."\n";
357     $oCmd->run();
358
359     $oDB->exec('update import_status set indexed = true');
360 }
361
362 if ($aResult['update-address-levels']) {
363     echo 'Updating address levels from '.CONST_Address_Level_Config.".\n";
364     $oAlParser = new \Nominatim\Setup\AddressLevelParser(CONST_Address_Level_Config);
365     $oAlParser->createTable($oDB, 'address_levels');
366 }
367
368 if ($aResult['recompute-importance']) {
369     echo "Updating importance values for database.\n";
370     $oDB = new Nominatim\DB();
371     $oDB->connect();
372
373     $sSQL = 'ALTER TABLE placex DISABLE TRIGGER ALL;';
374     $sSQL .= 'UPDATE placex SET (wikipedia, importance) =';
375     $sSQL .= '   (SELECT wikipedia, importance';
376     $sSQL .= '    FROM compute_importance(extratags, country_code, osm_type, osm_id));';
377     $sSQL .= 'UPDATE placex s SET wikipedia = d.wikipedia, importance = d.importance';
378     $sSQL .= ' FROM placex d';
379     $sSQL .= ' WHERE s.place_id = d.linked_place_id and d.wikipedia is not null';
380     $sSQL .= '       and (s.wikipedia is null or s.importance < d.importance);';
381     $sSQL .= 'ALTER TABLE placex ENABLE TRIGGER ALL;';
382     $oDB->exec($sSQL);
383 }
384
385 if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
386     //
387     if (strpos(CONST_Replication_Url, 'download.geofabrik.de') !== false && CONST_Replication_Update_Interval < 86400) {
388         fail('Error: Update interval too low for download.geofabrik.de. ' .
389              "Please check install documentation (https://nominatim.org/release-docs/latest/admin/Import-and-Update#setting-up-the-update-process)\n");
390     }
391
392     $sImportFile = CONST_InstallPath.'/osmosischange.osc';
393
394     $oCMDDownload = (new \Nominatim\Shell(CONST_Pyosmium_Binary))
395                     ->addParams('--server', CONST_Replication_Url)
396                     ->addParams('--outfile', $sImportFile)
397                     ->addParams('--size', CONST_Replication_Max_Diff_size);
398
399     $oCMDImport = (clone $oOsm2pgsqlCmd)->addParams($sImportFile);
400
401     while (true) {
402         $fStartTime = time();
403         $aLastState = $oDB->getRow('SELECT *, EXTRACT (EPOCH FROM lastimportdate) as unix_ts FROM import_status');
404
405         if (!$aLastState['sequence_id']) {
406             echo "Updates not set up. Please run ./utils/update.php --init-updates.\n";
407             exit(1);
408         }
409
410         echo 'Currently at sequence '.$aLastState['sequence_id'].' ('.$aLastState['lastimportdate'].') - '.$aLastState['indexed']." indexed\n";
411
412         $sBatchEnd = $aLastState['lastimportdate'];
413         $iEndSequence = $aLastState['sequence_id'];
414
415         if ($aLastState['indexed']) {
416             // Sleep if the update interval has not yet been reached.
417             $fNextUpdate = $aLastState['unix_ts'] + CONST_Replication_Update_Interval;
418             if ($fNextUpdate > $fStartTime) {
419                 $iSleepTime = $fNextUpdate - $fStartTime;
420                 echo "Waiting for next update for $iSleepTime sec.";
421                 sleep($iSleepTime);
422             }
423
424             // Download the next batch of changes.
425             do {
426                 $fCMDStartTime = time();
427                 $iNextSeq = (int) $aLastState['sequence_id'];
428                 unset($aOutput);
429
430                 $oCMD = (clone $oCMDDownload)->addParams('--start-id', $iNextSeq);
431                 echo $oCMD->escapedCmd()."\n";
432                 if (file_exists($sImportFile)) {
433                     unlink($sImportFile);
434                 }
435                 exec($oCMD->escapedCmd(), $aOutput, $iResult);
436
437                 if ($iResult == 3) {
438                     echo 'No new updates. Sleeping for '.CONST_Replication_Recheck_Interval." sec.\n";
439                     sleep(CONST_Replication_Recheck_Interval);
440                 } elseif ($iResult != 0) {
441                     echo 'ERROR: updates failed.';
442                     exit($iResult);
443                 } else {
444                     $iEndSequence = (int)$aOutput[0];
445                 }
446             } while ($iResult);
447
448             // get the newest object from the diff file
449             $sBatchEnd = 0;
450             $iRet = 0;
451             $oCMD = new \Nominatim\Shell(CONST_BasePath.'/utils/osm_file_date.py', $sImportFile);
452             exec($oCMD->escapedCmd(), $sBatchEnd, $iRet);
453             if ($iRet == 5) {
454                 echo "Diff file is empty. skipping import.\n";
455                 if (!$aResult['import-osmosis-all']) {
456                     exit(0);
457                 } else {
458                     continue;
459                 }
460             }
461             if ($iRet != 0) {
462                 fail('Error getting date from diff file.');
463             }
464             $sBatchEnd = $sBatchEnd[0];
465
466             // Import the file
467             $fCMDStartTime = time();
468
469
470             echo $oCMDImport->escapedCmd()."\n";
471             unset($sJunk);
472             $iErrorLevel = $oCMDImport->run();
473             if ($iErrorLevel) {
474                 echo "Error executing osm2pgsql: $iErrorLevel\n";
475                 exit($iErrorLevel);
476             }
477
478             // write the update logs
479             $iFileSize = filesize($sImportFile);
480             $sSQL = 'INSERT INTO import_osmosis_log';
481             $sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
482             $sSQL .= " values ('$sBatchEnd',$iEndSequence,$iFileSize,'";
483             $sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
484             $sSQL .= date('Y-m-d H:i:s')."','import')";
485             var_Dump($sSQL);
486             $oDB->exec($sSQL);
487
488             // update the status
489             $sSQL = "UPDATE import_status SET lastimportdate = '$sBatchEnd', indexed=false, sequence_id = $iEndSequence";
490             var_Dump($sSQL);
491             $oDB->exec($sSQL);
492             echo date('Y-m-d H:i:s')." Completed download step for $sBatchEnd in ".round((time()-$fCMDStartTime)/60, 2)." minutes\n";
493         }
494
495         // Index file
496         if (!$aResult['no-index']) {
497             $oThisIndexCmd = clone($oIndexCmd);
498             $fCMDStartTime = time();
499
500             echo $oThisIndexCmd->escapedCmd()."\n";
501             $iErrorLevel = $oThisIndexCmd->run();
502             if ($iErrorLevel) {
503                 echo "Error: $iErrorLevel\n";
504                 exit($iErrorLevel);
505             }
506
507             $sSQL = 'INSERT INTO import_osmosis_log';
508             $sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
509             $sSQL .= " values ('$sBatchEnd',$iEndSequence,NULL,'";
510             $sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
511             $sSQL .= date('Y-m-d H:i:s')."','index')";
512             var_Dump($sSQL);
513             $oDB->exec($sSQL);
514             echo date('Y-m-d H:i:s')." Completed index step for $sBatchEnd in ".round((time()-$fCMDStartTime)/60, 2)." minutes\n";
515
516             $sSQL = 'update import_status set indexed = true';
517             $oDB->exec($sSQL);
518         } else {
519             if ($aResult['import-osmosis-all']) {
520                 echo "Error: --no-index cannot be used with continuous imports (--import-osmosis-all).\n";
521                 exit(1);
522             }
523         }
524
525         $fDuration = time() - $fStartTime;
526         echo date('Y-m-d H:i:s')." Completed all for $sBatchEnd in ".round($fDuration/60, 2)." minutes\n";
527         if (!$aResult['import-osmosis-all']) exit(0);
528     }
529 }