-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathloaderSched.php
More file actions
270 lines (255 loc) · 16.9 KB
/
loaderSched.php
File metadata and controls
270 lines (255 loc) · 16.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
<?php
/* Планировщик заданий на загрузку тайлов. Видимо, запускается в одном экземпляре
cli only!
Просматривает файлы заданий, ставит их на скачивание, удаляет скачаные, создаёт задания следующего
масштаба. Запускает загрузчики.
*/
ini_set('error_reporting', E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
chdir(__DIR__); // задаем директорию выполнение скрипта
require('fCommon.php'); //
require 'fTilesStorage.php'; // стандартные функции получения тайла из локального источника
require('fIRun.php'); //
require('params.php'); // пути и параметры
if(!$phpCLIexec) $phpCLIexec = trim(explode(' ',trim(shell_exec("ps -p ".(getmypid())." -o command=")))[0]); // из PID системной командой получаем командную строку и берём первый отделённый пробелом элемент. Считаем, что он - команда запуска php. Должно работать и в busybox.
// Создадим рабочие каталоги - вдруг их нет?
$umask = umask(0); // сменим на 0777 и запомним текущую. Иначе не получится сделать mkdir с нужными прававми
@mkdir($jobsDir, 0777, true);
@mkdir($jobsInWorkDir, 0777, true);
umask($umask); // Вернём. Зачем? Но umask глобальна вообще для всех юзеров веб-сервера
if(IRun()) {
error_log("loaderSched.php - I'm already ruunning, exiting.");
return;
};
$thisCommand = getCurrentCommand(); // избавляет от знания реальной команды php и знает о параметрах
// Занесём себя в crontab grep -v - инвертировать результат, т.е., в crontab заносится всё, кроме thisCommand
exec("crontab -l | grep -v '$thisCommand' | crontab -"); // удалим себя из cron, потому что я мог быть запущен cron'ом, а умерший - не мог удалить
exec("(crontab -l ; echo \"* * * * * $thisCommand > /dev/null\") | crontab -"); // каждую минуту > /dev/null - это если cron настроен так, что шлёт письмо юзеру, если задание что-то вернуло
error_log("loaderSched.php - The Loader's scheduler started with pID ".getmypid());
$infinitely = '';
if(@$argv[1]=='--infinitely') $infinitely = '--infinitely';
$bannedSourcesFileName = "$jobsDir/bannedSources"; // служебный файл, куда загрузчик кладёт инфо о проблемах, а скачивальщик смотрит
@unlink($bannedSourcesFileName); // удалим файл с информацией о проблемах источников - он мог сохраниться из-за краха
// Нужен чтобы хотя бы один оборот, потому что могут быть задания для загрузчиков в jobsInWorkDir
// как новые, и тогда надо запустить загрузчик; так и завершённые, и тогда их надо убить.
do {
//echo "Очередь заданий перед началом обработки:"; print_r($jobs); echo "\n";
$loaderPIDs = array(); // запущенные процессы загрузки
exec('ps ax | grep "loader.php"',$loaderPIDs);
array_walk($loaderPIDs, function (&$str,$i){
if(strpos($str,'ps ax')!==false) $str=null;
if(strpos($str,'grep')!==false) $str=null;
if($str) $str = trim(explode(' ',trim($str))[0]);
});
$loaderPIDs = array_filter($loaderPIDs); // но на самом деле массив с PID загрузчиков нам не нужен. Нужно только их количество.
//echo "Вероятно, есть загрузчики: "; print_r($loaderPIDs); echo "\n";
//exit;
$jobs = preg_grep('~.[0-9]$~', scandir($jobsDir)); // возьмём только файлы с цифровым расшрением
// Проверим наличие, установим и снимем задания
foreach($jobs as $i => $job) { // Для каждого файла задания
//echo "Очередь заданий к началу обработки:"; print_r($jobs); echo "\n";
if(!is_file("$jobsDir/$job")) { // этого задания уже нет
//echo "$i -е задание $job не является заданием\n";
unset($jobs[$i]);
continue; //
};
//error_log("loaderSched.php - There is a job $job");
$path_parts = pathinfo($job);
$mapName = $path_parts['filename'];
list($mapName,$mapLayerNum) = explode('__',$mapName); // если это слой карты
$Zoom = $path_parts['extension'];
//echo "mapName=$mapName; Zoom=$Zoom;\n";
// загрузим параметры карты
require('mapsourcesVariablesList.php'); // потому что в файле источника они могут быть не все, и для новой карты останутся старые
$res=include("$mapSourcesDir/$mapName.php");
if(!$res){ // нет параметров для этой карты
error_log("loaderSched.php - There is no map specified in this job. Let's kill the job.");
unlink("$jobsDir/$job"); // убъём задание
unset($jobs[$i]);
continue;
};
// Проверим соответствие задания параметрам карты
if($loaderMaxZoom > $maxZoom) $loaderMaxZoom = $maxZoom; // $maxZoom - из параметров карты
if($Zoom > $loaderMaxZoom) {
error_log("loaderSched.php - This job has a larger zoom than allowed, we will kill the job.");
unlink("$jobsDir/$job"); // убъём задание
unset($jobs[$i]);
continue;
};
// Если рассматриваемое задание не выполняется
if(!file_exists("$jobsInWorkDir/$job")) {
if($mapLayerNum != null){ // это задание для слоя карты - просто поставим его на выполнение
error_log("loaderSched.php - A new job $job. Let's put it on download.");
$umask = umask(0); // сменим на 0777 и запомним текущую
$res = copy("$jobsDir/$job","$jobsInWorkDir/$job"); // поставим на скачивание
chmod("$jobsInWorkDir/$job",0666); // чтобы запуск от другого юзера
umask($umask); // Вернём. Зачем? Но umask глобальна вообще для всех юзеров веб-сервера
if($res) continue;
else {
error_log("loaderSched.php - ERROR: The download task could not be placed.\nThe directory $jobsInWorkDir/$job is missing? No permitions to it?");
break;
};
}
else { // это цельная карта
if(is_array($mapTiles)){
// у нас составная или многослойная карта
// В этом случае исходный файл задания нужно удалить, а вместо него сделать
// сколько-то файлов заданий с тем же масштабом и содержанием, но на каждый слой.
// Ставить их на скачивание не обязательно - они поставятся на следующем обороте.
foreach($mapTiles as $k=>$layerInfo){
if(is_array($layerInfo)){ // ссылка на составляющую карту
// Сделаем файл задания для карты.
// На следующем обороте его возмём в оборот как новое задание для карты
copy("$jobsDir/$job","$jobsDir/{$layerInfo['mapName']}.$Zoom");
}
else { // слой данной карты
// Сделаем задание для слоя.
copy("$jobsDir/$job","$jobsDir/$mapName".'__'."$k.$Zoom");
};
};
echo "Created a lot of job files instead of the complex job file $jobsInWorkDir/$jobName. Complex job file removed.\n";
unlink("$jobsDir/$job"); // убъём задание
unset($jobs[$i]);
continue;
}
else { // карта однослойная, просто ставим задание на выполнение
error_log("loaderSched.php - A new job $job. Let's put it on download.");
$umask = umask(0); // сменим на 0777 и запомним текущую
$res = copy("$jobsDir/$job","$jobsInWorkDir/$job"); // поставим на скачивание
chmod("$jobsInWorkDir/$job",0666); // чтобы запуск от другого юзера
umask($umask); // Вернём. Зачем? Но umask глобальна вообще для всех юзеров веб-сервера
if($res) continue;
else {
error_log("loaderSched.php - ERROR: The download task could not be placed.\nThe directory $jobsInWorkDir/$job is missing? No permitions to it?");
break;
};
};
};
};
// Рассматриваемое задание выполняется.
clearstatcache(TRUE,"$jobsInWorkDir/$job");
$fs = filesize("$jobsInWorkDir/$job"); // выполняющееся скачивание
//echo "The size of the $jobsInWorkDir/$job is $fs bytes.\n";
if($fs<=2 OR $fs==4096) { // условно - пустой файл, это задание завершилось
error_log("loaderSched.php - The job $job is completed.");
unlink("$jobsInWorkDir/$job"); //
if($Zoom >= $loaderMaxZoom) { //
error_log("loaderSched.php - We've downloaded everything, we'll kill the job.");
unlink("$jobsDir/$job"); // всё скачали, убъём задание
unset($jobs[$i]);
continue;
};
$nextJob = createNextZoomLevel("$jobsDir/$job",$minZoom); // создать файл с номерами тайлов следующего уровня, а текущий убъём ,$minZoom - из парамеров карты. При этом, если закончившееся задание было дополнено во время скачивания, то дополнения в этом задании пропадут. Но в следующий масштаб они попадут.
error_log("loaderSched.php - We have created a new job $nextJob;");
if($nextJob) { // его может не быть, если он уже есть
$newZoom = substr($nextJob, strrpos($nextJob,'.')+1); //
if($newZoom > $maxZoom) unlink("$nextJob"); // что-то не так с масштабами?
else {
error_log("loaderSched.php - Ok, Let's set the zoom for downloading $newZoom");
$umask = umask(0); // сменим на 0777 и запомним текущую
copy("$nextJob","$jobsInWorkDir/" . basename($nextJob)); // поставим на скачивание следующий уровень
chmod("$jobsInWorkDir/" . basename($nextJob),0666); // чтобы запуск от другого юзера
umask($umask); // Вернём. Зачем? Но umask глобальна вообще для всех юзеров веб-сервера
};
};
};
}; // конец перебора заданий
//echo "Имеющиеся задания к концу обработки:"; print_r($jobs); echo "\n";
// Если есть задания для загрузчиков -- созданные выше, или добавленные со стороны
$loaderJobs = preg_grep('~.[0-9]$~', scandir($jobsInWorkDir)); // возьмём только файлы с цифровым расшрением
//echo "Выполняющиеся задания loaderJobs:"; print_r($loaderJobs); echo "\n";
// Удалим завершившиеся загружающиеся задания
foreach($loaderJobs as $i => $jobName) { //
clearstatcache(TRUE,"$jobsInWorkDir/$jobName");
$fs = filesize("$jobsInWorkDir/$jobName"); // выполняющееся скачивание
//echo "Есть задание $jobName размером $fs, завершено?\n";
if($fs<=2 OR $fs==4096) { // условно - пустой файл, это задание завершилось
echo "Deleting the completed job file $jobsInWorkDir/$jobName.\n";
unlink("$jobsInWorkDir/$jobName");
unset($loaderJobs[$i]);
};
};
if($loaderJobs) { // Если есть задания для загрузки
//error_log("loaderSched.php - There are jobs for loaders -- loaders are needed.");
// Запустим указанное в конфиге количество загрузчиков
$execString = "$phpCLIexec loader.php $infinitely > /dev/null 2>&1 &";
//$execString = "$phpCLIexec loader.php $infinitely > /dev/null &"; // так в консоли видно и сообщения загрузчиков
for($runs=count($loaderPIDs); $runs<$maxLoaderRuns; $runs++) { // если уже запущено меньше разрешённого количества загрузчиков - запустим ещё
error_log("loaderSched.php - Launching another loader.");
exec($execString,$output,$result);
if($result==1){
error_log("loaderSched.php - Start loader failed, abort. execString=$execString;");
exit(1);
};
};
};
//break;
//echo "Ждём оборота =================================\n";
sleep(5);
} while(count($jobs)); // пока есть задания для планировщика. Загрузчики останутся работать.
// удалим себя из cron
exec("crontab -l | grep -v '$thisCommand' | crontab -");
// удалим файл с информацией о проблемах источников
@unlink($bannedSourcesFileName);
error_log("loaderSched.php - The loader scheduler has ended.");
exit(0);
function createNextZoomLevel($jobName,$minZoom=0) {
/* Получает имя csv файла $jobName, с zoom в качестве раширения,
и для номеров тайлов в этом файле создаёт файл с номерами тайлов следующего, большего уровня
предыдущий убивает
Если требуемый масштаб меньше $minZoom - минимального масштаба из параметров карты,
то создаёт файлы вплоть до $minZoom, т.е., задания для мелких масштабов, которых нет в карте
не останутся и не попадут к загрузчикам.
Возвращает имя полученного файла или пусто.
*/
$path_parts = pathinfo($jobName);
$zoom = $path_parts['extension']; //
$mapName = $path_parts['dirname'].'/'.$path_parts['filename'];
//echo "mapName=$mapName; Zoom=$zoom;\n";
global $jobsInWorkDir;
do {
$zoom++;
$nextJobName="$mapName.$zoom";
//echo "nextJobName=$nextJobName\n";
$oldJob = fopen($jobName,'r');
if(!$oldJob) { //echo " другой поцесс убил файл?\n";
$nextJobName = NULL;
break;
};
$res = flock($oldJob,LOCK_EX);
if($res === false){
error_log("loaderSched.php [createNextZoomLevel] Unable locking job file $jobName Error");
exit(1);
};
//echo "nextJobName=$nextJobName\n";
if(file_exists($nextJobName)) { //echo " такой файл уже может обрабатываться по какой-то причине\n";
$runNextJobName = "$jobsInWorkDir/" . $path_parts['filename'] . ".$zoom";
if(file_exists($runNextJobName)) rename($runNextJobName, $nextJobName); // заменим существующий файл задания ещё не выполненной его частью, удалив часть из выполняемых
};
$umask = umask(0); // сменим на 0777 и запомним текущую
// создадим новый - откроем старый файл только для записи, чтобы никто больше не трогал
$newJob = fopen($nextJobName,'a');
if($newJob === false){
error_log("loaderSched.php [createNextZoomLevel] open new job file error");
exit(1);
};
while(($str=fgets($oldJob)) !== false) {
list($x,$y) = explode(',',$str);
$x = trim($x);
$y = trim($y);
if((is_numeric($x)) and (is_numeric($y))) {
$xyS = nextZoom(array($x,$y));
foreach($xyS as $xy) {
fwrite($newJob,$xy[0].','.$xy[1]."\n"); // запишем файл / допишем в существующий
};
}
else fwrite($newJob,$str);
};
fclose($newJob);
chmod($nextJobName,0666); // чтобы запуск от другого юзера
fclose($oldJob);
umask($umask); // Вернём. Зачем? Но umask глобальна вообще для всех юзеров веб-сервера
unlink($jobName); // прибъём старое задание
} while($zoom<$minZoom);
return $nextJobName;
}; // end function createNextZoomLevel
?>