66 parent::__construct( $config );
68 $this->lockServers = $config[
'lockServers'];
69 if ( isset( $config[
'srvsByBucket'] ) ) {
71 $this->srvsByBucket = array_filter( $config[
'srvsByBucket'],
'is_array' );
72 $this->srvsByBucket = array_values( $this->srvsByBucket );
74 $this->srvsByBucket = [ array_keys( $this->lockServers ) ];
77 $config[
'redisConfig'][
'serializer'] =
'none';
82 $status = StatusValue::newGood();
84 $pathList = array_merge( ...array_values( $pathsByType ) );
86 $server = $this->lockServers[$lockSrv];
87 $conn = $this->redisPool->getConnection( $server, $this->logger );
89 foreach ( $pathList as
$path ) {
90 $status->fatal(
'lockmanager-fail-acquirelock',
$path );
97 foreach ( $pathsByType as
$type => $paths ) {
99 foreach ( $paths as
$path ) {
109 -- Load input params (e.g. session, ttl, time of request)
110 local rSession, rTTL, rMaxTTL, rTime = unpack(ARGV)
111 -- Check that all the locks can be acquired
112 for i,requestKey in ipairs(KEYS)
do
113 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
114 local keyIsFree =
true
115 local currentLocks = redis.call(
'hKeys',resourceKey)
116 for i,lockKey in ipairs(currentLocks)
do
117 -- Get the type and session of
this lock
118 local _, _, type, session =
string.find(lockKey,
"(%w+):(%w+)")
119 -- Check any locks that are not owned by
this session
120 if session ~= rSession then
121 local lockExpiry = redis.call(
'hGet',resourceKey,lockKey)
122 if 1*lockExpiry < 1*rTime then
123 -- Lock is stale, so just prune it out
124 redis.call(
'hDel',resourceKey,lockKey)
125 elseif rType ==
'EX' or type ==
'EX' then
131 if not keyIsFree then
132 failed[#failed+1] = requestKey
135 -- If all locks could be acquired, then
do so
137 for i,requestKey in ipairs(KEYS)
do
138 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
139 redis.call(
'hSet',resourceKey,rType ..
':' .. rSession,rTime + rTTL)
140 -- In addition to invalidation logic, be sure to garbage collect
141 redis.call(
'expire',resourceKey,rMaxTTL)
146 $res = $conn->luaEval( $script,
148 array_keys( $pathsByKey ),
156 count( $pathsByKey ) # number of first argument(s) that are keys
158 }
catch ( RedisException $e ) {
160 $this->redisPool->handleError( $conn, $e );
163 if (
$res ===
false ) {
164 foreach ( $pathList as
$path ) {
165 $status->fatal(
'lockmanager-fail-acquirelock',
$path );
167 } elseif ( count(
$res ) ) {
168 $status->fatal(
'lockmanager-fail-conflict' );
175 $status = StatusValue::newGood();
177 $pathList = array_merge( ...array_values( $pathsByType ) );
179 $server = $this->lockServers[$lockSrv];
180 $conn = $this->redisPool->getConnection( $server, $this->logger );
182 foreach ( $pathList as
$path ) {
183 $status->fatal(
'lockmanager-fail-releaselock',
$path );
190 foreach ( $pathsByType as
$type => $paths ) {
192 foreach ( $paths as
$path ) {
202 -- Load input params (e.g. session)
203 local rSession = unpack(ARGV)
204 for i,requestKey in ipairs(KEYS)
do
205 local _, _, rType, resourceKey =
string.find(requestKey,
"(%w+):(%w+)$")
206 local released = redis.call(
'hDel',resourceKey,rType ..
':' .. rSession)
208 -- Remove the whole structure
if it is now empty
209 if redis.call(
'hLen',resourceKey) == 0 then
210 redis.call(
'del',resourceKey)
213 failed[#failed+1] = requestKey
218 $res = $conn->luaEval( $script,
220 array_keys( $pathsByKey ),
225 count( $pathsByKey ) # number of first argument(s) that are keys
227 }
catch ( RedisException $e ) {
229 $this->redisPool->handleError( $conn, $e );
232 if (
$res ===
false ) {
233 foreach ( $pathList as
$path ) {
234 $status->fatal(
'lockmanager-fail-releaselock',
$path );
237 foreach (
$res as $key ) {
238 $status->fatal(
'lockmanager-fail-releaselock', $pathsByKey[$key] );