[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/drydock/storage/ -> DrydockLease.php (source)

   1  <?php
   2  
   3  final class DrydockLease extends DrydockDAO
   4    implements PhabricatorPolicyInterface {
   5  
   6    protected $resourceID;
   7    protected $resourceType;
   8    protected $until;
   9    protected $ownerPHID;
  10    protected $attributes = array();
  11    protected $status = DrydockLeaseStatus::STATUS_PENDING;
  12    protected $taskID;
  13  
  14    private $resource = self::ATTACHABLE;
  15    private $releaseOnDestruction;
  16  
  17    /**
  18     * Flag this lease to be released when its destructor is called. This is
  19     * mostly useful if you have a script which acquires, uses, and then releases
  20     * a lease, as you don't need to explicitly handle exceptions to properly
  21     * release the lease.
  22     */
  23    public function releaseOnDestruction() {
  24      $this->releaseOnDestruction = true;
  25      return $this;
  26    }
  27  
  28    public function __destruct() {
  29      if ($this->releaseOnDestruction) {
  30        if ($this->isActive()) {
  31          $this->release();
  32        }
  33      }
  34    }
  35  
  36    public function getLeaseName() {
  37      return pht('Lease %d', $this->getID());
  38    }
  39  
  40    public function getConfiguration() {
  41      return array(
  42        self::CONFIG_AUX_PHID => true,
  43        self::CONFIG_SERIALIZATION => array(
  44          'attributes'    => self::SERIALIZATION_JSON,
  45        ),
  46        self::CONFIG_COLUMN_SCHEMA => array(
  47          'status' => 'uint32',
  48          'until' => 'epoch?',
  49          'resourceType' => 'text128',
  50          'taskID' => 'id?',
  51          'ownerPHID' => 'phid?',
  52          'resourceID' => 'id?',
  53        ),
  54        self::CONFIG_KEY_SCHEMA => array(
  55          'key_phid' => null,
  56          'phid' => array(
  57            'columns' => array('phid'),
  58            'unique' => true,
  59          ),
  60        ),
  61      ) + parent::getConfiguration();
  62    }
  63  
  64    public function setAttribute($key, $value) {
  65      $this->attributes[$key] = $value;
  66      return $this;
  67    }
  68  
  69    public function getAttribute($key, $default = null) {
  70      return idx($this->attributes, $key, $default);
  71    }
  72  
  73    public function generatePHID() {
  74      return PhabricatorPHID::generateNewPHID(DrydockLeasePHIDType::TYPECONST);
  75    }
  76  
  77    public function getInterface($type) {
  78      return $this->getResource()->getInterface($this, $type);
  79    }
  80  
  81    public function getResource() {
  82      return $this->assertAttached($this->resource);
  83    }
  84  
  85    public function attachResource(DrydockResource $resource = null) {
  86      $this->resource = $resource;
  87      return $this;
  88    }
  89  
  90    public function hasAttachedResource() {
  91      return ($this->resource !== null);
  92    }
  93  
  94    public function loadResource() {
  95      return id(new DrydockResource())->loadOneWhere(
  96        'id = %d',
  97        $this->getResourceID());
  98    }
  99  
 100    public function queueForActivation() {
 101      if ($this->getID()) {
 102        throw new Exception(
 103          'Only new leases may be queued for activation!');
 104      }
 105  
 106      $this->setStatus(DrydockLeaseStatus::STATUS_PENDING);
 107      $this->save();
 108  
 109      $task = PhabricatorWorker::scheduleTask(
 110        'DrydockAllocatorWorker',
 111        $this->getID());
 112  
 113      // NOTE: Scheduling the task might execute it in-process, if we're running
 114      // from a CLI script. Reload the lease to make sure we have the most
 115      // up-to-date information. Normally, this has no effect.
 116      $this->reload();
 117  
 118      $this->setTaskID($task->getID());
 119      $this->save();
 120  
 121      return $this;
 122    }
 123  
 124    public function release() {
 125      $this->assertActive();
 126      $this->setStatus(DrydockLeaseStatus::STATUS_RELEASED);
 127      $this->save();
 128  
 129      $this->resource = null;
 130  
 131      return $this;
 132    }
 133  
 134    public function isActive() {
 135      switch ($this->status) {
 136        case DrydockLeaseStatus::STATUS_ACTIVE:
 137        case DrydockLeaseStatus::STATUS_ACQUIRING:
 138          return true;
 139      }
 140      return false;
 141    }
 142  
 143    private function assertActive() {
 144      if (!$this->isActive()) {
 145        throw new Exception(
 146          'Lease is not active! You can not interact with resources through '.
 147          'an inactive lease.');
 148      }
 149    }
 150  
 151    public static function waitForLeases(array $leases) {
 152      assert_instances_of($leases, 'DrydockLease');
 153  
 154      $task_ids = array_filter(mpull($leases, 'getTaskID'));
 155  
 156      PhabricatorWorker::waitForTasks($task_ids);
 157  
 158      $unresolved = $leases;
 159      while (true) {
 160        foreach ($unresolved as $key => $lease) {
 161          $lease->reload();
 162          switch ($lease->getStatus()) {
 163            case DrydockLeaseStatus::STATUS_ACTIVE:
 164              unset($unresolved[$key]);
 165              break;
 166            case DrydockLeaseStatus::STATUS_RELEASED:
 167              throw new Exception('Lease has already been released!');
 168            case DrydockLeaseStatus::STATUS_EXPIRED:
 169              throw new Exception('Lease has already expired!');
 170            case DrydockLeaseStatus::STATUS_BROKEN:
 171              throw new Exception('Lease has been broken!');
 172            case DrydockLeaseStatus::STATUS_PENDING:
 173            case DrydockLeaseStatus::STATUS_ACQUIRING:
 174              break;
 175            default:
 176              throw new Exception('Unknown status??');
 177          }
 178        }
 179  
 180        if ($unresolved) {
 181          sleep(1);
 182        } else {
 183          break;
 184        }
 185      }
 186  
 187      foreach ($leases as $lease) {
 188        $lease->attachResource($lease->loadResource());
 189      }
 190    }
 191  
 192    public function waitUntilActive() {
 193      if (!$this->getID()) {
 194        $this->queueForActivation();
 195      }
 196  
 197      self::waitForLeases(array($this));
 198      return $this;
 199    }
 200  
 201  
 202  /* -(  PhabricatorPolicyInterface  )----------------------------------------- */
 203  
 204  
 205    public function getCapabilities() {
 206      return array(
 207        PhabricatorPolicyCapability::CAN_VIEW,
 208      );
 209    }
 210  
 211    public function getPolicy($capability) {
 212      if ($this->getResource()) {
 213        return $this->getResource()->getPolicy($capability);
 214      }
 215      return PhabricatorPolicies::getMostOpenPolicy();
 216    }
 217  
 218    public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
 219      if ($this->getResource()) {
 220        return $this->getResource()->hasAutomaticCapability($capability, $viewer);
 221      }
 222      return false;
 223    }
 224  
 225    public function describeAutomaticCapability($capability) {
 226      return pht('Leases inherit policies from the resources they lease.');
 227    }
 228  
 229  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1