Commit 9a8de89c authored by Sebastian Kummer's avatar Sebastian Kummer

ZP-837 Added config options do categorize devices, when exporting keep

looking at the total runtime and stop in time.

Released under the Affero GNU General Public License (AGPL) version 3.
parent 7f31028e
......@@ -258,6 +258,20 @@
// The minimum accepted value is 1 second. The maximum accepted value is 3540 seconds (59 minutes).
define('PING_HIGHER_BOUND_LIFETIME', false);
// Maximum response time
// Mobiles implement different timeouts to their TCP/IP connections. Android devices for example
// have a hard timeout of 30 seconds. If the server is not able to answer a request within this timeframe,
// the answer will not be recieved and the device will send a new one overloading the server.
// There are three categories
// - Short timeout - server has up within 30 seconds - is automatically applied for not categorized types
// - Medium timeout - server has up to 90 seconds to respond
// - Long timeout - server has up to 4 minutes to respond
// If a timeout is almost reached the server will break and sent the results it has until this
// point. You can add DeviceType strings to the categories.
// In general longer timeouts are better, because more data can be streamed at once.
define('SYNC_TIMOUT_MEDIUM_DEVICETYPES', "SAMSUNGGTI");
define('SYNC_TIMOUT_LONG_DEVICETYPES', "iPod, iPad, iPhone, WP, WindowsOutlook");
/**********************************************************************************
* Backend settings
*/
......
......@@ -191,9 +191,7 @@ class FolderSync extends RequestProcessor {
$exporter->InitializeExporter($changesMem);
// Stream all changes to the ImportExportChangesMem
$maxExporttime = Request::GetExpectedConnectionTimeout();
$totalChanges = $exporter->GetChangeCount();
$started = time();
$exported = 0;
$partial = false;
while(is_array($exporter->Synchronize())) {
......@@ -204,8 +202,8 @@ class FolderSync extends RequestProcessor {
}
// if partial sync is allowed, stop if this takes too long
if (USE_PARTIAL_FOLDERSYNC && (time() - $started) > $maxExporttime) {
ZLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): Exporting folders is too slow. In %d seconds only %d from %d changes were processed.",(time() - $started), $exported, $totalChanges));
if (USE_PARTIAL_FOLDERSYNC && Request::IsRequestTimeoutReached()) {
ZLog::Write(LOGLEVEL_WARN, sprintf("Request->HandleFolderSync(): Exporting folders is too slow. In %d seconds only %d from %d changes were processed.",(time() - $_SERVER["REQUEST_TIME"]), $exported, $totalChanges));
self::$topCollector->AnnounceInformation(sprintf("Partial export of %d out of %d folders", $exported, $totalChanges), true);
self::$deviceManager->SetFolderSyncComplete(false);
$partial = true;
......
......@@ -97,7 +97,7 @@ class Request {
static private $koeVersion;
static private $koeBuild;
static private $koeBuildDate;
static private $expectedConnectionTimeout;
/**
* Initializes request data
......@@ -626,17 +626,32 @@ class Request {
// The amount of time returned is somehow lower than the max timeout so we have
// time for processing.
if (!isset(self::$expectedConnectionTimeout)) {
// Apple and Windows Phone have higher timeouts (4min = 240sec)
if (in_array(self::GetDeviceType(), array("iPod", "iPad", "iPhone", "WP"))) {
return 200;
if (stripos(SYNC_TIMOUT_LONG_DEVICETYPES, self::GetDeviceType()) !== false) {
self::$expectedConnectionTimeout = 210;
}
// Samsung devices have a intermediate timeout (90sec)
if (in_array(self::GetDeviceType(), array("SAMSUNGGTI"))) {
return 50;
else if (stripos(SYNC_TIMOUT_MEDIUM_DEVICETYPES, self::GetDeviceType()) !== false) {
self::$expectedConnectionTimeout = 85;
}
else {
// for all other devices, a timeout of 30 seconds is expected
return 20;
self::$expectedConnectionTimeout = 28;
}
}
return self::$expectedConnectionTimeout;
}
/**
* Indicates if the maximum timeout for the devicetype of this request is
* almost reached.
*
* @access public
* @return boolean
*/
static public function IsRequestTimeoutReached() {
return (time() - $_SERVER["REQUEST_TIME"]) >= self::GetExpectedConnectionTimeout();
}
/**----------------------------------------------------------------------------------------------------------
......
......@@ -782,6 +782,11 @@ class Sync extends RequestProcessor {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sync(): no exporter setup for '%s' as GlobalWindowSize is full.", $spa->GetFolderId()));
$setupExporter = false;
}
// if the maximum request timeout is reached, stop processing other collections
if (Request::IsRequestTimeoutReached()) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sync(): no exporter setup for '%s' as request timout reached, omitting output for collection.", $spa->GetFolderId()));
$setupExporter = false;
}
// compare the folder statistics if the backend supports this
if ($setupExporter && self::$backend->HasFolderStats()) {
......@@ -1084,6 +1089,7 @@ class Sync extends RequestProcessor {
}
if($sc->GetParameter($spa, "getchanges") && $spa->HasFolderId() && $spa->HasContentClass() && $spa->HasSyncKey()) {
$moreAvailbleSent = false;
$windowSize = self::$deviceManager->GetWindowSize($spa->GetFolderId(), $spa->GetUuid(), $spa->GetUuidCounter(), $changecount);
// limit windowSize to the max available limit of the global window size left
......@@ -1096,6 +1102,7 @@ class Sync extends RequestProcessor {
// or there is a move state (another sync should be done afterwards)
if($changecount > $windowSize || $spa->GetMoveState() !== false) {
self::$encoder->startTag(SYNC_MOREAVAILABLE, false, true);
$moreAvailbleSent = true;
$spa->DelFolderStat();
}
}
......@@ -1141,7 +1148,7 @@ class Sync extends RequestProcessor {
}
}
if($n >= $windowSize) {
if($n >= $windowSize || Request::IsRequestTimeoutReached()) {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("HandleSync(): Exported maxItems of messages: %d / %d", $n, $changecount));
break;
}
......@@ -1154,6 +1161,17 @@ class Sync extends RequestProcessor {
}
self::$encoder->endTag();
// log the request timeout
if (Request::IsRequestTimeoutReached()) {
ZLog::Write(LOGLEVEL_DEBUG, "HandleSync(): Stopping export as maximum request timeout is almost reached!");
// Send a <MoreAvailable/> tag if we reached the request timout, there are more changes and a moreavailable was not already send
if (!$moreAvailbleSent && ($n > $windowSize)) {
self::$encoder->startTag(SYNC_MOREAVAILABLE, false, true);
$spa->DelFolderStat();
}
}
self::$topCollector->AnnounceInformation(sprintf("Outgoing %d objects%s", $n, ($n >= $windowSize)?" of ".$changecount:""), $this->singleFolder);
$this->saveMultiFolderInfo("outgoing", $n);
$this->saveMultiFolderInfo("queued", $changecount);
......
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