63 $status = StatusValue::newGood();
65 $pathList = array_merge( ...array_values( $pathsByType ) );
67 $server = $this->lockServers[$lockSrv];
68 $conn = $this->redisPool->getConnection( $server, $this->logger );
70 foreach ( $pathList as
$path ) {
71 $status->fatal(
'lockmanager-fail-acquirelock',
$path );
78 foreach ( $pathsByType as $type => $paths ) {
80 foreach ( $paths as
$path ) {
90 -- Load input params (e.g. session, ttl, time of request)
91 local rSession, rTTL, rMaxTTL, rTime = unpack(ARGV)
92 -- Check that all the locks can be acquired
93 for i,requestKey in ipairs(KEYS)
do
94 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
95 local keyIsFree =
true
96 local currentLocks = redis.call(
'hKeys',resourceKey)
97 for i,
lockKey in ipairs(currentLocks)
do
98 -- Get the type and session of
this lock
99 local _, _, type, session =
string.find(
lockKey,
"(%w+):(%w+)")
100 -- Check any locks that are not owned by
this session
101 if session ~= rSession then
102 local lockExpiry = redis.call(
'hGet',resourceKey,
lockKey)
103 if 1*lockExpiry < 1*rTime then
104 -- Lock is stale, so just prune it out
105 redis.call(
'hDel',resourceKey,
lockKey)
106 elseif rType ==
'EX' or type ==
'EX' then
112 if not keyIsFree then
113 failed[#failed+1] = requestKey
116 -- If all locks could be acquired, then
do so
118 for i,requestKey in ipairs(KEYS)
do
119 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
120 redis.call(
'hSet',resourceKey,rType ..
':' .. rSession,rTime + rTTL)
121 -- In addition to invalidation logic, be sure to garbage collect
122 redis.call(
'expire',resourceKey,rMaxTTL)
127 $res = $conn->luaEval( $script,
129 array_keys( $pathsByKey ),
137 count( $pathsByKey ) # number of first argument(s) that are keys
139 }
catch ( RedisException $e ) {
141 $this->redisPool->handleError( $conn, $e );
144 if ( $res ===
false ) {
145 foreach ( $pathList as
$path ) {
146 $status->fatal(
'lockmanager-fail-acquirelock',
$path );
148 } elseif ( count( $res ) ) {
149 $status->fatal(
'lockmanager-fail-conflict' );
157 $status = StatusValue::newGood();
159 $pathList = array_merge( ...array_values( $pathsByType ) );
161 $server = $this->lockServers[$lockSrv];
162 $conn = $this->redisPool->getConnection( $server, $this->logger );
164 foreach ( $pathList as
$path ) {
165 $status->fatal(
'lockmanager-fail-releaselock',
$path );
172 foreach ( $pathsByType as $type => $paths ) {
174 foreach ( $paths as
$path ) {
184 -- Load input params (e.g. session)
185 local rSession = unpack(ARGV)
186 for i,requestKey in ipairs(KEYS)
do
187 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
188 local released = redis.call(
'hDel',resourceKey,rType ..
':' .. rSession)
190 -- Remove the whole structure
if it is now empty
191 if redis.call(
'hLen',resourceKey) == 0 then
192 redis.call(
'del',resourceKey)
195 failed[#failed+1] = requestKey
200 $res = $conn->luaEval( $script,
202 array_keys( $pathsByKey ),
207 count( $pathsByKey ) # number of first argument(s) that are keys
209 }
catch ( RedisException $e ) {
211 $this->redisPool->handleError( $conn, $e );
214 if ( $res ===
false ) {
215 foreach ( $pathList as
$path ) {
216 $status->fatal(
'lockmanager-fail-releaselock',
$path );
219 foreach ( $res as $key ) {
220 $status->fatal(
'lockmanager-fail-releaselock', $pathsByKey[$key] );