Optimize SyncML performance

This commit is contained in:
Jörg Lehrke 2009-12-01 11:21:13 +00:00
parent fd884940f8
commit a1ee7d5cbf
7 changed files with 198 additions and 234 deletions

View File

@ -174,119 +174,111 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
// Determine sync type and status response code.
Horde::logMessage("SyncML: Alert " . $this->_alert, __FILE__, __LINE__, PEAR_LOG_DEBUG);
switch ($this->_alert) {
case ALERT_NEXT_MESSAGE:
$state->setAlert222Received(true);
case ALERT_RESULT_ALERT:
case ALERT_NO_END_OF_DATA:
// Nothing to do on our side
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
$status->setCmdRef($this->_cmdID);
if ($this->_sourceLocURI != null) {
$status->setSourceRef($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
}
if ($this->_alert == ALERT_NEXT_MESSAGE) {
if ($this->_sourceLocURI != null) {
$status->setItemSourceLocURI($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
}
}
$currentCmdID = $status->output($currentCmdID, $output);
return $currentCmdID;
case ALERT_TWO_WAY:
if ($anchormatch) {
$synctype = ALERT_TWO_WAY;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_SLOW_SYNC;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_NEXT_MESSAGE:
$state->setAlert222Received(true);
case ALERT_RESULT_ALERT:
case ALERT_NO_END_OF_DATA:
// Nothing to do on our side
$status = new Horde_SyncML_Command_Status(RESPONSE_OK, 'Alert');
$status->setCmdRef($this->_cmdID);
if ($this->_sourceLocURI != null) {
$status->setSourceRef($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
}
if ($this->_alert == ALERT_NEXT_MESSAGE) {
if ($this->_sourceLocURI != null) {
$status->setItemSourceLocURI($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setItemTargetLocURI(isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI);
}
}
$currentCmdID = $status->output($currentCmdID, $output);
return $currentCmdID;
case ALERT_TWO_WAY:
if ($anchormatch) {
$synctype = ALERT_TWO_WAY;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_SLOW_SYNC;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_SLOW_SYNC:
$synctype = ALERT_SLOW_SYNC;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
break;
case ALERT_SLOW_SYNC:
$synctype = ALERT_SLOW_SYNC;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
break;
case ALERT_ONE_WAY_FROM_CLIENT:
if ($anchormatch) {
$synctype = ALERT_ONE_WAY_FROM_CLIENT;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_REFRESH_FROM_CLIENT;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_ONE_WAY_FROM_CLIENT:
if ($anchormatch) {
$synctype = ALERT_ONE_WAY_FROM_CLIENT;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_REFRESH_FROM_CLIENT;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_REFRESH_FROM_CLIENT:
$synctype = ALERT_REFRESH_FROM_CLIENT;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
case ALERT_REFRESH_FROM_CLIENT:
$synctype = ALERT_REFRESH_FROM_CLIENT;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
// We will erase the current server content,
// then we can add the client's contents.
// We will erase the current server content,
// then we can add the client's contents.
$hordeType = $state->getHordeType($this->_targetLocURI);
$hordeType = $state->getHordeType($this->_targetLocURI);
$state->setTargetURI($this->_targetLocURI);
$deletes = $state->getClientItems();
if (is_array($deletes)) {
foreach ($deletes as $delete) {
$registry->call($hordeType . '/delete', array($delete));
}
Horde::logMessage("SyncML: RefreshFromClient " . count($deletes) . " entries deleted for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
$anchormatch = false;
break;
$state->setTargetURI($this->_targetLocURI);
$deletes = $state->getClientItems();
if (is_array($deletes)) {
foreach ($deletes as $delete) {
$registry->call($hordeType . '/delete', array($delete));
}
Horde::logMessage("SyncML: RefreshFromClient " . count($deletes) . " entries deleted for $hordeType", __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
$anchormatch = false;
break;
case ALERT_ONE_WAY_FROM_SERVER:
if ($anchormatch) {
$synctype = ALERT_ONE_WAY_FROM_SERVER;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_REFRESH_FROM_SERVER;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_ONE_WAY_FROM_SERVER:
if ($anchormatch) {
$synctype = ALERT_ONE_WAY_FROM_SERVER;
$response = RESPONSE_OK;
} else {
$synctype = ALERT_REFRESH_FROM_SERVER;
$response = RESPONSE_REFRESH_REQUIRED;
}
break;
case ALERT_REFRESH_FROM_SERVER:
$synctype = ALERT_REFRESH_FROM_SERVER;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
break;
case ALERT_REFRESH_FROM_SERVER:
$synctype = ALERT_REFRESH_FROM_SERVER;
$response = $anchormatch ? RESPONSE_OK : RESPONSE_REFRESH_REQUIRED;
break;
case ALERT_RESUME:
// @TODO: Suspend and Resume is not supported yet
$synctype = ALERT_SLOW_SYNC;
$response = RESPONSE_REFRESH_REQUIRED;
break;
case ALERT_RESUME:
// @TODO: Suspend and Resume is not supported yet
$synctype = ALERT_SLOW_SYNC;
$response = RESPONSE_REFRESH_REQUIRED;
break;
default:
// We can't handle this one
Horde::logMessage('SyncML: Unknown sync type ' . $this->_alert,
__FILE__, __LINE__, PEAR_LOG_ERR);
$status = new Horde_SyncML_Command_Status(RESPONSE_BAD_REQUEST, 'Alert');
$status->setCmdRef($this->_cmdID);
if ($this->_sourceLocURI != null) {
$status->setSourceRef($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
}
$currentCmdID = $status->output($currentCmdID, $output);
return $currentCmdID;
default:
// We can't handle this one
Horde::logMessage('SyncML: Unknown sync type ' . $this->_alert,
__FILE__, __LINE__, PEAR_LOG_ERR);
$status = new Horde_SyncML_Command_Status(RESPONSE_BAD_REQUEST, 'Alert');
$status->setCmdRef($this->_cmdID);
if ($this->_sourceLocURI != null) {
$status->setSourceRef($this->_sourceLocURI);
}
if ($this->_targetLocURI != null) {
$status->setTargetRef((isset($this->_targetLocURIParameters) ? $this->_targetLocURI.'?/'.$this->_targetLocURIParameters : $this->_targetLocURI));
}
$currentCmdID = $status->output($currentCmdID, $output);
return $currentCmdID;
}
// Store client's Next Anchor in State and
// set server's Next Anchor. After successful sync
// this is then written to persistence for negotiation of
// further syncs.
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
$serverAnchorNext = time();
$state->setServerAnchorNext($type, $serverAnchorNext);
// Now set interval to retrieve server changes from, defined by
// ServerAnchor [Last,Next]
if ($synctype != ALERT_TWO_WAY &&
@ -305,7 +297,7 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
. $this->_targetLocURI . '; sync type ' . $synctype,
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$sync = &Horde_SyncML_Sync::factory($synctype);
$state->clearConflictItems($this->_targetLocURI);
$state->clearConflictItems($this->_targetLocURI);
}
$sync->setTargetLocURI($this->_targetLocURI);
$sync->setSourceLocURI($this->_sourceLocURI);
@ -313,6 +305,21 @@ class Horde_SyncML_Command_Alert extends Horde_SyncML_Command {
$sync->setsyncType($synctype);
$sync->setFilterExpression($this->_filterExpression);
$state->setSync($this->_targetLocURI, $sync);
$hordeType = $state->getHordeType($this->_targetLocURI);
$changes =& $registry->call($hordeType. '/listBy',
array('action' => 'modify',
'timestamp' => $serverAnchorLast,
'type' => $this->_targetLocURI,
'filter' => $this->_filterExpression));
$state->setChangedItems($this->_targetLocURI, $changes);
// Store client's Next Anchor in State and
// set server's Next Anchor. After successful sync
// this is then written to persistence for negotiation of
// further syncs.
$state->setClientAnchorNext($type, $this->_metaAnchorNext);
$serverAnchorNext = time();
$state->setServerAnchorNext($type, $serverAnchorNext);
$status = new Horde_SyncML_Command_Status($response, 'Alert');
$status->setCmdRef($this->_cmdID);

View File

@ -127,87 +127,92 @@ class Horde_SyncML_Command_Sync extends Horde_SyncML_Command {
function syncToClient($currentCmdID, &$output)
{
Horde::logMessage('SyncML: starting sync to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
Horde::logMessage('SyncML: starting sync to client',
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$state = &$_SESSION['SyncML.state'];
$state = &$_SESSION['SyncML.state'];
if($state->getSyncStatus() >= CLIENT_SYNC_FINNISHED && $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
{
$deviceInfo = $state->getClientDeviceInfo();
$targets = $state->getTargets();
foreach($targets as $target)
{
$sync = &$state->getSync($target);
Horde::logMessage('SyncML['. session_id() .']: sync alerttype '. $sync->_syncType .' found for target ' . $target, __FILE__, __LINE__, PEAR_LOG_DEBUG);
if ($sync->_syncType == ALERT_ONE_WAY_FROM_CLIENT ||
$sync->_syncType == ALERT_REFRESH_FROM_CLIENT) {
Horde::logMessage('SyncML['. session_id() .']: From client Sync, no sync of '. $target .' to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
$state->clearSync($target);
} else if ($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED) {
Horde::logMessage("SyncML: starting sync to client $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
$attrs = array();
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
$output->startElement($state->getURI(), 'Sync', $attrs);
$output->startElement($state->getURI(), 'CmdID', $attrs);
$output->characters($currentCmdID);
$currentCmdID++;
$output->endElement($state->getURI(), 'CmdID');
$output->startElement($state->getURI(), 'Target', $attrs);
$output->startElement($state->getURI(), 'LocURI', $attrs);
$chars = $sync->_sourceLocURI;
$output->characters($chars);
$output->endElement($state->getURI(), 'LocURI');
$output->endElement($state->getURI(), 'Target');
$output->startElement($state->getURI(), 'Source', $attrs);
$output->startElement($state->getURI(), 'LocURI', $attrs);
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
$output->characters($chars);
$output->endElement($state->getURI(), 'LocURI');
$output->endElement($state->getURI(), 'Source');
if(!$sync->_syncDataLoaded)
if ($state->getSyncStatus() >= CLIENT_SYNC_FINNISHED
&& $state->getSyncStatus() < SERVER_SYNC_FINNISHED)
{
$deviceInfo = $state->getClientDeviceInfo();
if (($targets = $state->getTargets())) {
foreach ($targets as $target)
{
$numberOfItems = $sync->loadData();
if($deviceInfo['supportNumberOfChanges'])
{
$output->startElement($state->getURI(), 'NumberOfChanges', $attrs);
$output->characters($numberOfItems);
$output->endElement($state->getURI(), 'NumberOfChanges');
}
$sync = &$state->getSync($target);
Horde::logMessage('SyncML[' . session_id() . ']: sync alerttype ' .
$sync->_syncType . ' found for target ' . $target,
__FILE__, __LINE__, PEAR_LOG_DEBUG);
if ($sync->_syncType == ALERT_ONE_WAY_FROM_CLIENT ||
$sync->_syncType == ALERT_REFRESH_FROM_CLIENT) {
Horde::logMessage('SyncML[' . session_id() .
']: From client Sync, no sync of ' . $target .
' to client', __FILE__, __LINE__, PEAR_LOG_DEBUG);
$state->clearSync($target);
} elseif ($state->getSyncStatus() >= CLIENT_SYNC_ACKNOWLEDGED) {
Horde::logMessage("SyncML: starting sync to client $target",
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$attrs = array();
$state->setSyncStatus(SERVER_SYNC_DATA_PENDING);
$output->startElement($state->getURI(), 'Sync', $attrs);
$output->startElement($state->getURI(), 'CmdID', $attrs);
$output->characters($currentCmdID);
$currentCmdID++;
$output->endElement($state->getURI(), 'CmdID');
$output->startElement($state->getURI(), 'Target', $attrs);
$output->startElement($state->getURI(), 'LocURI', $attrs);
$chars = $sync->_sourceLocURI;
$output->characters($chars);
$output->endElement($state->getURI(), 'LocURI');
$output->endElement($state->getURI(), 'Target');
$output->startElement($state->getURI(), 'Source', $attrs);
$output->startElement($state->getURI(), 'LocURI', $attrs);
$chars = (isset($sync->_targetLocURIParameters) ? $sync->_targetLocURI.'?/'.$sync->_targetLocURIParameters : $sync->_targetLocURI);
$output->characters($chars);
$output->endElement($state->getURI(), 'LocURI');
$output->endElement($state->getURI(), 'Source');
if(!$sync->_syncDataLoaded)
{
$numberOfItems = $sync->loadData();
if($deviceInfo['supportNumberOfChanges'])
{
$output->startElement($state->getURI(), 'NumberOfChanges', $attrs);
$output->characters($numberOfItems);
$output->endElement($state->getURI(), 'NumberOfChanges');
}
}
$currentCmdID = $sync->endSync($currentCmdID, $output);
$output->endElement($state->getURI(), 'Sync');
if (isset($state->curSyncItem) ||
$state->getNumberOfElements() === false) {
break;
}
} else {
Horde::logMessage("SyncML: Waiting for client ACKNOWLEDGE for $target",
__FILE__, __LINE__, PEAR_LOG_DEBUG);
}
}
}
$currentCmdID = $sync->endSync($currentCmdID, $output);
$output->endElement($state->getURI(), 'Sync');
if (isset($state->curSyncItem) ||
$state->getNumberOfElements() === false) {
break;
}
} else {
Horde::logMessage("SyncML: Waiting for client ACKNOWLEDGE for $target", __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
}
// no syncs left
if($state->getTargets() === FALSE &&
!isset($state->curSyncItem)) {
$state->setSyncStatus(SERVER_SYNC_FINNISHED);
}
Horde::logMessage('SyncML: syncStatus(syncToClient) = '. $state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
return $currentCmdID;
// no syncs left
if ($state->getTargets() === false &&
!isset($state->curSyncItem)) {
$state->setSyncStatus(SERVER_SYNC_FINNISHED);
}
Horde::logMessage('SyncML: syncStatus(syncToClient) = ' .
$state->getSyncStatus(), __FILE__, __LINE__, PEAR_LOG_DEBUG);
}
return $currentCmdID;
}
function endElement($uri, $element)

View File

@ -612,7 +612,7 @@ class Horde_SyncML_State {
function getTargets()
{
if(count($this->_syncs) < 1)
return FALSE;
return false;
foreach($this->_syncs as $target => $sync)
{

View File

@ -213,8 +213,9 @@ class EGW_SyncML_State extends Horde_SyncML_State
/**
* returns GUIDs of all client items
*/
function getClientItems() {
$mapID = $this->_locName . $this->_sourceURI . $this->_targetURI;
function getClientItems($type=false) {
if (!$type) $type = $this->_targetURI;
$mapID = $this->_locName . $this->_sourceURI . $type;
$guids = array();
foreach($GLOBALS['egw']->db->select('egw_contentmap', 'map_guid', array(

View File

@ -177,14 +177,8 @@ class Horde_SyncML_Sync {
$sourceURI = $state->getSourceURI();
$hordeType = $state->getHordeType($type);
$serverAnchorLast = $state->getServerAnchorLast($type);
$state->setTargetURI($type);
$changes = array();
// First we get all changes done after the previous sync start
foreach ($registry->call($hordeType. '/listBy',
array('action' => 'modify',
'timestamp' => $serverAnchorLast,
'type' => $type,
'filter' => $this->_filterExpression)) as $change) {
foreach($state->getChangedItems($type) as $change) {
// now we have to remove the ones
// that came from the last sync with this client
$guid_ts = $state->getSyncTSforAction($change, 'modify');

View File

@ -308,21 +308,11 @@ class Horde_SyncML_Sync_SlowSync extends Horde_SyncML_Sync_TwoWaySync {
$hordeType = $state->getHordeType($syncType);
$state->setTargetURI($syncType);
$future = $state->getServerAnchorNext($syncType);
$delta_add = 0;
Horde::logMessage("SyncML: reading added items from database for $hordeType",
__FILE__, __LINE__, PEAR_LOG_DEBUG);
/* The items, which now match the filter criteria are show here, too
$delta_add = count($registry->call($hordeType. '/listBy',
array('action' => 'add',
'timestamp' => $future,
'type' => $syncType,
'filter' => $this->_filterExpression)));
*/
$state->mergeAddedItems($syncType, $registry->call($hordeType. '/list', array('filter' => $this->_filterExpression)));
$this->_syncDataLoaded = TRUE;
return count($state->getAddedItems($syncType)) - $delta_add + count($state->getConflictItems($syncType));
return count($state->getAddedItems($syncType)) + count($state->getConflictItems($syncType));
}
}

View File

@ -409,27 +409,8 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
$state = & $_SESSION['SyncML.state'];
$syncType = $this->_targetLocURI;
$hordeType = $state->getHordeType($syncType);
$state->setTargetURI($syncType);
$refts = $state->getServerAnchorLast($syncType);
$future = $state->getServerAnchorNext($syncType);
$delta_mod = 0;
$delta_add = 0;
Horde :: logMessage("SyncML: reading changed items from database for $hordeType",
__FILE__, __LINE__, PEAR_LOG_DEBUG);
$delta_mod = count($registry->call($hordeType . '/listBy', array (
'action' => 'modify',
'timestamp' => $future,
'type' => $syncType,
'filter' => $this->_filterExpression
)));
$changedItems =& $registry->call($hordeType . '/listBy', array (
'action' => 'modify',
'timestamp' => $refts,
'type' => $syncType,
'filter' => $this->_filterExpression
));
$addedItems =& $registry->call($hordeType . '/listBy', array (
'action' => 'add',
@ -438,12 +419,7 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
'filter' => $this->_filterExpression
));
// added items may show up as changed, too
$changedItems = array_diff($changedItems, $addedItems);
$state->mergeChangedItems($syncType, $changedItems);
$state->mergeAddedItems($syncType, $addedItems);
$state->setAddedItems($syncType, $addedItems);
$state->setDeletedItems($syncType, $registry->call($hordeType . '/listBy', array (
'action' => 'delete',
@ -452,17 +428,8 @@ class Horde_SyncML_Sync_TwoWaySync extends Horde_SyncML_Sync {
'filter' => $this->_filterExpression
)));
/* The items, which now match the filter criteria are show here, too
$delta_add = count($registry->call($hordeType . '/listBy', array (
'action' => 'add',
'timestamp' => $future,
'type' => $syncType,
'filter' => $this->_filterExpression
)));
*/
$this->_syncDataLoaded = TRUE;
return count($state->getChangedItems($syncType)) - $delta_mod + count($state->getDeletedItems($syncType)) + count($state->getAddedItems($syncType)) - $delta_add + count($state->getConflictItems($syncType));
return count($state->getChangedItems($syncType)) + count($state->getDeletedItems($syncType)) + count($state->getAddedItems($syncType)) + count($state->getConflictItems($syncType));
}
}