public function canAcquireLeaseOnResource(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease)
 {
     if (!DrydockSlotLock::isLockFree($this->getLeaseSlotLock($resource))) {
         return false;
     }
     return true;
 }
 public function canAcquireLeaseOnResource(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease)
 {
     $need_map = $lease->getAttribute('repositories.map');
     if (!is_array($need_map)) {
         return false;
     }
     $have_map = $resource->getAttribute('repositories.map');
     if (!is_array($have_map)) {
         return false;
     }
     $have_as = ipull($have_map, 'phid');
     $need_as = ipull($need_map, 'phid');
     foreach ($need_as as $need_directory => $need_phid) {
         if (empty($have_as[$need_directory])) {
             // This resource is missing a required working copy.
             return false;
         }
         if ($have_as[$need_directory] != $need_phid) {
             // This resource has a required working copy, but it contains
             // the wrong repository.
             return false;
         }
         unset($have_as[$need_directory]);
     }
     if ($have_as && $lease->getAttribute('repositories.strict')) {
         // This resource has extra repositories, but the lease is strict about
         // which repositories are allowed to exist.
         return false;
     }
     if (!DrydockSlotLock::isLockFree($this->getLeaseSlotLock($resource))) {
         return false;
     }
     return true;
 }
 protected function buildLocksTab($owner_phid)
 {
     $locks = DrydockSlotLock::loadLocks($owner_phid);
     $rows = array();
     foreach ($locks as $lock) {
         $rows[] = array($lock->getID(), $lock->getLockKey());
     }
     $table = id(new AphrontTableView($rows))->setNoDataString(pht('No slot locks held.'))->setHeaders(array(pht('ID'), pht('Lock Key')))->setColumnClasses(array(null, 'wide'));
     return id(new PHUIPropertyListView())->addRawContent($table);
 }
 public function canAcquireLeaseOnResource(DrydockBlueprint $blueprint, DrydockResource $resource, DrydockLease $lease)
 {
     $have_phid = $resource->getAttribute('repositoryPHID');
     $need_phid = $lease->getAttribute('repositoryPHID');
     if ($need_phid !== $have_phid) {
         return false;
     }
     if (!DrydockSlotLock::isLockFree($this->getLeaseSlotLock($resource))) {
         return false;
     }
     return true;
 }
 private function releaseLease(DrydockLease $lease)
 {
     $lease->openTransaction();
     $lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED)->save();
     // TODO: Hold slot locks until destruction?
     DrydockSlotLock::releaseLocks($lease->getPHID());
     $lease->saveTransaction();
     PhabricatorWorker::scheduleTask('DrydockLeaseDestroyWorker', array('leasePHID' => $lease->getPHID()), array('objectPHID' => $lease->getPHID()));
     $resource = $lease->getResource();
     $blueprint = $resource->getBlueprint();
     $blueprint->didReleaseLease($resource, $lease);
 }
 private function releaseResource(DrydockResource $resource)
 {
     if ($resource->getStatus() != DrydockResourceStatus::STATUS_ACTIVE) {
         // If we had multiple release commands
         // This command is only meaningful to resources in the "Open" state.
         return;
     }
     $viewer = $this->getViewer();
     $drydock_phid = id(new PhabricatorDrydockApplication())->getPHID();
     $resource->openTransaction();
     $resource->setStatus(DrydockResourceStatus::STATUS_RELEASED)->save();
     // TODO: Hold slot locks until destruction?
     DrydockSlotLock::releaseLocks($resource->getPHID());
     $resource->saveTransaction();
     $statuses = array(DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACQUIRED, DrydockLeaseStatus::STATUS_ACTIVE);
     $leases = id(new DrydockLeaseQuery())->setViewer($viewer)->withResourcePHIDs(array($resource->getPHID()))->withStatuses($statuses)->execute();
     foreach ($leases as $lease) {
         $command = DrydockCommand::initializeNewCommand($viewer)->setTargetPHID($lease->getPHID())->setAuthorPHID($drydock_phid)->setCommand(DrydockCommand::COMMAND_RELEASE)->save();
         $lease->scheduleUpdate();
     }
     PhabricatorWorker::scheduleTask('DrydockResourceDestroyWorker', array('resourcePHID' => $resource->getPHID()), array('objectPHID' => $resource->getPHID()));
 }
 /**
  * @task destroy
  */
 private function destroyLease(DrydockLease $lease)
 {
     $resource = $lease->getResource();
     if ($resource) {
         $blueprint = $resource->getBlueprint();
         $blueprint->destroyLease($resource, $lease);
     }
     DrydockSlotLock::releaseLocks($lease->getPHID());
     $lease->setStatus(DrydockLeaseStatus::STATUS_DESTROYED)->save();
     $lease->logEvent(DrydockLeaseDestroyedLogType::LOGCONST);
     $lease->awakenTasks();
 }
