65 parent::__construct( $config );
67 $this->lockServers = $config[
'lockServers'];
69 $this->srvsByBucket = array_filter( $config[
'srvsByBucket'],
'is_array' );
70 $this->srvsByBucket = array_values( $this->srvsByBucket );
72 $config[
'redisConfig'][
'serializer'] =
'none';
79 $pathList = array_merge( ...array_values( $pathsByType ) );
81 $server = $this->lockServers[$lockSrv];
82 $conn = $this->redisPool->getConnection( $server, $this->logger );
84 foreach ( $pathList as
$path ) {
92 foreach ( $pathsByType as
$type => $paths ) {
94 foreach ( $paths as
$path ) {
104 -- Load input params (e.g. session, ttl, time of request)
105 local rSession, rTTL, rMaxTTL, rTime = unpack(ARGV)
106 -- Check that all the locks can be acquired
107 for i,requestKey in ipairs(KEYS)
do
108 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
109 local keyIsFree =
true
110 local currentLocks = redis.call(
'hKeys',resourceKey)
111 for i,lockKey in ipairs(currentLocks)
do
112 -- Get the type and session of
this lock
113 local _, _, type, session =
string.find(lockKey,
"(%w+):(%w+)")
114 -- Check any locks that are not owned by
this session
115 if session ~= rSession then
116 local lockExpiry = redis.call(
'hGet',resourceKey,lockKey)
117 if 1*lockExpiry < 1*rTime then
118 -- Lock is stale, so just prune it out
119 redis.call(
'hDel',resourceKey,lockKey)
120 elseif rType ==
'EX' or type ==
'EX' then
126 if not keyIsFree then
127 failed[#failed+1] = requestKey
130 -- If all locks could be acquired, then
do so
132 for i,requestKey in ipairs(KEYS)
do
133 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
134 redis.call(
'hSet',resourceKey,rType ..
':' .. rSession,rTime + rTTL)
135 -- In addition to invalidation logic, be sure to garbage collect
136 redis.call(
'expire',resourceKey,rMaxTTL)
141 $res = $conn->luaEval( $script,
143 array_keys( $pathsByKey ),
151 count( $pathsByKey ) # number of first argument(s) that are keys
153 }
catch ( RedisException $e ) {
155 $this->redisPool->handleError( $conn, $e );
158 if (
$res ===
false ) {
159 foreach ( $pathList as
$path ) {
160 $status->fatal(
'lockmanager-fail-acquirelock',
$path );
163 foreach (
$res as $key ) {
164 $status->fatal(
'lockmanager-fail-acquirelock', $pathsByKey[$key] );
174 $pathList = array_merge( ...array_values( $pathsByType ) );
176 $server = $this->lockServers[$lockSrv];
177 $conn = $this->redisPool->getConnection( $server, $this->logger );
179 foreach ( $pathList as
$path ) {
180 $status->fatal(
'lockmanager-fail-releaselock',
$path );
187 foreach ( $pathsByType as
$type => $paths ) {
189 foreach ( $paths as
$path ) {
199 -- Load input params (e.g. session)
200 local rSession = unpack(ARGV)
201 for i,requestKey in ipairs(KEYS)
do
202 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
203 local released = redis.call(
'hDel',resourceKey,rType ..
':' .. rSession)
205 -- Remove the whole structure
if it is now empty
206 if redis.call(
'hLen',resourceKey) == 0 then
207 redis.call(
'del',resourceKey)
210 failed[#failed+1] = requestKey
215 $res = $conn->luaEval( $script,
217 array_keys( $pathsByKey ),
222 count( $pathsByKey ) # number of first argument(s) that are keys
224 }
catch ( RedisException $e ) {
226 $this->redisPool->handleError( $conn, $e );
229 if (
$res ===
false ) {
230 foreach ( $pathList as
$path ) {
231 $status->fatal(
'lockmanager-fail-releaselock',
$path );
234 foreach (
$res as $key ) {
235 $status->fatal(
'lockmanager-fail-releaselock', $pathsByKey[$key] );
247 $conn = $this->redisPool->getConnection( $this->lockServers[$lockSrv], $this->logger );
266 while ( count( $this->locksHeld ) ) {
268 foreach ( $this->locksHeld as
$path => $locks ) {
269 foreach ( $locks as
$type => $count ) {