Commit 8e3339da authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-851 Added an expiration time for folder stats depending on the

filtertype (max. 1 month) that is taken into account when calling sync
and in ping to determine if an exporter run is required on a folder.

Released under the Affero GNU General Public License (AGPL) version 3.
parent 17813d04
...@@ -518,7 +518,7 @@ class SyncCollections implements Iterator { ...@@ -518,7 +518,7 @@ class SyncCollections implements Iterator {
} }
// check if the folder stat changed since the last sync, if so generate a change for it (only on first run) // check if the folder stat changed since the last sync, if so generate a change for it (only on first run)
if ($this->waitingTime == 0 && ZPush::GetBackend()->HasFolderStats() && $spa->HasFolderStat() && ZPush::GetBackend()->GetFolderStat($store, $spa->GetFolderId()) !== $spa->GetFolderStat()) { if ($this->waitingTime == 0 && ZPush::GetBackend()->HasFolderStats() && $spa->IsExporterRunRequired(ZPush::GetBackend()->GetFolderStat($store, $spa->GetFolderId()), true)) {
$this->changes[$spa->GetFolderId()] = 1; $this->changes[$spa->GetFolderId()] = 1;
} }
} }
......
...@@ -72,6 +72,7 @@ class SyncParameters extends StateObject { ...@@ -72,6 +72,7 @@ class SyncParameters extends StateObject {
'foldersynctotal' => false, 'foldersynctotal' => false,
'foldersyncremaining' => false, 'foldersyncremaining' => false,
'folderstat' => false, 'folderstat' => false,
'folderstattimeout' => false,
); );
/** /**
...@@ -275,6 +276,25 @@ class SyncParameters extends StateObject { ...@@ -275,6 +276,25 @@ class SyncParameters extends StateObject {
$this->checkCPO($this->currentCPO); $this->checkCPO($this->currentCPO);
} }
/**
* Indicates if a exporter run is required. This is the case if the given folderstat is different form the saved one
* or when the expiration time expired.
*
* @param string $currentFolderStat
* @param boolean $doLog
*
* @access public
* @return boolean
*/
public function IsExporterRunRequired($currentFolderStat, $doLog = false) {
$run = ! ($this->HasFolderStat() && $currentFolderStat === $this->GetFolderStat() && time() < $this->GetFolderStatTimeout());
if ($doLog) {
$expDate = ($this->HasFolderStatTimeout()) ? date('Y-m-d H:i:s', $this->GetFolderStatTimeout()) : "not set";
ZLog::Write(LOGLEVEL_DEBUG, sprintf("SyncParameters->IsExporterRunRequired(): %s - current: %s - saved: %s - expiring: %s", Utils::PrintAsString($run), $currentFolderStat, Utils::PrintAsString($this->GetFolderStat()), $expDate));
}
return $run;
}
/** /**
* Checks if a CPO is correctly inicialized and inicializes it if necessary * Checks if a CPO is correctly inicialized and inicializes it if necessary
* *
......
...@@ -741,7 +741,7 @@ class Sync extends RequestProcessor { ...@@ -741,7 +741,7 @@ class Sync extends RequestProcessor {
if ($setupExporter && self::$backend->HasFolderStats()) { if ($setupExporter && self::$backend->HasFolderStats()) {
// check if the folder stats changed -> if not, don't setup the exporter, there are no changes! // check if the folder stats changed -> if not, don't setup the exporter, there are no changes!
$newFolderStat = self::$backend->GetFolderStat(ZPush::GetAdditionalSyncFolderStore($spa->GetFolderId()), $spa->GetFolderId()); $newFolderStat = self::$backend->GetFolderStat(ZPush::GetAdditionalSyncFolderStore($spa->GetFolderId()), $spa->GetFolderId());
if ($spa->HasFolderStat() && $newFolderStat === $spa->GetFolderStat()) { if (! $spa->IsExporterRunRequired($newFolderStat, true)) {
$changecount = 0; $changecount = 0;
$setupExporter = false; $setupExporter = false;
ZLog::Write(LOGLEVEL_DEBUG, "Sync(): Folder stat from the backend indicates that the folder did not change. Exporter will not run."); ZLog::Write(LOGLEVEL_DEBUG, "Sync(): Folder stat from the backend indicates that the folder did not change. Exporter will not run.");
...@@ -828,7 +828,7 @@ class Sync extends RequestProcessor { ...@@ -828,7 +828,7 @@ class Sync extends RequestProcessor {
// Fir AS 14.0+ omit output for folder, if there were no incoming or outgoing changes and no Fetch // Fir AS 14.0+ omit output for folder, if there were no incoming or outgoing changes and no Fetch
if (Request::GetProtocolVersion() >= 14.0 && ! $spa->HasNewSyncKey() && $changecount == 0 && empty($actiondata["fetchids"]) && $status == SYNC_STATUS_SUCCESS && if (Request::GetProtocolVersion() >= 14.0 && ! $spa->HasNewSyncKey() && $changecount == 0 && empty($actiondata["fetchids"]) && $status == SYNC_STATUS_SUCCESS &&
$spa->HasFolderStat() && $spa->GetFolderStat() === $newFolderStat) { ! $spa->IsExporterRunRequired($newFolderStat)) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleSync: No changes found for %s folder id '%s'. Omitting output.", $spa->GetContentClass(), $spa->GetFolderId())); ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleSync: No changes found for %s folder id '%s'. Omitting output.", $spa->GetContentClass(), $spa->GetFolderId()));
continue; continue;
} }
...@@ -1118,7 +1118,7 @@ class Sync extends RequestProcessor { ...@@ -1118,7 +1118,7 @@ class Sync extends RequestProcessor {
// changecount is initialized with 'false', so 0 means no changes! // changecount is initialized with 'false', so 0 means no changes!
if ($changecount === 0 || ($changecount !== false && $changecount <= $windowSize)) { if ($changecount === 0 || ($changecount !== false && $changecount <= $windowSize)) {
self::$deviceManager->SetFolderSyncStatus($spa->GetFolderId(), DeviceManager::FLD_SYNC_COMPLETED); self::$deviceManager->SetFolderSyncStatus($spa->GetFolderId(), DeviceManager::FLD_SYNC_COMPLETED);
$spa->SetFolderStat($newFolderStat); $this->setFolderStat($spa, $newFolderStat);
} }
else else
self::$deviceManager->SetFolderSyncStatus($spa->GetFolderId(), DeviceManager::FLD_SYNC_INPROGRESS); self::$deviceManager->SetFolderSyncStatus($spa->GetFolderId(), DeviceManager::FLD_SYNC_INPROGRESS);
...@@ -1468,4 +1468,23 @@ class Sync extends RequestProcessor { ...@@ -1468,4 +1468,23 @@ class Sync extends RequestProcessor {
} }
return $s; return $s;
} }
/**
* Sets the new folderstat and calculates & sets an expiration date for the folder stat.
*
* @param SyncParameters $spa
* @param string $newFolderStat
*
* @access private
* @return
*/
private function setFolderStat($spa, $newFolderStat) {
$spa->SetFolderStat($newFolderStat);
$maxTimeout = 60 * 60 * 24 * 31; // one month
$interval = Utils::GetFiltertypeInterval($spa->GetFilterType());
$timeout = time() + (($interval && $interval < $maxTimeout) ? $interval : $maxTimeout);
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sync()->setFolderStat() on %s: %s expiring %s", $spa->getFolderId(), $newFolderStat, date('Y-m-d H:i:s', $timeout)));
$spa->SetFolderStatTimeout($timeout);
}
} }
...@@ -308,13 +308,32 @@ class Utils { ...@@ -308,13 +308,32 @@ class Utils {
/** /**
* Converts SYNC_FILTERTYPE into a timestamp * Converts SYNC_FILTERTYPE into a timestamp
* *
* @param int Filtertype * @param int $filtertype Filtertype
* *
* @access public * @access public
* @return long * @return long
*/ */
static public function GetCutOffDate($restrict) { static public function GetCutOffDate($filtertype) {
switch($restrict) { $back = Utils::GetFiltertypeInterval($filtertype);
if ($back === false) {
return 0; // unlimited
}
return time() - $back;
}
/**
* Returns the interval indicated by the filtertype.
*
* @param int $filtertype
*
* @access public
* @return long|boolean returns false on invalid filtertype
*/
static public function GetFiltertypeInterval($filtertype) {
$back = false;
switch($filtertype) {
case SYNC_FILTERTYPE_1DAY: case SYNC_FILTERTYPE_1DAY:
$back = 60 * 60 * 24; $back = 60 * 60 * 24;
break; break;
...@@ -337,10 +356,9 @@ class Utils { ...@@ -337,10 +356,9 @@ class Utils {
$back = 60 * 60 * 24 * 31 * 6; $back = 60 * 60 * 24 * 31 * 6;
break; break;
default: default:
return 0; // unlimited $back = false;
} }
return $back;
return time() - $back;
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment