/**
  * Load the pull frequency for this repository, based on the time since the
  * last activity.
  *
  * We pull rarely used repositories less frequently. This finds the most
  * recent commit which is older than the current time (which prevents us from
  * spinning on repositories with a silly commit post-dated to some time in
  * 2037). We adjust the pull frequency based on when the most recent commit
  * occurred.
  *
  * @param   int   The minimum update interval to use, in seconds.
  * @return  int   Repository update interval, in seconds.
  */
 public function loadUpdateInterval($minimum = 15)
 {
     // First, check if we've hit errors recently. If we have, wait one period
     // for each consecutive error. Normally, this corresponds to a backoff of
     // 15s, 30s, 45s, etc.
     $message_table = new PhabricatorRepositoryStatusMessage();
     $conn = $message_table->establishConnection('r');
     $error_count = queryfx_one($conn, 'SELECT MAX(messageCount) error_count FROM %T
     WHERE repositoryID = %d
     AND statusType IN (%Ls)
     AND statusCode IN (%Ls)', $message_table->getTableName(), $this->getID(), array(PhabricatorRepositoryStatusMessage::TYPE_INIT, PhabricatorRepositoryStatusMessage::TYPE_FETCH), array(PhabricatorRepositoryStatusMessage::CODE_ERROR));
     $error_count = (int) $error_count['error_count'];
     if ($error_count > 0) {
         return (int) ($minimum * $error_count);
     }
     // If a repository is still importing, always pull it as frequently as
     // possible. This prevents us from hanging for a long time at 99.9% when
     // importing an inactive repository.
     if ($this->isImporting()) {
         return $minimum;
     }
     $window_start = PhabricatorTime::getNow() + $minimum;
     $table = id(new PhabricatorRepositoryCommit());
     $last_commit = queryfx_one($table->establishConnection('r'), 'SELECT epoch FROM %T
     WHERE repositoryID = %d AND epoch <= %d
     ORDER BY epoch DESC LIMIT 1', $table->getTableName(), $this->getID(), $window_start);
     if ($last_commit) {
         $time_since_commit = $window_start - $last_commit['epoch'];
     } else {
         // If the repository has no commits, treat the creation date as
         // though it were the date of the last commit. This makes empty
         // repositories update quickly at first but slow down over time
         // if they don't see any activity.
         $time_since_commit = $window_start - $this->getDateCreated();
     }
     $last_few_days = phutil_units('3 days in seconds');
     if ($time_since_commit <= $last_few_days) {
         // For repositories with activity in the recent past, we wait one
         // extra second for every 10 minutes since the last commit. This
         // shorter backoff is intended to handle weekends and other short
         // breaks from development.
         $smart_wait = $time_since_commit / 600;
     } else {
         // For repositories without recent activity, we wait one extra second
         // for every 4 minutes since the last commit. This longer backoff
         // handles rarely used repositories, up to the maximum.
         $smart_wait = $time_since_commit / 240;
     }
     // We'll never wait more than 6 hours to pull a repository.
     $longest_wait = phutil_units('6 hours in seconds');
     $smart_wait = min($smart_wait, $longest_wait);
     $smart_wait = max($minimum, $smart_wait);
     return (int) $smart_wait;
 }
 public function writeStatusMessage($status_type, $status_code, array $parameters = array())
 {
     $table = new PhabricatorRepositoryStatusMessage();
     $conn_w = $table->establishConnection('w');
     $table_name = $table->getTableName();
     if ($status_code === null) {
         queryfx($conn_w, 'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s', $table_name, $this->getID(), $status_type);
     } else {
         queryfx($conn_w, 'INSERT INTO %T
       (repositoryID, statusType, statusCode, parameters, epoch)
       VALUES (%d, %s, %s, %s, %d)
       ON DUPLICATE KEY UPDATE
         statusCode = VALUES(statusCode),
         parameters = VALUES(parameters),
         epoch = VALUES(epoch)', $table_name, $this->getID(), $status_type, $status_code, json_encode($parameters), time());
     }
     return $this;
 }
 /**
  * @task pull
  */
 private function loadLastUpdate(PhabricatorRepository $repository)
 {
     $table = new PhabricatorRepositoryStatusMessage();
     $conn = $table->establishConnection('r');
     $epoch = queryfx_one($conn, 'SELECT MAX(epoch) last_update FROM %T
     WHERE repositoryID = %d
       AND statusType IN (%Ls)', $table->getTableName(), $repository->getID(), array(PhabricatorRepositoryStatusMessage::TYPE_INIT, PhabricatorRepositoryStatusMessage::TYPE_FETCH));
     if ($epoch) {
         return (int) $epoch['last_update'];
     }
     return PhabricatorTime::getNow();
 }