if upd.op ~= "dup" then
local hash_key = prefix .. upd.digest
- -- Build KEYS array for the Redis script
+ -- Build KEYS array (only actual Redis key names) and ARGV (parameters)
local keys = {
hash_key,
- upd.op,
- tostring(upd.flag),
- tostring(upd.value),
- tostring(expire),
- tostring(upd.timestamp),
- tostring(upd.is_weak),
count_key,
- upd.digest,
}
-- Append shingle keys if present
end
end
+ local args = {
+ upd.op,
+ tostring(upd.flag),
+ tostring(upd.value),
+ tostring(expire),
+ tostring(upd.timestamp),
+ tostring(upd.is_weak),
+ upd.digest,
+ }
+
local function update_cb(err, _)
if err then
logger.errx(rspamd_config, '%s: update script failed: %s', N, err)
lua_redis.exec_redis_script(update_script_id,
{ ev_base = ev_base, is_write = true, key = hash_key },
- update_cb, keys)
+ update_cb, keys, args)
end
end
end
-- Handles ADD, DEL, and REFRESH operations including multi-flag merge and shingles
--
-- KEYS[1] = hash_key (prefix + digest)
--- KEYS[2] = operation: "add", "del", "refresh"
--- KEYS[3] = flag (string number)
--- KEYS[4] = value (string number)
--- KEYS[5] = expire (string number, seconds)
--- KEYS[6] = timestamp (string number, calendar seconds)
--- KEYS[7] = is_weak ("0" or "1")
--- KEYS[8] = count_key (prefix .. "_count")
--- KEYS[9] = digest (raw bytes, used as value for shingle SETEX)
--- KEYS[10..] = shingle keys (0 or 32 of them)
+-- KEYS[2] = count_key (prefix .. "_count")
+-- KEYS[3..] = shingle keys (0 or 32 of them)
+-- ARGV[1] = operation: "add", "del", "refresh"
+-- ARGV[2] = flag (string number)
+-- ARGV[3] = value (string number)
+-- ARGV[4] = expire (string number, seconds)
+-- ARGV[5] = timestamp (string number, calendar seconds)
+-- ARGV[6] = is_weak ("0" or "1")
+-- ARGV[7] = digest (raw bytes, used as value for shingle SETEX)
local key = KEYS[1]
-local op = KEYS[2]
-local new_flag = tonumber(KEYS[3])
-local new_value = tonumber(KEYS[4])
-local expire = tonumber(KEYS[5])
-local timestamp = KEYS[6]
-local is_weak = tonumber(KEYS[7])
-local count_key = KEYS[8]
-local digest = KEYS[9]
+local count_key = KEYS[2]
+local op = ARGV[1]
+local new_flag = tonumber(ARGV[2])
+local new_value = tonumber(ARGV[3])
+local expire = tonumber(ARGV[4])
+local timestamp = ARGV[5]
+local is_weak = tonumber(ARGV[6])
+local digest = ARGV[7]
if op == "add" then
-- Multi-flag merge logic: up to 8 flag slots (primary '' + extra '1'..'7')
redis.call('INCR', count_key)
-- Handle shingles: SETEX each shingle key with expire and digest as value
- for i = 10, #KEYS do
+ for i = 3, #KEYS do
redis.call('SETEX', KEYS[i], expire, digest)
end
redis.call('DEL', key)
redis.call('DECR', count_key)
- for i = 10, #KEYS do
+ for i = 3, #KEYS do
redis.call('DEL', KEYS[i])
end
elseif op == "refresh" then
redis.call('EXPIRE', key, expire)
- for i = 10, #KEYS do
+ for i = 3, #KEYS do
redis.call('EXPIRE', KEYS[i], expire)
end
end
-- Lua script to save and unlock ANN in redis
--- Uses the following keys
+-- Uses the following keys and argv
-- key1 - prefix for ANN
-- key2 - prefix for profile
--- key3 - compressed ANN
--- key4 - profile as JSON
--- key5 - expire in seconds
--- key6 - current time
--- key7 - old key
--- key8 - ROC Thresholds
--- key9 - optional PCA
--- key10 - optional providers_meta (JSON)
--- key11 - optional norm_stats (JSON)
-local now = tonumber(KEYS[6])
-redis.call('ZADD', KEYS[2], now, KEYS[4])
-redis.call('HSET', KEYS[1], 'ann', KEYS[3])
-redis.call('HSET', KEYS[1], 'roc_thresholds', KEYS[8])
-if KEYS[9] and KEYS[9] ~= '' then
- redis.call('HSET', KEYS[1], 'pca', KEYS[9])
+-- key3 - old key
+-- argv1 - compressed ANN
+-- argv2 - profile as JSON
+-- argv3 - expire in seconds
+-- argv4 - current time
+-- argv5 - ROC Thresholds
+-- argv6 - optional PCA
+-- argv7 - optional providers_meta (JSON)
+-- argv8 - optional norm_stats (JSON)
+local now = tonumber(ARGV[4])
+redis.call('ZADD', KEYS[2], now, ARGV[2])
+redis.call('HSET', KEYS[1], 'ann', ARGV[1])
+redis.call('HSET', KEYS[1], 'roc_thresholds', ARGV[5])
+if ARGV[6] and ARGV[6] ~= '' then
+ redis.call('HSET', KEYS[1], 'pca', ARGV[6])
end
-if KEYS[10] and KEYS[10] ~= '' then
- redis.call('HSET', KEYS[1], 'providers_meta', KEYS[10])
+if ARGV[7] and ARGV[7] ~= '' then
+ redis.call('HSET', KEYS[1], 'providers_meta', ARGV[7])
end
-if KEYS[11] and KEYS[11] ~= '' then
- redis.call('HSET', KEYS[1], 'norm_stats', KEYS[11])
+if ARGV[8] and ARGV[8] ~= '' then
+ redis.call('HSET', KEYS[1], 'norm_stats', ARGV[8])
end
redis.call('HDEL', KEYS[1], 'lock')
-redis.call('HDEL', KEYS[7], 'lock')
-redis.call('HSET', KEYS[7], 'obsolete', '1')
-redis.call('EXPIRE', KEYS[7], 600)
-redis.call('EXPIRE', KEYS[1], tonumber(KEYS[5]))
+redis.call('HDEL', KEYS[3], 'lock')
+redis.call('HSET', KEYS[3], 'obsolete', '1')
+redis.call('EXPIRE', KEYS[3], 600)
+redis.call('EXPIRE', KEYS[1], tonumber(ARGV[3]))
-- expire in 10m, to not face race condition with other rspamd replicas refill deleted keys
-redis.call('EXPIRE', KEYS[7] .. '_spam_set', 600)
-redis.call('EXPIRE', KEYS[7] .. '_ham_set', 600)
+redis.call('EXPIRE', KEYS[3] .. '_spam_set', 600)
+redis.call('EXPIRE', KEYS[3] .. '_ham_set', 600)
return 1