Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/drydock/storage/DrydockSlotLock.php
12256 views
1
<?php
2
3
/**
4
* Simple optimistic locks for Drydock resources and leases.
5
*
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.
10
*
11
* @task info Getting Lock Information
12
* @task lock Acquiring and Releasing Locks
13
*/
14
final class DrydockSlotLock extends DrydockDAO {
15
16
protected $ownerPHID;
17
protected $lockIndex;
18
protected $lockKey;
19
20
protected function getConfiguration() {
21
return array(
22
self::CONFIG_TIMESTAMPS => false,
23
self::CONFIG_COLUMN_SCHEMA => array(
24
'lockIndex' => 'bytes12',
25
'lockKey' => 'text',
26
),
27
self::CONFIG_KEY_SCHEMA => array(
28
'key_lock' => array(
29
'columns' => array('lockIndex'),
30
'unique' => true,
31
),
32
'key_owner' => array(
33
'columns' => array('ownerPHID'),
34
),
35
),
36
) + parent::getConfiguration();
37
}
38
39
40
/* -( Getting Lock Information )------------------------------------------- */
41
42
43
/**
44
* Load all locks held by a particular owner.
45
*
46
* @param phid Owner PHID.
47
* @return list<DrydockSlotLock> All held locks.
48
* @task info
49
*/
50
public static function loadLocks($owner_phid) {
51
return id(new DrydockSlotLock())->loadAllWhere(
52
'ownerPHID = %s',
53
$owner_phid);
54
}
55
56
57
/**
58
* Test if a lock is currently free.
59
*
60
* @param string Lock key to test.
61
* @return bool True if the lock is currently free.
62
* @task info
63
*/
64
public static function isLockFree($lock) {
65
return self::areLocksFree(array($lock));
66
}
67
68
69
/**
70
* Test if a list of locks are all currently free.
71
*
72
* @param list<string> List of lock keys to test.
73
* @return bool True if all locks are currently free.
74
* @task info
75
*/
76
public static function areLocksFree(array $locks) {
77
$lock_map = self::loadHeldLocks($locks);
78
return !$lock_map;
79
}
80
81
82
/**
83
* Load named locks.
84
*
85
* @param list<string> List of lock keys to load.
86
* @return list<DrydockSlotLock> List of held locks.
87
* @task info
88
*/
89
public static function loadHeldLocks(array $locks) {
90
if (!$locks) {
91
return array();
92
}
93
94
$table = new DrydockSlotLock();
95
$conn_r = $table->establishConnection('r');
96
97
$indexes = array();
98
foreach ($locks as $lock) {
99
$indexes[] = PhabricatorHash::digestForIndex($lock);
100
}
101
102
return id(new DrydockSlotLock())->loadAllWhere(
103
'lockIndex IN (%Ls)',
104
$indexes);
105
}
106
107
108
/* -( Acquiring and Releasing Locks )-------------------------------------- */
109
110
111
/**
112
* Acquire a set of slot locks.
113
*
114
* This method either acquires all the locks or throws an exception (usually
115
* because one or more locks are held).
116
*
117
* @param phid Lock owner PHID.
118
* @param list<string> List of locks to acquire.
119
* @return void
120
* @task locks
121
*/
122
public static function acquireLocks($owner_phid, array $locks) {
123
if (!$locks) {
124
return;
125
}
126
127
$table = new DrydockSlotLock();
128
$conn_w = $table->establishConnection('w');
129
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);
138
}
139
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');
152
153
throw new DrydockSlotLockException($held);
154
}
155
}
156
157
158
/**
159
* Release all locks held by an owner.
160
*
161
* @param phid Lock owner PHID.
162
* @return void
163
* @task locks
164
*/
165
public static function releaseLocks($owner_phid) {
166
$table = new DrydockSlotLock();
167
$conn_w = $table->establishConnection('w');
168
169
queryfx(
170
$conn_w,
171
'DELETE FROM %T WHERE ownerPHID = %s',
172
$table->getTableName(),
173
$owner_phid);
174
}
175
176
}
177
178