68 lines
2.5 KiB
Lua
68 lines
2.5 KiB
Lua
local tickets_key = KEYS[1]
|
|
local owners_key = KEYS[2]
|
|
local worker_index_key = KEYS[3]
|
|
|
|
local proxy_id = ARGV[1]
|
|
local worker_id = ARGV[2]
|
|
local assignment_epoch = tonumber(ARGV[3])
|
|
local required_epoch = tonumber(ARGV[4])
|
|
local session_id = ARGV[5]
|
|
local version = tonumber(ARGV[6])
|
|
local snapshot_epoch = tonumber(ARGV[7])
|
|
local checksum = ARGV[8]
|
|
|
|
local function reply(status)
|
|
return cjson.encode({status = status})
|
|
end
|
|
|
|
local function decode_table(raw)
|
|
if not raw then
|
|
return nil
|
|
end
|
|
local ok, value = pcall(cjson.decode, raw)
|
|
if not ok or type(value) ~= 'table' then
|
|
return nil
|
|
end
|
|
return value
|
|
end
|
|
|
|
local function valid_checksum(value)
|
|
return type(value) == 'string' and string.len(value) == 64 and string.match(value, '^[0-9a-f]+$') ~= nil
|
|
end
|
|
|
|
if type(proxy_id) ~= 'string' or proxy_id == '' or type(worker_id) ~= 'string' or worker_id == '' or
|
|
not assignment_epoch or assignment_epoch <= 0 or not required_epoch or required_epoch <= assignment_epoch or
|
|
type(session_id) ~= 'string' or session_id == '' or not version or version <= 0 or
|
|
not snapshot_epoch or snapshot_epoch < required_epoch or not valid_checksum(checksum) then
|
|
return reply('invalid')
|
|
end
|
|
|
|
local ticket = decode_table(redis.call('HGET', tickets_key, proxy_id))
|
|
local assignment = decode_table(redis.call('HGET', owners_key, proxy_id))
|
|
if not ticket or ticket.version ~= 1 or ticket.proxyId ~= proxy_id or ticket.workerId ~= worker_id or
|
|
ticket.workerIndexKey ~= worker_index_key or tonumber(ticket.assignmentEpoch) ~= assignment_epoch or
|
|
tonumber(ticket.requiredSnapshotEpoch) ~= required_epoch or not assignment or assignment.version ~= 1 or
|
|
assignment.draining ~= true or assignment.workerId ~= worker_id or tonumber(assignment.epoch) ~= assignment_epoch then
|
|
return reply('stale')
|
|
end
|
|
|
|
local current_epoch = tonumber(ticket.snapshotOwnershipEpoch) or 0
|
|
local current_version = tonumber(ticket.snapshotVersion) or 0
|
|
if ticket.sessionId == session_id then
|
|
if current_epoch > snapshot_epoch or (current_epoch == snapshot_epoch and current_version > version) then
|
|
return reply('ok')
|
|
end
|
|
if current_epoch == snapshot_epoch and current_version == version then
|
|
if ticket.snapshotChecksum ~= checksum then
|
|
return reply('stale')
|
|
end
|
|
return reply('ok')
|
|
end
|
|
end
|
|
ticket.sessionId = session_id
|
|
ticket.snapshotVersion = version
|
|
ticket.snapshotOwnershipEpoch = snapshot_epoch
|
|
ticket.snapshotChecksum = checksum
|
|
redis.call('HSET', tickets_key, proxy_id, cjson.encode(ticket))
|
|
return reply('ok')
|