Generate file attachment transactions for explicit Remarkup attachments on common...
[phabricator.git] / src / applications / drydock / storage / DrydockSlotLock.php
blob7a9bce8b3fcd629d9c8809c0061b2f67ff921cdf
1 <?php
3 /**
4 * Simple optimistic locks for Drydock resources and leases.
6 * Most blueprints only need very simple locks: for example, a host blueprint
7 * might not want to create multiple resources representing the same physical
8 * machine. These optimistic "slot locks" provide a flexible way to do this
9 * sort of simple locking.
11 * @task info Getting Lock Information
12 * @task lock Acquiring and Releasing Locks
14 final class DrydockSlotLock extends DrydockDAO {
16 protected $ownerPHID;
17 protected $lockIndex;
18 protected $lockKey;
20 protected function getConfiguration() {
21 return array(
22 self::CONFIG_TIMESTAMPS => false,
23 self::CONFIG_COLUMN_SCHEMA => array(
24 'lockIndex' => 'bytes12',
25 'lockKey' => 'text',
27 self::CONFIG_KEY_SCHEMA => array(
28 'key_lock' => array(
29 'columns' => array('lockIndex'),
30 'unique' => true,
32 'key_owner' => array(
33 'columns' => array('ownerPHID'),
36 ) + parent::getConfiguration();
40 /* -( Getting Lock Information )------------------------------------------- */
43 /**
44 * Load all locks held by a particular owner.
46 * @param phid Owner PHID.
47 * @return list<DrydockSlotLock> All held locks.
48 * @task info
50 public static function loadLocks($owner_phid) {
51 return id(new DrydockSlotLock())->loadAllWhere(
52 'ownerPHID = %s',
53 $owner_phid);
57 /**
58 * Test if a lock is currently free.
60 * @param string Lock key to test.
61 * @return bool True if the lock is currently free.
62 * @task info
64 public static function isLockFree($lock) {
65 return self::areLocksFree(array($lock));
69 /**
70 * Test if a list of locks are all currently free.
72 * @param list<string> List of lock keys to test.
73 * @return bool True if all locks are currently free.
74 * @task info
76 public static function areLocksFree(array $locks) {
77 $lock_map = self::loadHeldLocks($locks);
78 return !$lock_map;
82 /**
83 * Load named locks.
85 * @param list<string> List of lock keys to load.
86 * @return list<DrydockSlotLock> List of held locks.
87 * @task info
89 public static function loadHeldLocks(array $locks) {
90 if (!$locks) {
91 return array();
94 $table = new DrydockSlotLock();
95 $conn_r = $table->establishConnection('r');
97 $indexes = array();
98 foreach ($locks as $lock) {
99 $indexes[] = PhabricatorHash::digestForIndex($lock);
102 return id(new DrydockSlotLock())->loadAllWhere(
103 'lockIndex IN (%Ls)',
104 $indexes);
108 /* -( Acquiring and Releasing Locks )-------------------------------------- */
112 * Acquire a set of slot locks.
114 * This method either acquires all the locks or throws an exception (usually
115 * because one or more locks are held).
117 * @param phid Lock owner PHID.
118 * @param list<string> List of locks to acquire.
119 * @return void
120 * @task locks
122 public static function acquireLocks($owner_phid, array $locks) {
123 if (!$locks) {
124 return;
127 $table = new DrydockSlotLock();
128 $conn_w = $table->establishConnection('w');
130 $sql = array();
131 foreach ($locks as $lock) {
132 $sql[] = qsprintf(
133 $conn_w,
134 '(%s, %s, %s)',
135 $owner_phid,
136 PhabricatorHash::digestForIndex($lock),
137 $lock);
140 try {
141 queryfx(
142 $conn_w,
143 'INSERT INTO %T (ownerPHID, lockIndex, lockKey) VALUES %LQ',
144 $table->getTableName(),
145 $sql);
146 } catch (AphrontDuplicateKeyQueryException $ex) {
147 // Try to improve the readability of the exception. We might miss on
148 // this query if the lock has already been released, but most of the
149 // time we should be able to figure out which locks are already held.
150 $held = self::loadHeldLocks($locks);
151 $held = mpull($held, 'getOwnerPHID', 'getLockKey');
153 throw new DrydockSlotLockException($held);
159 * Release all locks held by an owner.
161 * @param phid Lock owner PHID.
162 * @return void
163 * @task locks
165 public static function releaseLocks($owner_phid) {
166 $table = new DrydockSlotLock();
167 $conn_w = $table->establishConnection('w');
169 queryfx(
170 $conn_w,
171 'DELETE FROM %T WHERE ownerPHID = %s',
172 $table->getTableName(),
173 $owner_phid);