public static function processDownloadFromQueue($syncProcessID) { Zotero_DB::beginTransaction(); // Get a queued process $smallestFirst = Z_CONFIG::$SYNC_DOWNLOAD_SMALLEST_FIRST; $sql = "SELECT syncDownloadQueueID, SDQ.userID,\n\t\t\t\tUNIX_TIMESTAMP(lastsync) AS lastsync, version, params, added, objects, ipAddress\n\t\t\t\tFROM syncDownloadQueue SDQ JOIN sessions USING (sessionID)\n\t\t\t\tWHERE started IS NULL ORDER BY tries > 4, "; if ($smallestFirst) { $sql .= "ROUND(objects / 100), "; } $sql .= "added LIMIT 1 FOR UPDATE"; $row = Zotero_DB::rowQuery($sql); // No pending processes if (!$row) { Zotero_DB::commit(); return 0; } $host = gethostbyname(gethostname()); $startedTimestamp = microtime(true); $sql = "UPDATE syncDownloadQueue SET started=FROM_UNIXTIME(?), processorHost=INET_ATON(?) WHERE syncDownloadQueueID=?"; Zotero_DB::query($sql, array(round($startedTimestamp), $host, $row['syncDownloadQueueID'])); Zotero_DB::commit(); $error = false; $lockError = false; try { if (Zotero_Sync::userIsWriteLocked($row['userID'])) { $lockError = true; throw new Exception("User is write locked"); } $xml = self::getResponseXML($row['version']); $doc = new DOMDocument(); $domResponse = dom_import_simplexml($xml); $domResponse = $doc->importNode($domResponse, true); $doc->appendChild($domResponse); $params = !empty($row['params']) ? json_decode($row['params'], true) : []; self::processDownloadInternal($row['userID'], $row['lastsync'], $doc, $row['syncDownloadQueueID'], $syncProcessID, $params); } catch (Exception $e) { $error = true; $code = $e->getCode(); $msg = $e->getMessage(); } Zotero_DB::beginTransaction(); // Mark download as finished — NULL indicates success if (!$error) { $timestamp = $doc->documentElement->getAttribute('timestamp'); $xmldata = $doc->saveXML(); $size = strlen($xmldata); $sql = "UPDATE syncDownloadQueue SET finished=FROM_UNIXTIME(?), xmldata=? WHERE syncDownloadQueueID=?"; Zotero_DB::query($sql, array($timestamp, $xmldata, $row['syncDownloadQueueID'])); StatsD::increment("sync.process.download.queued.success"); StatsD::updateStats("sync.process.download.queued.size", $size); StatsD::timing("sync.process.download.process", round((microtime(true) - $startedTimestamp) * 1000)); StatsD::timing("sync.process.download.total", max(0, time() - strtotime($row['added'])) * 1000); self::logDownload($row['userID'], round($row['lastsync']), $row['objects'], $row['ipAddress'], $host, round((double) microtime(true) - $startedTimestamp, 2), max(0, min(time() - strtotime($row['added']), 65535)), 0); } else { if ($lockError || strpos($msg, "Lock wait timeout exceeded; try restarting transaction") !== false || strpos($msg, "Deadlock found when trying to get lock; try restarting transaction") !== false || strpos($msg, "Too many connections") !== false || strpos($msg, "Can't connect to MySQL server") !== false || $code == Z_ERROR_SHARD_UNAVAILABLE) { Z_Core::logError($e); $sql = "UPDATE syncDownloadQueue SET started=NULL, tries=tries+1 WHERE syncDownloadQueueID=?"; Zotero_DB::query($sql, $row['syncDownloadQueueID']); $lockError = true; StatsD::increment("sync.process.download.queued.errorTemporary"); } else { Z_Core::logError($e); $sql = "UPDATE syncDownloadQueue SET finished=?, errorCode=?,\n\t\t\t\t\t\terrorMessage=? WHERE syncDownloadQueueID=?"; Zotero_DB::query($sql, array(Zotero_DB::getTransactionTimestamp(), $e->getCode(), substr(serialize($e), 0, 65535), $row['syncDownloadQueueID'])); StatsD::increment("sync.process.download.queued.errorPermanent"); self::logDownload($row['userID'], $row['lastsync'], $row['objects'], $row['ipAddress'], $host, round((double) microtime(true) - $startedTimestamp, 2), max(0, min(time() - strtotime($row['added']), 65535)), 1); } } Zotero_DB::commit(); if ($lockError) { return -1; } else { if ($error) { return -2; } } return 1; }
public function clear() { $this->sessionCheck(); if (Zotero_Sync::userIsReadLocked($this->userID) || Zotero_Sync::userIsWriteLocked($this->userID)) { $message = "You cannot reset server data while one of your libraries " . "is locked for syncing. Please wait for all related syncs to complete."; $this->error(400, 'SYNC_LOCKED', $message); } StatsD::increment("sync.clear"); Zotero_Users::clearAllData($this->userID); $this->responseXML->addChild('cleared'); $this->end(); }