queris 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +34 -0
- data/README.md +53 -0
- data/Rakefile +1 -0
- data/data/redis_scripts/add_low_ttl.lua +10 -0
- data/data/redis_scripts/copy_key_if_absent.lua +13 -0
- data/data/redis_scripts/copy_ttl.lua +13 -0
- data/data/redis_scripts/create_page_if_absent.lua +24 -0
- data/data/redis_scripts/debuq.lua +20 -0
- data/data/redis_scripts/delete_if_string.lua +8 -0
- data/data/redis_scripts/delete_matching_keys.lua +7 -0
- data/data/redis_scripts/expire_temp_query_keys.lua +7 -0
- data/data/redis_scripts/make_rangehack_if_needed.lua +30 -0
- data/data/redis_scripts/master_expire.lua +15 -0
- data/data/redis_scripts/match_key_type.lua +9 -0
- data/data/redis_scripts/move_key.lua +11 -0
- data/data/redis_scripts/multisize.lua +19 -0
- data/data/redis_scripts/paged_query_ready.lua +35 -0
- data/data/redis_scripts/periodic_zremrangebyscore.lua +9 -0
- data/data/redis_scripts/persist_reusable_temp_query_keys.lua +14 -0
- data/data/redis_scripts/query_ensure_existence.lua +23 -0
- data/data/redis_scripts/query_intersect_optimization.lua +31 -0
- data/data/redis_scripts/remove_from_keyspace.lua +27 -0
- data/data/redis_scripts/remove_from_sets.lua +13 -0
- data/data/redis_scripts/results_from_hash.lua +54 -0
- data/data/redis_scripts/results_with_ttl.lua +20 -0
- data/data/redis_scripts/subquery_intersect_optimization.lua +25 -0
- data/data/redis_scripts/subquery_intersect_optimization_cleanup.lua +5 -0
- data/data/redis_scripts/undo_add_low_ttl.lua +8 -0
- data/data/redis_scripts/unpaged_query_ready.lua +17 -0
- data/data/redis_scripts/unpersist_reusable_temp_query_keys.lua +11 -0
- data/data/redis_scripts/update_live_expiring_presence_index.lua +20 -0
- data/data/redis_scripts/update_query.lua +126 -0
- data/data/redis_scripts/update_rangehacks.lua +94 -0
- data/data/redis_scripts/zrangestore.lua +12 -0
- data/lib/queris.rb +400 -0
- data/lib/queris/errors.rb +8 -0
- data/lib/queris/indices.rb +735 -0
- data/lib/queris/mixin/active_record.rb +74 -0
- data/lib/queris/mixin/object.rb +398 -0
- data/lib/queris/mixin/ohm.rb +81 -0
- data/lib/queris/mixin/queris_model.rb +59 -0
- data/lib/queris/model.rb +455 -0
- data/lib/queris/profiler.rb +275 -0
- data/lib/queris/query.rb +1215 -0
- data/lib/queris/query/operations.rb +398 -0
- data/lib/queris/query/page.rb +101 -0
- data/lib/queris/query/timer.rb +42 -0
- data/lib/queris/query/trace.rb +108 -0
- data/lib/queris/query_store.rb +137 -0
- data/lib/queris/version.rb +3 -0
- data/lib/rails/log_subscriber.rb +22 -0
- data/lib/rails/request_timing.rb +29 -0
- data/lib/tasks/queris.rake +138 -0
- data/queris.gemspec +41 -0
- data/test.rb +39 -0
- data/test/current.rb +74 -0
- data/test/dsl.rb +35 -0
- data/test/ohm.rb +37 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3308c207243318c193dcc8557c6b5120bff0fb85
|
4
|
+
data.tar.gz: 0b81f79d85f4adc0fc801b671d92b342b6ebdf8f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a59b24e659d0652dd1403682720fc75b8de4e91f57ba0013fe1da3a254de2aaa562cc9e627515e1e81272793dae2a85ab27eb101c349df624cf98c4ba3859530
|
7
|
+
data.tar.gz: 0ef348c9862862fd5a0159b57e0efa64c9479427050a67911ec8d83c87bf4c0ba1a3d4592fc2904b7e368f8c320a537bd4ec704cec23eb8240577a6ec027508e
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
queris (0.8.1)
|
5
|
+
diffy
|
6
|
+
hiredis
|
7
|
+
redis (~> 3.2.1)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
coderay (1.1.0)
|
13
|
+
diffy (3.0.7)
|
14
|
+
hiredis (0.6.0)
|
15
|
+
method_source (0.8.2)
|
16
|
+
pry (0.10.2)
|
17
|
+
coderay (~> 1.1.0)
|
18
|
+
method_source (~> 0.8.1)
|
19
|
+
slop (~> 3.4)
|
20
|
+
pry-debundle (0.8)
|
21
|
+
pry
|
22
|
+
redis (3.2.1)
|
23
|
+
slop (3.6.0)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
pry
|
30
|
+
pry-debundle
|
31
|
+
queris!
|
32
|
+
|
33
|
+
BUNDLED WITH
|
34
|
+
1.10.6
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
Nutshell
|
2
|
+
========
|
3
|
+
A Ruby object indexing and querying tool using Redis to store data and perform set operations.
|
4
|
+
|
5
|
+
What's all this about?
|
6
|
+
====
|
7
|
+
Redis is a flexible data structures server. It's pretty fast, but if you want to index something, you have to do it manually.
|
8
|
+
Queris can be bolted onto some Ruby objects (hashes, ActiveRecord models, Ohm objects, etc.) to maintain indices and perform queries. Attributes can be indexed into regular or sorted sets, allowing set selection on arbitrary data, and range selection on numeric data (if desired). More complex indexing, like n-gram text search, can be implemented client-side (and will be included in some future Queris version.)
|
9
|
+
Queries can perform set operations on all indices and other queries, and can be sorted. Each query can be cached for a custom duration. Queries can also be live (reflect realtime changes to complex set operations) in O(log(n)) server time.
|
10
|
+
Thus Queris offers customizeable indexing, and nestable, cacheable, optionally realtime, set queries (with a few more bells and whistles).
|
11
|
+
|
12
|
+
Learning By Example
|
13
|
+
===================
|
14
|
+
First connect to redis. Let's assume a Redis server on localhost at standard port 6379:
|
15
|
+
```ruby
|
16
|
+
Queris.add_redis Redis.new
|
17
|
+
```
|
18
|
+
Let's say you have a User ActiveRecord model with some obvious attributes - id, name, email, age. Let's also assume a UserTags model, linked to User by its userId attribute.
|
19
|
+
```ruby
|
20
|
+
class User < ActiveRecord::Base
|
21
|
+
include Queris
|
22
|
+
|
23
|
+
#declare which attributes to index, and how
|
24
|
+
index_attributes :name, :email #simple set index
|
25
|
+
index_range_attribute :age #sorted set index
|
26
|
+
index_attribute_from model: UserTags, attribute: :tag, key: :userId #index from a different model
|
27
|
+
end
|
28
|
+
```
|
29
|
+
To build indices:
|
30
|
+
```ruby
|
31
|
+
User.build_redis_indices
|
32
|
+
```
|
33
|
+
This will load all current User objects into memory and index said objects. You currently need enough space to keep the entire dataset in memory for building indices. (Future versions will be able to import data incrementally.)
|
34
|
+
|
35
|
+
You can now query Users:
|
36
|
+
```ruby
|
37
|
+
young_bob_and_steve = User.query(:ttl=>2.days).union(:name, ["Steve", "Bob"]).intersect(:age, 0..30).diff(:email, "steve@example.org") #query expires in 2 days
|
38
|
+
#you can have subqueries, too:
|
39
|
+
bob_and_steve_and_bill = User.query.union(young_bob_and_steve).union(:name, "Bill")
|
40
|
+
#now get the results
|
41
|
+
bob_and_steve_and_bill.results #all results
|
42
|
+
bob_and_steve_and_bill.count #result count
|
43
|
+
bob_and_steve_and_bill.results(3..5) # results # 3 through 5
|
44
|
+
```
|
45
|
+
Queries can be expressed in set notation:
|
46
|
+
```ruby
|
47
|
+
bob_and_steve_and_bill.to_s # same as .explain
|
48
|
+
# ((name<["Steve", "Bob"]> ∩ age<0..30> ∖ email<steve@example.org>) ∪ name<Bill>)
|
49
|
+
```
|
50
|
+
|
51
|
+
Note that query operations are applied sequentially (with no complex operator precedence rules), but can be arranged or grouped by the use of subqueries.
|
52
|
+
|
53
|
+
...more to follow...
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
local min_ttl=tonumber(ARGV[1])
|
2
|
+
local keys=KEYS
|
3
|
+
local state=table.remove(keys) --last key is state key
|
4
|
+
for i, k in ipairs(keys) do
|
5
|
+
local ttl = tonumber(redis.call('ttl', k))
|
6
|
+
if ttl>0 and ttl < min_ttl then
|
7
|
+
redis.call('expire', k, ttl + min_ttl)
|
8
|
+
table.sadd(state, k)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
local dst, src = KEYS[1], KEYS[2]
|
2
|
+
local t = redis.call('type', src).ok
|
3
|
+
if t == 'zset' then
|
4
|
+
redis.call('zunionstore', dst, 1, src)
|
5
|
+
elseif t == 'set' then
|
6
|
+
redis.call('sunionstore', dst, 1, src)
|
7
|
+
elseif t == 'string' then
|
8
|
+
redis.call('set', dst, redis.call('get', src))
|
9
|
+
elseif t == 'none' then
|
10
|
+
--noop
|
11
|
+
else
|
12
|
+
redis.log(redis.LOG_WARNING, "copy_key_if_absent: unsupported key type " .. t .. ".")
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
if redis.call('exists', KEYS[2]) == 0 then
|
2
|
+
return nil
|
3
|
+
end
|
4
|
+
local ttl, delete_if_absent = redis.call("ttl", KEYS[1]), (ARGV[1] or false)
|
5
|
+
if ttl ~= -1 then
|
6
|
+
redis.call("expire", KEYS[2], ttl)
|
7
|
+
return ttl
|
8
|
+
elseif delete_if_absent and redis.call('exists', KEYS[1]) == 0 then
|
9
|
+
if redis.call("del", KEYS[2]) == 1 then
|
10
|
+
return "DELETED"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
return 'OK'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
local dst, source = KEYS[1], KEYS[2]
|
2
|
+
local min, max = ARGV[1], ARGV[2]
|
3
|
+
local dst_type = redis.call('type', dst).ok
|
4
|
+
redis.log(redis.LOG_WARNING, "want a page at " .. dst .. " from " .. source)
|
5
|
+
if dst_type == 'string' then
|
6
|
+
redis.call('del', dst)
|
7
|
+
elseif dst_type == 'zset' then
|
8
|
+
redis.log(redis.LOG_WARNING, 'page ' .. dst .. ' already exists with size ' .. redis.call('zcard', dst))
|
9
|
+
return redis.call('zcard', dst)
|
10
|
+
end
|
11
|
+
|
12
|
+
local res = redis.call("zrange", source, min, max, "withscores")
|
13
|
+
local id, score
|
14
|
+
if next(res) ~= nil then
|
15
|
+
redis.call('del', dst)
|
16
|
+
end
|
17
|
+
for i,v in ipairs(res) do
|
18
|
+
if i%2==1 then id=v; else
|
19
|
+
score=v
|
20
|
+
redis.call('zadd', dst, score, id)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
redis.log(redis.LOG_WARNING, 'pagesize of ' .. dst .. ': ' .. redis.call('zcard', dst))
|
24
|
+
return #res/2
|
@@ -0,0 +1,20 @@
|
|
1
|
+
local cmd=ARGV[1]
|
2
|
+
local keys = KEYS
|
3
|
+
|
4
|
+
local info = function(k)
|
5
|
+
local t = redis.call('type', k).ok
|
6
|
+
if t == 'zset' then
|
7
|
+
return "zset size=" .. redis.call('zcard', k)
|
8
|
+
elseif t== 'set' then
|
9
|
+
return "set size=" .. redis.call('scard', k)
|
10
|
+
elseif t== 'string' then
|
11
|
+
return "string = " .. redis.call('get', k)
|
12
|
+
else
|
13
|
+
return t
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
redis.log(redis.LOG_WARNING, "info for " ..cmd.. ": " .. #KEYS .. " keys")
|
18
|
+
for k,v in pairs(keys) do
|
19
|
+
redis.log(redis.LOG_WARNING, (" " .. v .. ": " .. info(v)))
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
local dst, src, rangehack_set_key, not_needed_key = KEYS[1], KEYS[2], KEYS[3], KEYS[4]
|
2
|
+
local min, max, exclude_max = tonumber(ARGV[1]), tonumber(ARGV[2]), ARGV
|
3
|
+
redis.log(redis.LOG_WARNING, "want rangehack ("..min..","..max..") for " .. src)
|
4
|
+
if redis.call('exists', not_needed_key) == 1 then
|
5
|
+
--nevermind, we don't need to run this
|
6
|
+
redis.log(redis.LOG_WARNING, "nevermind, the query doesn't need it..")
|
7
|
+
return
|
8
|
+
end
|
9
|
+
local opf = "(%s" --)
|
10
|
+
local t = redis.call('type', dst).ok
|
11
|
+
if t == 'zset' then
|
12
|
+
--already exists, nothing to do
|
13
|
+
redis.log(redis.LOG_WARNING, "it's already here.")
|
14
|
+
return
|
15
|
+
else
|
16
|
+
redis.call('zunionstore', dst, 1, src) --slow as a fat, barbed turd
|
17
|
+
--remove inverse range
|
18
|
+
redis.call('zremrangebyscore', dst, '-inf', opf:format(min))
|
19
|
+
redis.call('zremrangebyscore', dst, (exclude_max and max or opf:format(max)), 'inf')
|
20
|
+
|
21
|
+
--add to rangehack 'index'
|
22
|
+
redis.call('sadd', rangehack_set_key, dst)
|
23
|
+
|
24
|
+
redis.log(redis.LOG_WARNING, "made one at " .. dst .. " with size " .. redis.call('zcard', dst))
|
25
|
+
if redis.call('zcard', dst) == 0 then
|
26
|
+
--dummy one-element zset
|
27
|
+
redis.call('zadd', dst, 0, "=-{*_*}-= <- the nullset ghost")
|
28
|
+
end
|
29
|
+
redis.log(redis.LOG_WARNING, "made one at " .. dst .. " with size " .. redis.call('zcard', dst))
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
local ttl, renew, dummy = ARGV[1], ARGV[2], ARGV[3]
|
2
|
+
redis.log(redis.LOG_WARNING, "master_expire keys [" .. table.concat(KEYS, ', ') .. "] with ttl " .. ttl .. " renew: " .. (renew and "yes" or "no") .. " dummy: " .. (dummy and "yes" or "no"))
|
3
|
+
for i,k in ipairs(KEYS) do
|
4
|
+
local exists = redis.call('exists', k) == 1
|
5
|
+
if not exists and dummy then
|
6
|
+
exists = 1
|
7
|
+
redis.call('setnx', k, 'dummy')
|
8
|
+
end
|
9
|
+
if exists then
|
10
|
+
local current_ttl = redis.call('ttl', k)
|
11
|
+
if current_ttl < 0 or renew then
|
12
|
+
redis.call('expire', k, ttl)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
local oldkey, newkey = KEYS[1], KEYS[2]
|
2
|
+
if redis.call('exists', oldkey) == 1 then
|
3
|
+
redis.call('rename', oldkey, newkey)
|
4
|
+
return 1
|
5
|
+
else
|
6
|
+
--oldkey is empty, so we move that emptiness to newkey
|
7
|
+
if redis.call('exists', newkey) == 1 then
|
8
|
+
redis.call('del', newkey) --clear newkey
|
9
|
+
end
|
10
|
+
return 0
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
local key = KEYS[1]
|
2
|
+
local keytype = redis.call('type', key).ok
|
3
|
+
|
4
|
+
if keytype=='set' then
|
5
|
+
return redis.call('scard', key)
|
6
|
+
elseif keytype=='zset' then
|
7
|
+
return redis.call('zcard', key)
|
8
|
+
elseif keytype=='list' then
|
9
|
+
return redis.call('llen', key)
|
10
|
+
elseif keytype=='hash' then
|
11
|
+
return redis.call('hlen', key)
|
12
|
+
elseif keytype=='none' then
|
13
|
+
return 0
|
14
|
+
elseif keytype=='string' then
|
15
|
+
return redis.call('strlen', key)
|
16
|
+
else
|
17
|
+
redis.log(redis.LOG_WARNING, "I wonder what the size of key " .. key .. "(" .. keytype .. ")".. "is?")
|
18
|
+
return "WTF for " .. keytype
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
local results_key, exists_key, sort_key, page_key, runstate_key = KEYS[1], KEYS[2], KEYS[3], KEYS[4], KEYS[5]
|
2
|
+
local pagesize, min, max = tonumber(ARGV[1]), tonumber(ARGV[2]), tonumber(ARGV[3])
|
3
|
+
|
4
|
+
if redis.call('exists', exists_key) ~= 1 then
|
5
|
+
return nil
|
6
|
+
end
|
7
|
+
|
8
|
+
local last_loaded_page = redis.call('get', page_key)
|
9
|
+
|
10
|
+
if not last_loaded_page then
|
11
|
+
return nil
|
12
|
+
end
|
13
|
+
|
14
|
+
local t = redis.call('type', results_key).ok
|
15
|
+
local current_count
|
16
|
+
if t == 'zset' then
|
17
|
+
current_count = redis.call('zcard', results_key)
|
18
|
+
elseif t=='set' then
|
19
|
+
current_count = redis.call('scard', results_key)
|
20
|
+
else
|
21
|
+
current_count = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
if current_count > max then
|
25
|
+
if runstate_key then
|
26
|
+
redis.call('set', runstate_key, 1)
|
27
|
+
end
|
28
|
+
return true
|
29
|
+
elseif (last_loaded_page + 1) * pagesize >= redis.call('zcard', sort_key) then
|
30
|
+
--we've reached the end
|
31
|
+
if runstate_key then
|
32
|
+
redis.call('set', runstate_key, 1)
|
33
|
+
end
|
34
|
+
return true
|
35
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
local ttl = tonumber(ARGV[1])
|
2
|
+
local key = KEYS[1]
|
3
|
+
local timer_key = key .. ":timer"
|
4
|
+
if redis.call('exists', timer_key) == 1 then
|
5
|
+
return 0
|
6
|
+
else
|
7
|
+
redis.call('setex', timer_key, ttl, "don't do it as long as i exist")
|
8
|
+
end
|
9
|
+
return redis.call('zremrangebyscore', key, ARGV[2], ARGV[3])
|
@@ -0,0 +1,14 @@
|
|
1
|
+
local dst=table.remove(KEYS, 1)
|
2
|
+
if redis.call('exists', dst) == 1 then
|
3
|
+
redis.log(redis.LOG_WARNING, "persist_reusable_temp_query_keys storage key " .. dst .. " already exist. WTF?")
|
4
|
+
redis.call('del', dst)
|
5
|
+
end
|
6
|
+
for i,k in ipairs(KEYS) do
|
7
|
+
local t= redis.call('type', k).ok
|
8
|
+
if t ~= 'none' then
|
9
|
+
ttl = redis.call('ttl', k)
|
10
|
+
redis.call('persist', k)
|
11
|
+
redis.zadd(dst, ttl, k)
|
12
|
+
redis.log(redis.LOG_WARNING, "persisted key " .. k .. " ttl=" .. ttl)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
local existence_key, results_key = KEYS[1], KEYS[2]
|
2
|
+
local ttl, min_ttl, master_only = ARGV[1], tonumber(ARGV[2]), ARGV[3]=='true'
|
3
|
+
if redis.call('exists', existence_key) == 1 then
|
4
|
+
for i, k in ipairs(KEYS) do
|
5
|
+
if min_ttl then
|
6
|
+
local key_ttl = redis.call('ttl', k)
|
7
|
+
if key_ttl < min_ttl then
|
8
|
+
redis.call('expire', k, min_ttl)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
redis.call('expire', k, ttl)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
if not master_only then
|
15
|
+
return true
|
16
|
+
else
|
17
|
+
return redis.call('type', results_key).ok ~= 'string'
|
18
|
+
end
|
19
|
+
else
|
20
|
+
redis.call('setnx', results_key, 1)
|
21
|
+
redis.call('expire', results_key, ttl)
|
22
|
+
return false
|
23
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
local dstkey, key, smallkey = KEYS[1], KEYS[2], KEYS[3]
|
2
|
+
local ttl = ARGV[1] or 120
|
3
|
+
local t=redis.call('type', dstkey).ok
|
4
|
+
|
5
|
+
local multisize = function(key)
|
6
|
+
local keytype = redis.call('type', key).ok
|
7
|
+
if keytype=='set' then
|
8
|
+
return "set card=" .. redis.call('scard', key)
|
9
|
+
elseif keytype=='zset' then
|
10
|
+
return "zset card=" .. redis.call('zcard', key)
|
11
|
+
elseif keytype=='list' then
|
12
|
+
return "list card=" .. redis.call('llen', key)
|
13
|
+
elseif keytype=='hash' then
|
14
|
+
return "hash card=" .. redis.call('hlen', key)
|
15
|
+
elseif keytype=='none' then
|
16
|
+
return "none"
|
17
|
+
elseif keytype=='string' then
|
18
|
+
return "string length=" .. redis.call('strlen', key)
|
19
|
+
else
|
20
|
+
return "WTF for " .. keytype
|
21
|
+
end
|
22
|
+
end
|
23
|
+
if t ~= 'zset' then
|
24
|
+
redis.call('zinterstore', dstkey, 2, key, smallkey, 'weights', 1, 0)
|
25
|
+
redis.call('expire', dstkey, ttl)
|
26
|
+
for i,v in pairs({dstkey, key, smallkey}) do
|
27
|
+
redis.log(redis.LOG_WARNING, " inter: " .. v .. ": " .. multisize(v))
|
28
|
+
end
|
29
|
+
else
|
30
|
+
redis.log(redis.LOG_WARNING, "intersectoptimization " .. dstkey .. " already exists")
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
local element, keysearch, ttl = ARGV[1], ARGV[2], tonumber(ARGV[3])
|
2
|
+
local keys_key = "Queris:removing_from_keyspace:" .. keysearch
|
3
|
+
local keys
|
4
|
+
|
5
|
+
--relevant keys
|
6
|
+
if redis.call('zcard', keys_key) > 0 then
|
7
|
+
keys = redis.call('zrange', keys_key, 0, -1)
|
8
|
+
else
|
9
|
+
keys = redis.call('keys', keysearch)
|
10
|
+
if #keys > 0 then
|
11
|
+
for i,v in ipairs(keys) do
|
12
|
+
redis.call('zadd', keys_key, 0, v)
|
13
|
+
end
|
14
|
+
redis.call('expire', keys_key, ttl)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
local removed = 0
|
19
|
+
for i,key in ipairs(keys) do
|
20
|
+
local keytype= redis.call('type', key).ok
|
21
|
+
if keytype == 'zset' then
|
22
|
+
removed = removed + redis.call('zrem', key, element)
|
23
|
+
elseif keytype == 'set' then
|
24
|
+
removed = removed + redis.call('srem', key, element)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
return removed
|