Horde_ActiveSync_SyncCache::setPingChangeFlag PHP Method

setPingChangeFlag() public method

Set the ping change flag on a collection. Indicatates that the last PING was terminated with a change in this collection.
Since: 2.3.0
public setPingChangeFlag ( string $id )
$id string The collection id.
    public function setPingChangeFlag($id)
    {
        if (empty($this->_data['collections'][$id])) {
            throw new InvalidArgumentException('Collection does not exist.');
        }
        $this->_data['collections'][$id]['pingchange'] = true;
        $this->_markCollectionsDirty($id);
    }

Usage Example

Esempio n. 1
0
 /**
  * Poll the backend for changes.
  *
  * @param integer $heartbeat  The heartbeat lifetime to wait for changes.
  * @param integer $interval   The wait interval between poll iterations.
  * @param array $options      An options array containing any of:
  *   - pingable: (boolean)  Only poll collections with the pingable flag set.
  *                DEFAULT: false
  *
  * @return boolean|integer True if changes were detected in any of the
  *                         collections, false if no changes detected
  *                         or a status code if failed.
  */
 public function pollForChanges($heartbeat, $interval, array $options = array())
 {
     $dataavailable = false;
     $started = time();
     $until = $started + $heartbeat;
     $this->_logger->info(sprintf('Waiting for changes for %s seconds', $heartbeat));
     // If pinging, make sure we have pingable collections. Note we can't
     // filter on them here because the collections might change during the
     // loop below.
     if (!empty($options['pingable']) && !$this->havePingableCollections()) {
         $this->_logger->err('No pingable collections.');
         return self::COLLECTION_ERR_SERVER;
     }
     // Need to update AND SAVE the timestamp for race conditions to be
     // detected.
     $this->lasthbsyncstarted = $started;
     $this->save();
     // We only check for remote wipe request once every 5 iterations to
     // save on DB load since we must reload the device's state each time.
     $rw_check_countdown = 5;
     while (($now = time()) < $until) {
         // Try not to go over the heartbeat interval.
         if ($until - $now < $interval) {
             $interval = $until - $now;
         }
         // See if another process has altered the sync_cache.
         if ($this->checkStaleRequest()) {
             return self::COLLECTION_ERR_STALE;
         }
         // Make sure the collections are still there (there might have been
         // an error in refreshing them from the cache). Ideally this should
         // NEVER happen.
         if (!count($this->_collections)) {
             $this->_logger->err('NO COLLECTIONS! This should not happen!');
             return self::COLLECTION_ERR_SERVER;
         }
         // Check for WIPE request once every 5 iterations to balance between
         // performance and speed of catching a remote wipe request.
         if ($rw_check_countdown-- == 0) {
             $rw_check_countdown = 5;
             if ($this->_as->provisioning != Horde_ActiveSync::PROVISIONING_NONE) {
                 $rwstatus = $this->_as->state->getDeviceRWStatus($this->_as->device->id, true);
                 if ($rwstatus == Horde_ActiveSync::RWSTATUS_PENDING || $rwstatus == Horde_ActiveSync::RWSTATUS_WIPED) {
                     return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
                 }
             }
         }
         // Check each collection we are interested in.
         foreach ($this->_collections as $id => $collection) {
             // Initialize the collection's state data in the state handler.
             try {
                 $this->initCollectionState($collection, true);
             } catch (Horde_ActiveSync_Exception_StateGone $e) {
                 $this->_logger->notice(sprintf('[%s] State not found for %s. Continuing.', $this->_procid, $id));
                 if (!empty($options['pingable'])) {
                     return self::COLLECTION_ERR_PING_NEED_FULL;
                 }
                 $dataavailable = true;
                 $this->setGetChangesFlag($id);
                 continue;
             } catch (Horde_ActiveSync_Exception_InvalidRequest $e) {
                 // Thrown when state is unable to be initialized because the
                 // collection has not yet been synched, but was requested to
                 // be pinged.
                 $this->_logger->err(sprintf('[%s] Unable to initialize state for %s. Ignoring during pollForChanges: %s.', $this->_procid, $id, $e->getMessage()));
                 continue;
             } catch (Horde_ActiveSync_Exception_FolderGone $e) {
                 $this->_logger->warn('Folder gone for collection ' . $collection['id']);
                 return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
             } catch (Horde_ActiveSync_Exception $e) {
                 $this->_logger->err('Error loading state: ' . $e->getMessage());
                 $this->_as->state->loadState(array(), null, Horde_ActiveSync::REQUEST_TYPE_SYNC, $id);
                 $this->setGetChangesFlag($id);
                 $dataavailable = true;
                 continue;
             }
             if (!empty($options['pingable']) && !$this->_cache->collectionIsPingable($id)) {
                 $this->_logger->notice(sprintf('[%s] Skipping %s because it is not PINGable.', $this->_procid, $id));
                 continue;
             }
             try {
                 if ($cnt = $this->getCollectionChangeCount(true)) {
                     $dataavailable = true;
                     $this->setGetChangesFlag($id);
                     if (!empty($options['pingable'])) {
                         $this->_cache->setPingChangeFlag($id);
                     }
                 } else {
                     try {
                         $this->_as->state->updateSyncStamp();
                     } catch (Horde_ActiveSync_Exception $e) {
                         $this->_logger->err($e->getMessage());
                     }
                 }
             } catch (Horde_ActiveSync_Exception_StaleState $e) {
                 $this->_logger->notice(sprintf('[%s] SYNC terminating and force-clearing device state: %s', $this->_procid, $e->getMessage()));
                 $this->_as->state->loadState(array(), null, Horde_ActiveSync::REQUEST_TYPE_SYNC, $id);
                 $this->setGetChangesFlag($id);
                 $dataavailable = true;
             } catch (Horde_ActiveSync_Exception_FolderGone $e) {
                 $this->_logger->notice(sprintf('[%s] SYNC terminating: %s', $this->_procid, $e->getMessage()));
                 // If we are missing a folder, we should clear the PING
                 // cache also, to be sure it picks up any hierarchy changes
                 // since most clients don't seem smart enough to figure this
                 // out on their own.
                 $this->resetPingCache();
                 return self::COLLECTION_ERR_FOLDERSYNC_REQUIRED;
             } catch (Horde_Exception_AuthenticationFailure $e) {
                 // We lost authentication for some reason.
                 $this->_logger->err(sprintf('[%s] Authentication lost during PING!!', $this->_procid));
                 return self::COLLECTION_ERR_AUTHENTICATION;
             } catch (Horde_ActiveSync_Exception $e) {
                 $this->_logger->err(sprintf('[%s] Sync object cannot be configured, throttling: %s', $this->_procid, $e->getMessage()));
                 $this->_sleep(30);
                 continue;
             }
         }
         if (!empty($dataavailable)) {
             $this->_logger->info(sprintf('[%s] Found changes!', $this->_procid));
             break;
         }
         // Wait a bit...
         $this->_sleep($interval);
         // Refresh the collections.
         $this->updateCollectionsFromCache();
     }
     // Check that no other Sync process already started
     // If so, we exit here and let the other process do the export.
     if ($this->checkStaleRequest()) {
         $this->_logger->info('Changes in cache determined during Sync Wait/Heartbeat, exiting here.');
         return self::COLLECTION_ERR_STALE;
     }
     $this->_logger->info(sprintf('[%s] Looping Sync complete: DataAvailable: %s, DataImported: %s', $this->_procid, $dataavailable, $this->importedChanges));
     return $dataavailable;
 }