Example #8
0
 public function activateOnResource(DrydockResource $resource)
 {
     $expect_status = DrydockLeaseStatus::STATUS_ACQUIRED;
     $actual_status = $this->getStatus();
     if ($actual_status != $expect_status) {
         throw new Exception(pht('Trying to activate a lease which has the wrong status: status ' . 'must be "%s", actually "%s".', $expect_status, $actual_status));
     }
     if ($resource->getStatus() == DrydockResourceStatus::STATUS_PENDING) {
         // TODO: Be stricter about this?
         throw new Exception(pht('Trying to activate a lease on a pending resource.'));
     }
     $this->openTransaction();
     $this->setStatus(DrydockLeaseStatus::STATUS_ACTIVE)->save();
     DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
     $this->slotLocks = array();
     $this->saveTransaction();
     $this->isActivated = true;
     $this->didActivate();
     return $this;
 }
 /**
  * @task destroy
  */
 private function destroyResource(DrydockResource $resource)
 {
     $blueprint = $resource->getBlueprint();
     $blueprint->destroyResource($resource);
     DrydockSlotLock::releaseLocks($resource->getPHID());
     $resource->setStatus(DrydockResourceStatus::STATUS_DESTROYED)->save();
 }
 protected function getConcurrentResourceLimitSlotLock(DrydockBlueprint $blueprint)
 {
     $limit = $this->getConcurrentResourceLimit($blueprint);
     if ($limit === null) {
         return;
     }
     $blueprint_phid = $blueprint->getPHID();
     // TODO: This logic shouldn't do anything awful, but is a little silly. It
     // would be nice to unify the "huge limit" and "small limit" cases
     // eventually but it's a little tricky.
     // If the limit is huge, just pick a random slot. This is just stopping
     // us from exploding if someone types a billion zillion into the box.
     if ($limit > 1024) {
         $slot = mt_rand(0, $limit - 1);
         return "allocator({$blueprint_phid}).limit({$slot})";
     }
     // For reasonable limits, actually check for an available slot.
     $locks = DrydockSlotLock::loadLocks($blueprint_phid);
     $locks = mpull($locks, null, 'getLockKey');
     $slots = range(0, $limit - 1);
     shuffle($slots);
     foreach ($slots as $slot) {
         $slot_lock = "allocator({$blueprint_phid}).limit({$slot})";
         if (empty($locks[$slot_lock])) {
             return $slot_lock;
         }
     }
     // If we found no free slot, just return whatever we checked last (which
     // is just a random slot). There's a small chance we'll get lucky and the
     // lock will be free by the time we try to take it, but usually we'll just
     // fail to grab the lock, throw an appropriate lock exception, and get back
     // on the right path to retry later.
     return $slot_lock;
 }
Example #11
0
 public function activateResource()
 {
     if (!$this->getID()) {
         throw new Exception(pht('Trying to activate a resource which has not yet been persisted.'));
     }
     $expect_status = DrydockResourceStatus::STATUS_PENDING;
     $actual_status = $this->getStatus();
     if ($actual_status != $expect_status) {
         throw new Exception(pht('Trying to activate a resource from the wrong status. Status must ' . 'be "%s", actually "%s".', $expect_status, $actual_status));
     }
     $this->openTransaction();
     $this->setStatus(DrydockResourceStatus::STATUS_ACTIVE)->save();
     DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
     $this->slotLocks = array();
     $this->saveTransaction();
     $this->isActivated = true;
     return $this;
 }
 public function closeResource()
 {
     // TODO: This is super broken and will race other lease writers!
     $this->openTransaction();
     $statuses = array(DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACTIVE);
     $leases = id(new DrydockLeaseQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withResourceIDs(array($this->getID()))->withStatuses($statuses)->execute();
     foreach ($leases as $lease) {
         switch ($lease->getStatus()) {
             case DrydockLeaseStatus::STATUS_PENDING:
                 $message = pht('Breaking pending lease (resource closing).');
                 $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN);
                 break;
             case DrydockLeaseStatus::STATUS_ACTIVE:
                 $message = pht('Releasing active lease (resource closing).');
                 $lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
                 break;
         }
         DrydockBlueprintImplementation::writeLog($this, $lease, $message);
         $lease->save();
     }
     $this->setStatus(DrydockResourceStatus::STATUS_CLOSED);
     $this->save();
     DrydockSlotLock::releaseLocks($this->getPHID());
     $this->saveTransaction();
 }
Example #13
0
 /**
  * Release all locks held by an owner.
  *
  * @param phid Lock owner PHID.
  * @return void
  * @task locks
  */
 public static function releaseLocks($owner_phid)
 {
     $table = new DrydockSlotLock();
     $conn_w = $table->establishConnection('w');
     queryfx($conn_w, 'DELETE FROM %T WHERE ownerPHID = %s', $table->getTableName(), $owner_phid);
 }
Example #14
0
 public function activateResource()
 {
     if (!$this->getID()) {
         throw new Exception(pht('Trying to activate a resource which has not yet been persisted.'));
     }
     $expect_status = DrydockResourceStatus::STATUS_PENDING;
     $actual_status = $this->getStatus();
     if ($actual_status != $expect_status) {
         throw new Exception(pht('Trying to activate a resource from the wrong status. Status must ' . 'be "%s", actually "%s".', $expect_status, $actual_status));
     }
     $this->openTransaction();
     try {
         DrydockSlotLock::acquireLocks($this->getPHID(), $this->slotLocks);
         $this->slotLocks = array();
     } catch (DrydockSlotLockException $ex) {
         $this->killTransaction();
         $this->logEvent(DrydockSlotLockFailureLogType::LOGCONST, array('locks' => $ex->getLockMap()));
         throw $ex;
     }
     $this->setStatus(DrydockResourceStatus::STATUS_ACTIVE)->save();
     $this->saveTransaction();
     $this->isActivated = true;
     $this->didActivate();
     return $this;
 }