/** * Sync $dst backend to $src backend based on the $src logs given after $start. * Returns the journal entry ID this advanced to and handled (inclusive). * * @param FileBackend $src * @param FileBackend $dst * @param int $start Starting journal position * @param int $end Starting journal position * @param Closure $callback Callback to update any position file * @return int|bool Journal entry ID or false if there are none */ protected function syncBackends(FileBackend $src, FileBackend $dst, $start, $end, Closure $callback) { $lastOKPos = 0; // failed $first = true; // first batch if ($start > $end) { // sanity $this->error("Error: given starting ID greater than ending ID.", 1); } $next = null; do { $limit = min($this->mBatchSize, $end - $start + 1); // don't go pass ending ID $this->output("Doing id {$start} to " . ($start + $limit - 1) . "...\n"); $entries = $src->getJournal()->getChangeEntries($start, $limit, $next); $start = $next; // start where we left off next time if ($first && !count($entries)) { return false; // nothing to do } $first = false; $lastPosInBatch = 0; $pathsInBatch = []; // changed paths foreach ($entries as $entry) { if ($entry['op'] !== 'null') { // null ops are just for reference $pathsInBatch[$entry['path']] = 1; // remove duplicates } $lastPosInBatch = $entry['id']; } $status = $this->syncFileBatch(array_keys($pathsInBatch), $src, $dst); if ($status->isOK()) { $lastOKPos = max($lastOKPos, $lastPosInBatch); $callback($lastOKPos); // update position file } else { $this->error(print_r($status->getErrorsArray(), true)); break; // no gaps; everything up to $lastPos must be OK } if (!$start) { $this->output("End of journal entries.\n"); } } while ($start && $start <= $end); return $lastOKPos; }