1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
failover.php
См. документацию.
1<?php
3
5{
6 const ST_ERROR = -1;
7 const ST_UNKNOWN = 0;
8 const ST_FAILOVER = 1;
9 const ST_END = 2;
10 const ST_CONTINUE = 3;
11
12 public static function IsEnabled()
13 {
14 return (COption::GetOptionString('clouds', 'failover_enabled') === 'Y');
15 }
16
17 public static function queueDelete($obBucket, $FILE_PATH)
18 {
19 if (
20 $obBucket->FAILOVER_BUCKET_ID > 0
21 && $obBucket->FAILOVER_DELETE === 'Y'
22 && $obBucket->getQueueFlag()
23 )
24 {
25 if (
26 ($obBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
27 && ($obBucket->FAILOVER_ACTIVE === 'Y')
28 )
29 {
30 $BUCKET_ID = $obBucket->ID;
31 }
32 else
33 {
34 $BUCKET_ID = $obBucket->FAILOVER_BUCKET_ID;
35 }
37 'TIMESTAMP_X' => new \Bitrix\Main\Type\DateTime(),
38 'BUCKET_ID' => $BUCKET_ID,
39 'FILE_PATH' => $FILE_PATH,
40 ]);
41 }
42 }
43
44 public static function queueCopy($obBucket, $FILE_PATH)
45 {
46 if (
47 $obBucket->FAILOVER_BUCKET_ID > 0
48 && $obBucket->FAILOVER_COPY === 'Y'
49 && $obBucket->getQueueFlag()
50 )
51 {
52 if (
53 ($obBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
54 && ($obBucket->FAILOVER_ACTIVE === 'Y')
55 )
56 {
57 $TARGET_BUCKET_ID = $obBucket->ID;
58 $SOURCE_BUCKET_ID = $obBucket->FAILOVER_BUCKET_ID;
59 }
60 else
61 {
62 $TARGET_BUCKET_ID = $obBucket->FAILOVER_BUCKET_ID;
63 $SOURCE_BUCKET_ID = $obBucket->ID;
64 }
65
67 'TIMESTAMP_X' => new \Bitrix\Main\Type\DateTime(),
68 'OP' => \Bitrix\Clouds\CopyQueueTable::OP_COPY,
69 'SOURCE_BUCKET_ID' => $SOURCE_BUCKET_ID,
70 'SOURCE_FILE_PATH' => $FILE_PATH,
71 'TARGET_BUCKET_ID' => $TARGET_BUCKET_ID,
72 'TARGET_FILE_PATH' => $FILE_PATH,
73 ]);
74
76 'select' => ['ID'],
77 'filter' => [
78 '=BUCKET_ID' => $TARGET_BUCKET_ID,
79 '=FILE_PATH' => $FILE_PATH,
80 ],
81 ]);
82 while ($task = $deleteTasks->fetch())
83 {
85 }
86 }
87 }
88
89 public static function queueRename($obBucket, $FILE_PATH_FROM, $FILE_PATH_TO)
90 {
91 if (
92 $obBucket->FAILOVER_BUCKET_ID > 0
93 && $obBucket->FAILOVER_COPY === 'Y'
94 && $obBucket->getQueueFlag()
95 )
96 {
97 if (
98 ($obBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
99 && ($obBucket->FAILOVER_ACTIVE === 'Y')
100 )
101 {
102 $BUCKET_ID = $obBucket->ID;
103 }
104 else
105 {
106 $BUCKET_ID = $obBucket->FAILOVER_BUCKET_ID;
107 }
108
110 'TIMESTAMP_X' => new \Bitrix\Main\Type\DateTime(),
111 'OP' => \Bitrix\Clouds\CopyQueueTable::OP_RENAME,
112 'SOURCE_BUCKET_ID' => $BUCKET_ID,
113 'SOURCE_FILE_PATH' => $FILE_PATH_FROM,
114 'TARGET_BUCKET_ID' => $BUCKET_ID,
115 'TARGET_FILE_PATH' => $FILE_PATH_TO,
116 ]);
117
119 'select' => ['ID'],
120 'filter' => [
121 '=BUCKET_ID' => $BUCKET_ID,
122 '=FILE_PATH' => $FILE_PATH_TO,
123 ],
124 ]);
125 while ($task = $deleteTasks->fetch())
126 {
128 }
129 }
130 }
131
132 public static function executeDeleteQueue()
133 {
135 'limit' => 1,
136 'order' => ['ID' => 'ASC']
137 ])->fetch();
138 if ($deleteTask)
139 {
140 $testBucket = new CCloudStorageBucket($deleteTask['BUCKET_ID']);
141 if (
142 ($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
143 && ($testBucket->FAILOVER_ACTIVE === 'Y')
144 )
145 {
147 }
148
149 $obBucket = new CCloudStorageBucket($deleteTask['BUCKET_ID'], false);
150 if ((time() - $deleteTask['TIMESTAMP_X']->getTimestamp()) > $obBucket->FAILOVER_DELETE_DELAY)
151 {
152 if ($obBucket->Init())
153 {
154 $obBucket->setQueueFlag(false);
155 if (!CCloudTempFile::IsTempFile($deleteTask['FILE_PATH']))
156 {
157 $fileSize = 0;
158 $fileExists = $obBucket->FileExists($deleteTask['FILE_PATH']);
159 if ($fileExists)
160 {
161 $fileSize = $obBucket->GetFileSize($deleteTask['FILE_PATH']);
162 }
163 $result = $obBucket->DeleteFile($deleteTask['FILE_PATH']);
164 if ($result && $fileExists)
165 {
166 $obBucket->DecFileCounter($fileSize);
167 }
168 }
169 else
170 {
171 $obBucket->DeleteFile($deleteTask['FILE_PATH']);
172 }
173
175 }
176 }
178 }
179 else
180 {
182 }
183 }
184
185 public static function executeCopyQueue()
186 {
188 'filter' => ['=STATUS' => 'Y'],
189 'limit' => 1,
190 'order' => ['ID' => 'ASC']
191 ])->fetch();
192 if ($task)
193 {
194 if ($task['OP'] == \Bitrix\Clouds\CopyQueueTable::OP_RENAME)
195 {
196 return static::executeRenameTask($task);
197 }
198 elseif ($task['OP'] == \Bitrix\Clouds\CopyQueueTable::OP_COPY)
199 {
200 return static::executeCopyTask($task, true);
201 }
202 elseif ($task['OP'] == \Bitrix\Clouds\CopyQueueTable::OP_SYNC)
203 {
204 return static::executeCopyTask($task, false);
205 }
206 else
207 {
209 }
210
212 }
213 else
214 {
216 }
217 }
218
219 public static function executeCopyTask($copyTask, $overwrite)
220 {
221 //Check if failover condition is active
222 $testBucket = new CCloudStorageBucket($copyTask['SOURCE_BUCKET_ID']);
223 if (
224 ($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
225 && ($testBucket->FAILOVER_ACTIVE === 'Y')
226 )
227 {
229 }
230
231 $testBucket = new CCloudStorageBucket($copyTask['TARGET_BUCKET_ID']);
232 if (
233 ($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
234 && ($testBucket->FAILOVER_ACTIVE === 'Y')
235 )
236 {
238 }
239
240 //Initialize storages
241 $sourceBucket = new CCloudStorageBucket($copyTask['SOURCE_BUCKET_ID'], false);
242 if (!$sourceBucket->Init())
243 {
245 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
246 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
247 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): failed to init source bucket.'
248 ]);
250 }
251
252 $targetBucket = new CCloudStorageBucket($copyTask['TARGET_BUCKET_ID'], false);
253 if (!$targetBucket->Init())
254 {
256 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
257 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
258 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): failed to init target bucket.'
259 ]);
261 }
262
263 //Check if source file is exists
264 if (!$sourceBucket->FileExists($copyTask['SOURCE_FILE_PATH']))
265 {
267 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
268 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
269 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): source file does not exists.'
270 ]);
272 }
273
274 $CONTENT_TYPE = $sourceBucket->getService()->GetLastRequestHeader('Content-Type');
275 $CONTENT_LENGTH = $sourceBucket->getService()->GetLastRequestHeader('Content-Length');
276
277 if ($copyTask['FILE_SIZE'] == -1)
278 {
279 if ($CONTENT_LENGTH)
280 {
281 $copyTask['FILE_SIZE'] = intval($CONTENT_LENGTH);
282 }
283 else
284 {
285 $copyTask['FILE_SIZE'] = $sourceBucket->GetFileSize($copyTask['SOURCE_FILE_PATH']);
286 }
288 'FILE_SIZE' => $copyTask['FILE_SIZE'],
289 ]);
290 }
291 //AddMessage2Log($copyTask);
292 $targetBucket->setQueueFlag(false);
293 $tempPath = $copyTask['TARGET_FILE_PATH'] . '.fail-over-copy-part';
294
295 $CLOchunkSize = $targetBucket->getService()->GetMinUploadPartSize();
296 if ($copyTask['FILE_SIZE'] <= $CLOchunkSize)
297 {
298 $http = new \Bitrix\Main\Web\HttpClient([
299 'streamTimeout' => 0,
300 ]);
301 $arFile = [
302 'type' => $CONTENT_TYPE,
303 'content' => false,
304 ];
305 $arFile['content'] = $http->get($sourceBucket->GetFileSRC($copyTask['SOURCE_FILE_PATH']));
306 if ($arFile['content'] === false)
307 {
309 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
310 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
311 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): failed to download.'
312 ]);
314 }
315
316 if (!$overwrite && $targetBucket->FileExists($copyTask['TARGET_FILE_PATH']))
317 {
320 }
321
322 $res = $targetBucket->SaveFile($copyTask['TARGET_FILE_PATH'], $arFile);
323 if ($res)
324 {
327 }
328 else
329 {
331 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
332 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
333 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): failed to upload file.'
334 ]);
336 }
337 }
338
339 $upload = new CCloudStorageUpload($tempPath);
340 if ($copyTask['FILE_POS'] == 0)
341 {
342 if (!$overwrite && $targetBucket->FileExists($copyTask['TARGET_FILE_PATH']))
343 {
346 }
347
348 if (!$upload->isStarted())
349 {
350 if (!$upload->Start($targetBucket, $copyTask['FILE_SIZE'], $CONTENT_TYPE))
351 {
353 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
354 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
355 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): failed to start upload.'
356 ]);
358 }
359 }
360 }
361
362 //Download part
363
364 $http = new \Bitrix\Main\Web\HttpClient();
365 $rangeStart = $copyTask['FILE_POS'];
366 $rangeEnd = min($copyTask['FILE_POS'] + $targetBucket->getService()->GetMinUploadPartSize(), $copyTask['FILE_SIZE']) - 1;
367 $http->setHeader('Range', 'bytes=' . $rangeStart . '-' . $rangeEnd);
368 $data = $http->get($sourceBucket->GetFileSRC($copyTask['SOURCE_FILE_PATH']));
369
370 $uploadResult = false;
371 while ($upload->hasRetries())
372 {
373 if ($upload->Next($data, $targetBucket))
374 {
375 $uploadResult = true;
376 break;
377 }
378 }
379
380 if (!$uploadResult)
381 {
383 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
384 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
385 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): upload part failed.'
386 ]);
388 }
389
390 $filePos = $upload->GetPos();
391
392 //Continue next time
393 if ($filePos < $copyTask['FILE_SIZE'])
394 {
396 'FILE_POS' => $filePos,
397 ]);
399 }
400
401 if (!$upload->Finish($targetBucket))
402 {
404 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
405 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
406 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): finish has failed.'
407 ]);
409 }
410
411 if (!CCloudTempFile::IsTempFile($copyTask['TARGET_FILE_PATH']))
412 {
413 $targetBucket->IncFileCounter($copyTask['FILE_SIZE']);
414 }
415
416 if ($overwrite && $targetBucket->FileExists($copyTask['TARGET_FILE_PATH']))
417 {
418 $fileSize = $targetBucket->GetFileSize($copyTask['TARGET_FILE_PATH']);
419 if ($targetBucket->DeleteFile($copyTask['TARGET_FILE_PATH']))
420 {
421 if (!CCloudTempFile::IsTempFile($copyTask['TARGET_FILE_PATH']))
422 {
423 $targetBucket->DecFileCounter($fileSize);
424 }
425 }
426 }
427
428 if (!$targetBucket->FileRename($tempPath, $copyTask['TARGET_FILE_PATH']))
429 {
431 'FAIL_COUNTER' => $copyTask['FAIL_COUNTER'] + 1,
432 'STATUS' => $copyTask['FAIL_COUNTER'] >= COption::GetOptionInt('clouds', 'max_copy_fail_count') ? 'N' : $copyTask['STATUS'],
433 'ERROR_MESSAGE' => 'CCloudFailover::executeCopyQueue(' . $copyTask['ID'] . '): rename failed.'
434 ]);
436 }
437
440 }
441
442 public static function executeRenameTask($renameTask)
443 {
444 $testBucket = new CCloudStorageBucket($renameTask['SOURCE_BUCKET_ID']);
445 if (
446 ($testBucket->isFailoverEnabled() && CCloudFailover::IsEnabled())
447 && ($testBucket->FAILOVER_ACTIVE === 'Y')
448 )
449 {
451 }
452
453 $obBucket = new CCloudStorageBucket($renameTask['SOURCE_BUCKET_ID'], false);
454 if ($obBucket->Init())
455 {
456 $obBucket->setQueueFlag(false);
457 $obBucket->FileRename($renameTask['SOURCE_FILE_PATH'], $renameTask['TARGET_FILE_PATH']);
458 \Bitrix\Clouds\CopyQueueTable::delete($renameTask['ID']);
459 }
460
462 }
463
464 public static function queueAgent()
465 {
466 if (static::lock())
467 {
468 $etime = time() + COption::GetOptionInt('clouds', 'queue_agent_time');
469 $deleteStatus = CCloudFailover::ST_CONTINUE;
470 $copyStatus = CCloudFailover::ST_CONTINUE;
471 do
472 {
473 if ($deleteStatus === CCloudFailover::ST_CONTINUE)
474 {
475 $deleteStatus = static::executeDeleteQueue();
476 if ($deleteStatus === CCloudFailover::ST_FAILOVER)
477 {
478 break;
479 }
480 }
481
482 if ($copyStatus === CCloudFailover::ST_CONTINUE)
483 {
484 $copyStatus = static::executeCopyQueue();
485 if ($copyStatus === CCloudFailover::ST_FAILOVER)
486 {
487 break;
488 }
489 }
490
491 if (
492 ($deleteStatus !== CCloudFailover::ST_CONTINUE)
493 && ($copyStatus !== CCloudFailover::ST_CONTINUE)
494 )
495 {
496 break;
497 }
498 }
499 while (time() < $etime);
500 }
501 static::unlock();
502
503 return 'CCloudFailover::queueAgent();';
504 }
505
506 public static function syncAgent($bucketFrom, $bucketTo, $limit = 100)
507 {
508 $bucketFrom = intval($bucketFrom);
509 $bucketTo = intval($bucketTo);
510 $limit = intval($limit);
511
512 if (static::lock())
513 {
514 $bucket = new CCloudStorageBucket($bucketFrom, false);
515 if ($bucket->Init())
516 {
517 $etime = time() + COption::GetOptionInt('clouds', 'sync_agent_time');
518 do
519 {
521 'select' => ['SOURCE_FILE_PATH'],
522 'filter' => [
523 '=OP' => \Bitrix\Clouds\CopyQueueTable::OP_SYNC,
524 '=SOURCE_BUCKET_ID' => $bucketFrom,
525 '=TARGET_BUCKET_ID' => $bucketTo,
526 ],
527 'order' => ['ID' => 'DESC'],
528 'limit' => 1
529 ])->fetch();
530 $lastKey = $lastJob ? ltrim($lastJob['SOURCE_FILE_PATH'], '/') : '';
531
532 $files = $bucket->ListFiles('/', true, $limit, $lastKey);
533 if ($files === false || empty($files['file']))
534 {
535 return '';
536 }
537
538 foreach ($files['file'] as $fileName)
539 {
541 'TIMESTAMP_X' => new \Bitrix\Main\Type\DateTime(),
542 'OP' => \Bitrix\Clouds\CopyQueueTable::OP_SYNC,
543 'SOURCE_BUCKET_ID' => $bucketFrom,
544 'SOURCE_FILE_PATH' => '/' . $fileName,
545 'TARGET_BUCKET_ID' => $bucketTo,
546 'TARGET_FILE_PATH' => '/' . $fileName,
547 ]);
548 }
549 }
550 while (time() < $etime);
551 }
552 }
553 static::unlock();
554
555 return 'CCloudFailover::syncAgent(' . $bucketFrom . ', ' . $bucketTo . ', ' . $limit . ');';
556 }
557
558 protected static $lock = false;
559
560 public static function lock()
561 {
562 $max_parallel_count = COption::GetOptionInt('clouds', 'agents_max_parallel_count');
563 if ($max_parallel_count == 0)
564 {
565 return true;
566 }
567 elseif ($max_parallel_count == 1)
568 {
569 if (self::_lock_by_id(0))
570 {
571 return true;
572 }
573 }
574 else
575 {
576 for ($i = 0; $i < $max_parallel_count; $i++)
577 {
578 $lockId = mt_rand(0, $max_parallel_count - 1);
579 if (self::_lock_by_id($lockId))
580 {
581 return true;
582 }
583 }
584 for ($i = 0; $i < $max_parallel_count; $i++)
585 {
586 if (self::_lock_by_id($i))
587 {
588 return true;
589 }
590 }
591 }
592 return false;
593 }
594
595 public static function unlock()
596 {
597 if (static::$lock)
598 {
599 flock(static::$lock, LOCK_UN);
600 fclose(static::$lock);
601 static::$lock = false;
602 }
603 }
604
605 protected static function _lock_by_id($lockId)
606 {
607 $lock_file_template = CTempFile::GetAbsoluteRoot() . '/clouds-%d.lock';
608 $lock_file_name = sprintf($lock_file_template, $lockId);
609 static::$lock = fopen($lock_file_name, 'w');
610 if (!static::$lock)
611 {
612 return false;
613 }
614 $locked = flock(static::$lock, LOCK_EX | LOCK_NB);
615 if (!$locked)
616 {
617 fclose(static::$lock);
618 static::$lock = false;
619 }
620 return $locked;
621 }
622}
static getList(array $parameters=array())
Определения datamanager.php:431
static delete($primary)
Определения datamanager.php:1644
static add(array $data)
Определения datamanager.php:877
static update($primary, array $data)
Определения datamanager.php:1256
Определения failover.php:5
const ST_UNKNOWN
Определения failover.php:7
static unlock()
Определения failover.php:595
const ST_ERROR
Определения failover.php:6
static executeDeleteQueue()
Определения failover.php:132
static executeRenameTask($renameTask)
Определения failover.php:442
const ST_FAILOVER
Определения failover.php:8
static queueCopy($obBucket, $FILE_PATH)
Определения failover.php:44
static queueDelete($obBucket, $FILE_PATH)
Определения failover.php:17
static queueAgent()
Определения failover.php:464
static queueRename($obBucket, $FILE_PATH_FROM, $FILE_PATH_TO)
Определения failover.php:89
static _lock_by_id($lockId)
Определения failover.php:605
static IsEnabled()
Определения failover.php:12
static syncAgent($bucketFrom, $bucketTo, $limit=100)
Определения failover.php:506
const ST_END
Определения failover.php:9
static executeCopyTask($copyTask, $overwrite)
Определения failover.php:219
static executeCopyQueue()
Определения failover.php:185
static lock()
Определения failover.php:560
const ST_CONTINUE
Определения failover.php:10
static $lock
Определения failover.php:558
static IsTempFile($file_name)
Определения temp_file.php:19
$data['IS_AVAILABLE']
Определения .description.php:13
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
IncludeModuleLangFile($filepath, $lang=false, $bReturnArray=false)
Определения tools.php:3778
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$fileName
Определения quickway.php:305
$i
Определения factura.php:643