Path: blob/master/src/applications/drydock/storage/DrydockSlotLock.php
12256 views
<?php12/**3* Simple optimistic locks for Drydock resources and leases.4*5* Most blueprints only need very simple locks: for example, a host blueprint6* might not want to create multiple resources representing the same physical7* machine. These optimistic "slot locks" provide a flexible way to do this8* sort of simple locking.9*10* @task info Getting Lock Information11* @task lock Acquiring and Releasing Locks12*/13final class DrydockSlotLock extends DrydockDAO {1415protected $ownerPHID;16protected $lockIndex;17protected $lockKey;1819protected function getConfiguration() {20return array(21self::CONFIG_TIMESTAMPS => false,22self::CONFIG_COLUMN_SCHEMA => array(23'lockIndex' => 'bytes12',24'lockKey' => 'text',25),26self::CONFIG_KEY_SCHEMA => array(27'key_lock' => array(28'columns' => array('lockIndex'),29'unique' => true,30),31'key_owner' => array(32'columns' => array('ownerPHID'),33),34),35) + parent::getConfiguration();36}373839/* -( Getting Lock Information )------------------------------------------- */404142/**43* Load all locks held by a particular owner.44*45* @param phid Owner PHID.46* @return list<DrydockSlotLock> All held locks.47* @task info48*/49public static function loadLocks($owner_phid) {50return id(new DrydockSlotLock())->loadAllWhere(51'ownerPHID = %s',52$owner_phid);53}545556/**57* Test if a lock is currently free.58*59* @param string Lock key to test.60* @return bool True if the lock is currently free.61* @task info62*/63public static function isLockFree($lock) {64return self::areLocksFree(array($lock));65}666768/**69* Test if a list of locks are all currently free.70*71* @param list<string> List of lock keys to test.72* @return bool True if all locks are currently free.73* @task info74*/75public static function areLocksFree(array $locks) {76$lock_map = self::loadHeldLocks($locks);77return !$lock_map;78}798081/**82* Load named locks.83*84* @param list<string> List of lock keys to load.85* @return list<DrydockSlotLock> List of held locks.86* @task info87*/88public static function loadHeldLocks(array $locks) {89if (!$locks) {90return array();91}9293$table = new DrydockSlotLock();94$conn_r = $table->establishConnection('r');9596$indexes = array();97foreach ($locks as $lock) {98$indexes[] = PhabricatorHash::digestForIndex($lock);99}100101return id(new DrydockSlotLock())->loadAllWhere(102'lockIndex IN (%Ls)',103$indexes);104}105106107/* -( Acquiring and Releasing Locks )-------------------------------------- */108109110/**111* Acquire a set of slot locks.112*113* This method either acquires all the locks or throws an exception (usually114* because one or more locks are held).115*116* @param phid Lock owner PHID.117* @param list<string> List of locks to acquire.118* @return void119* @task locks120*/121public static function acquireLocks($owner_phid, array $locks) {122if (!$locks) {123return;124}125126$table = new DrydockSlotLock();127$conn_w = $table->establishConnection('w');128129$sql = array();130foreach ($locks as $lock) {131$sql[] = qsprintf(132$conn_w,133'(%s, %s, %s)',134$owner_phid,135PhabricatorHash::digestForIndex($lock),136$lock);137}138139try {140queryfx(141$conn_w,142'INSERT INTO %T (ownerPHID, lockIndex, lockKey) VALUES %LQ',143$table->getTableName(),144$sql);145} catch (AphrontDuplicateKeyQueryException $ex) {146// Try to improve the readability of the exception. We might miss on147// this query if the lock has already been released, but most of the148// time we should be able to figure out which locks are already held.149$held = self::loadHeldLocks($locks);150$held = mpull($held, 'getOwnerPHID', 'getLockKey');151152throw new DrydockSlotLockException($held);153}154}155156157/**158* Release all locks held by an owner.159*160* @param phid Lock owner PHID.161* @return void162* @task locks163*/164public static function releaseLocks($owner_phid) {165$table = new DrydockSlotLock();166$conn_w = $table->establishConnection('w');167168queryfx(169$conn_w,170'DELETE FROM %T WHERE ownerPHID = %s',171$table->getTableName(),172$owner_phid);173}174175}176177178