redis_counters 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/CHANGELOG.md +38 -0
- data/Gemfile +3 -0
- data/Makefile +14 -0
- data/README.md +320 -0
- data/Rakefile +15 -0
- data/lib/redis_counters.rb +21 -0
- data/lib/redis_counters/base_counter.rb +84 -0
- data/lib/redis_counters/bucket.rb +59 -0
- data/lib/redis_counters/cluster.rb +22 -0
- data/lib/redis_counters/clusterize_and_partitionize.rb +194 -0
- data/lib/redis_counters/hash_counter.rb +70 -0
- data/lib/redis_counters/partition.rb +16 -0
- data/lib/redis_counters/unique_hash_counter.rb +51 -0
- data/lib/redis_counters/unique_values_lists/base.rb +57 -0
- data/lib/redis_counters/unique_values_lists/blocking.rb +167 -0
- data/lib/redis_counters/unique_values_lists/expirable.rb +155 -0
- data/lib/redis_counters/unique_values_lists/non_blocking.rb +91 -0
- data/lib/redis_counters/version.rb +3 -0
- data/redis_counters.gemspec +31 -0
- data/spec/redis_counters/base_spec.rb +29 -0
- data/spec/redis_counters/hash_counter_spec.rb +462 -0
- data/spec/redis_counters/unique_hash_counter_spec.rb +83 -0
- data/spec/redis_counters/unique_values_lists/blocking_spec.rb +94 -0
- data/spec/redis_counters/unique_values_lists/expirable_spec.rb +6 -0
- data/spec/redis_counters/unique_values_lists/non_blicking_spec.rb +6 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/unique_values_lists/common.rb +563 -0
- data/spec/support/unique_values_lists/expirable.rb +162 -0
- data/spec/support/unique_values_lists/set.rb +119 -0
- data/tasks/audit.rake +6 -0
- data/tasks/cane.rake +12 -0
- data/tasks/changelog.rake +7 -0
- data/tasks/coverage.rake +21 -0
- data/tasks/support.rb +24 -0
- metadata +242 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'redis_counters/hash_counter'
|
3
|
+
|
4
|
+
module RedisCounters
|
5
|
+
|
6
|
+
# HashCounter, с возможностью подсчета только уникальных значений.
|
7
|
+
|
8
|
+
class UniqueHashCounter < HashCounter
|
9
|
+
UNIQUE_LIST_POSTFIX = 'uq'.freeze
|
10
|
+
|
11
|
+
UNIQUE_LIST_POSTFIX_DELIMITER = '_'.freeze
|
12
|
+
|
13
|
+
attr_reader :unique_values_list
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def process_value
|
18
|
+
unique_values_list.add(params) { super }
|
19
|
+
end
|
20
|
+
|
21
|
+
def init
|
22
|
+
super
|
23
|
+
@unique_values_list = unique_values_list_class.new(
|
24
|
+
redis,
|
25
|
+
unique_values_list_options
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
def unique_values_list_options
|
30
|
+
options.fetch(:unique_list).merge!(:counter_name => unique_values_list_name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def unique_values_list_name
|
34
|
+
[counter_name, UNIQUE_LIST_POSTFIX].join(unique_list_postfix_delimiter)
|
35
|
+
end
|
36
|
+
|
37
|
+
def unique_values_list_class
|
38
|
+
unique_values_list_options.fetch(:list_class).to_s.constantize
|
39
|
+
end
|
40
|
+
|
41
|
+
def unique_list_postfix_delimiter
|
42
|
+
@unique_list_postfix_delimiter ||= options.fetch(:unique_list_postfix_delimiter, UNIQUE_LIST_POSTFIX_DELIMITER)
|
43
|
+
end
|
44
|
+
|
45
|
+
def partitions_keys(params = {})
|
46
|
+
# удаляем из списка партиций, ключи в которых хранятся списки уникальных значений
|
47
|
+
super.delete_if { |partition| partition.start_with?(unique_values_list_name) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'redis_counters/base_counter'
|
3
|
+
require 'redis_counters/clusterize_and_partitionize'
|
4
|
+
|
5
|
+
module RedisCounters
|
6
|
+
module UniqueValuesLists
|
7
|
+
|
8
|
+
# Базовый класс списка уникальных значений,
|
9
|
+
# с возможностью кластеризации и партиционирования.
|
10
|
+
|
11
|
+
class Base < RedisCounters::BaseCounter
|
12
|
+
include RedisCounters::ClusterizeAndPartitionize
|
13
|
+
|
14
|
+
alias_method :add, :process
|
15
|
+
alias_method :<<, :process
|
16
|
+
|
17
|
+
# Public: Проверяет существует ли заданное значение.
|
18
|
+
#
|
19
|
+
# params - Hash - параметры кластера и значения.
|
20
|
+
#
|
21
|
+
# Returns Boolean.
|
22
|
+
#
|
23
|
+
def has_value?(params)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def value
|
30
|
+
value_params = value_keys.map { |key| params.fetch(key) }
|
31
|
+
value_params.join(value_delimiter)
|
32
|
+
end
|
33
|
+
|
34
|
+
def value_keys
|
35
|
+
@value_keys ||= Array.wrap(options.fetch(:value_keys))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Protected: Возвращает данные партиции в виде массива хешей.
|
39
|
+
#
|
40
|
+
# Каждый элемент массива, представлен в виде хеша, содержащего все параметры уникального значения.
|
41
|
+
#
|
42
|
+
# cluster - Array - листовой кластер - массив параметров однозначно идентифицирующий кластер.
|
43
|
+
# partition - Array - листовая партиция - массив параметров однозначно идентифицирующий партицию.
|
44
|
+
#
|
45
|
+
# Returns Array of WithIndifferentAccess.
|
46
|
+
#
|
47
|
+
def partition_data(cluster, partition)
|
48
|
+
keys = value_keys
|
49
|
+
redis.smembers(key(partition, cluster)).inject(Array.new) do |result, (key, value)|
|
50
|
+
values = key.split(value_delimiter, -1) << value.to_i
|
51
|
+
result << Hash[keys.zip(values)].with_indifferent_access
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'redis_counters/unique_values_lists/base'
|
3
|
+
|
4
|
+
module RedisCounters
|
5
|
+
module UniqueValuesLists
|
6
|
+
|
7
|
+
# Список уникальных значений, на основе механизма оптимистических блокировок.
|
8
|
+
#
|
9
|
+
# смотри Optimistic locking using check-and-set:
|
10
|
+
# http://redis.io/topics/transactions
|
11
|
+
#
|
12
|
+
# Особенности:
|
13
|
+
# * Значения сохраняет в партициях;
|
14
|
+
# * Ведет список партиций;
|
15
|
+
# * Полностью транзакционен.
|
16
|
+
|
17
|
+
class Blocking < Base
|
18
|
+
PARTITIONS_LIST_POSTFIX = :partitions
|
19
|
+
|
20
|
+
# Public: Проверяет существует ли заданное значение.
|
21
|
+
#
|
22
|
+
# params - Hash - параметры кластера и значения.
|
23
|
+
#
|
24
|
+
# Returns Boolean.
|
25
|
+
#
|
26
|
+
def has_value?(params)
|
27
|
+
set_params(params)
|
28
|
+
reset_partitions_cache
|
29
|
+
value_already_exists?
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Нетранзакционно удаляет данные конкретной конечной партиции.
|
33
|
+
#
|
34
|
+
# params - Hash - хеш параметров, определяющий кластер и партицию.
|
35
|
+
# write_session - Redis - соединение с Redis, в рамках которого
|
36
|
+
# будет производится удаление (опционально).
|
37
|
+
# По умолчанию - основное соединение счетчика.
|
38
|
+
#
|
39
|
+
# Если передан блок, то вызывает блок, после удаления всех данных, в транзакции.
|
40
|
+
#
|
41
|
+
# Returns Nothing.
|
42
|
+
#
|
43
|
+
def delete_partition_direct!(params = {}, write_session = redis)
|
44
|
+
super(params, write_session)
|
45
|
+
|
46
|
+
# удаляем партицию из списка
|
47
|
+
return unless use_partitions?
|
48
|
+
|
49
|
+
cluster = ::RedisCounters::Cluster.new(self, params).params
|
50
|
+
partition = ::RedisCounters::Partition.new(self, params).params(:only_leaf => true)
|
51
|
+
|
52
|
+
partition = partition.flatten.join(key_delimiter)
|
53
|
+
write_session.lrem(partitions_list_key(cluster), 0, partition)
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def key(partition = partition_params, cluster = cluster_params)
|
59
|
+
return super if use_partitions?
|
60
|
+
|
61
|
+
raise 'Array required' if partition && !partition.is_a?(Array)
|
62
|
+
raise 'Array required' if cluster && !cluster.is_a?(Array)
|
63
|
+
|
64
|
+
[counter_name, cluster, partition].flatten.compact.join(key_delimiter)
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_value
|
68
|
+
loop do
|
69
|
+
reset_partitions_cache
|
70
|
+
|
71
|
+
watch_partitions_list
|
72
|
+
watch_all_partitions
|
73
|
+
|
74
|
+
if value_already_exists?
|
75
|
+
redis.unwatch
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
|
79
|
+
result = transaction do
|
80
|
+
add_value
|
81
|
+
add_partition
|
82
|
+
yield redis if block_given?
|
83
|
+
end
|
84
|
+
|
85
|
+
return true if result.present?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def reset_partitions_cache
|
90
|
+
@partitions = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def watch_partitions_list
|
94
|
+
return unless use_partitions?
|
95
|
+
redis.watch(partitions_list_key)
|
96
|
+
end
|
97
|
+
|
98
|
+
def watch_all_partitions
|
99
|
+
all_partitions.each do |partition|
|
100
|
+
redis.watch(key(partition))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def value_already_exists?
|
105
|
+
all_partitions.reverse.any? do |partition|
|
106
|
+
redis.sismember(key(partition), value)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_value
|
111
|
+
redis.sadd(key, value)
|
112
|
+
end
|
113
|
+
|
114
|
+
def all_partitions(cluster = cluster_params)
|
115
|
+
return @partitions unless @partitions.nil?
|
116
|
+
return (@partitions = [nil]) unless use_partitions?
|
117
|
+
|
118
|
+
@partitions = redis.lrange(partitions_list_key(cluster), 0, -1)
|
119
|
+
@partitions = @partitions.map do |partition|
|
120
|
+
partition.split(key_delimiter, -1)
|
121
|
+
end.delete_if(&:empty?)
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_partition
|
125
|
+
return unless use_partitions?
|
126
|
+
return unless new_partition?
|
127
|
+
redis.rpush(partitions_list_key, current_partition)
|
128
|
+
end
|
129
|
+
|
130
|
+
def partitions_list_key(cluster = cluster_params)
|
131
|
+
raise 'Array required' if cluster && !cluster.is_a?(Array)
|
132
|
+
|
133
|
+
[counter_name, cluster, PARTITIONS_LIST_POSTFIX].flatten.join(key_delimiter)
|
134
|
+
end
|
135
|
+
|
136
|
+
def current_partition
|
137
|
+
partition_params.flatten.join(key_delimiter)
|
138
|
+
end
|
139
|
+
|
140
|
+
def new_partition?
|
141
|
+
!all_partitions.include?(current_partition.split(key_delimiter))
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# Protected: Возвращает массив листовых партиций в виде ключей.
|
146
|
+
#
|
147
|
+
# Если кластер не указан и нет кластеризации в счетчике, то возвращает все партиции.
|
148
|
+
# Если партиция не указана, возвращает все партиции кластера (все партиции, если нет кластеризации).
|
149
|
+
#
|
150
|
+
# params - Hash - хеш параметров, определяющий кластер и партицию.
|
151
|
+
#
|
152
|
+
# Returns Array of Hash.
|
153
|
+
#
|
154
|
+
def partitions_keys(params = {})
|
155
|
+
reset_partitions_cache
|
156
|
+
|
157
|
+
cluster = ::RedisCounters::Cluster.new(self, params).params
|
158
|
+
partition = ::RedisCounters::Partition.new(self, params).params
|
159
|
+
|
160
|
+
partitions_keys = all_partitions(cluster).map { |part| key(part, cluster) }
|
161
|
+
|
162
|
+
fuzzy_pattern = key(partition, cluster)
|
163
|
+
partitions_keys.select { |part| part.start_with?(fuzzy_pattern) }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'redis_counters/unique_values_lists/blocking'
|
4
|
+
require 'active_support/core_ext/module/aliasing'
|
5
|
+
|
6
|
+
module RedisCounters
|
7
|
+
module UniqueValuesLists
|
8
|
+
|
9
|
+
# Список уникальных значений, с возможностью expire отдельных элементов.
|
10
|
+
#
|
11
|
+
# На основе сортированного множества.
|
12
|
+
# http://redis4you.com/code.php?id=010
|
13
|
+
#
|
14
|
+
# На основе механизма оптимистических блокировок.
|
15
|
+
# смотри Optimistic locking using check-and-set:
|
16
|
+
# http://redis.io/topics/transactions
|
17
|
+
#
|
18
|
+
# Особенности:
|
19
|
+
# * Expire - таймаут, можно установить как на уровне счетчика,
|
20
|
+
# так и на уровне отдельного занчения;
|
21
|
+
# * Очистка возможна как в автоматическогом режиме так в и ручном;
|
22
|
+
# * Значения сохраняет в партициях;
|
23
|
+
# * Ведет список партиций;
|
24
|
+
# * Полностью транзакционен.
|
25
|
+
#
|
26
|
+
# Пример:
|
27
|
+
#
|
28
|
+
# counter = RedisCounters::UniqueValuesLists::Expirable.new(redis,
|
29
|
+
# :counter_name => :sessions,
|
30
|
+
# :value_keys => [:session_id],
|
31
|
+
# :expire => 10.minutes
|
32
|
+
# )
|
33
|
+
#
|
34
|
+
# counter << session_id: 1
|
35
|
+
# counter << session_id: 2
|
36
|
+
# counter << session_id: 3, expire: :never
|
37
|
+
#
|
38
|
+
# counter.data
|
39
|
+
# > [{session_id: 1}, {session_id: 2}, {session_id: 3}]
|
40
|
+
#
|
41
|
+
# # after 10 minutes
|
42
|
+
#
|
43
|
+
# counter.data
|
44
|
+
# > [{session_id: 3}]
|
45
|
+
#
|
46
|
+
# counter.has_value?(session_id: 1)
|
47
|
+
# false
|
48
|
+
|
49
|
+
class Expirable < Blocking
|
50
|
+
DEFAULT_AUTO_CLEAN_EXPIRED = true
|
51
|
+
DEFAULT_VALUE_TIMEOUT = :never
|
52
|
+
|
53
|
+
NEVER_EXPIRE_TIMESTAMP = 0
|
54
|
+
|
55
|
+
# Public: Производит принудительную очистку expired - значений.
|
56
|
+
#
|
57
|
+
# cluster - Hash - параметры кластера, если используется кластеризация.
|
58
|
+
#
|
59
|
+
# Returns nothing.
|
60
|
+
#
|
61
|
+
def clean_expired(cluster = {})
|
62
|
+
set_params(cluster)
|
63
|
+
internal_clean_expired
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def add_value
|
69
|
+
redis.zadd(key, value_expire_timestamp, value)
|
70
|
+
end
|
71
|
+
|
72
|
+
def reset_partitions_cache
|
73
|
+
super
|
74
|
+
internal_clean_expired if auto_clean_expired?
|
75
|
+
end
|
76
|
+
|
77
|
+
alias_method :clean, :reset_partitions_cache
|
78
|
+
|
79
|
+
def current_timestamp
|
80
|
+
Time.now.to_i
|
81
|
+
end
|
82
|
+
|
83
|
+
def value_already_exists?
|
84
|
+
all_partitions.reverse.any? do |partition|
|
85
|
+
redis.zrank(key(partition), value).present?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def internal_clean_expired
|
90
|
+
all_partitions.each do |partition|
|
91
|
+
redis.zremrangebyscore(key(partition), "(#{NEVER_EXPIRE_TIMESTAMP}", current_timestamp)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def value_expire_timestamp
|
96
|
+
timeout = params[:expire] || default_value_expire
|
97
|
+
|
98
|
+
case timeout
|
99
|
+
when Symbol
|
100
|
+
NEVER_EXPIRE_TIMESTAMP
|
101
|
+
else
|
102
|
+
current_timestamp + timeout.to_i
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def default_value_expire
|
107
|
+
@default_value_expire ||= options[:expire].try(:seconds) || DEFAULT_VALUE_TIMEOUT
|
108
|
+
end
|
109
|
+
|
110
|
+
def auto_clean_expired?
|
111
|
+
@auto_clean_expired ||= options.fetch(:clean_expired, DEFAULT_AUTO_CLEAN_EXPIRED)
|
112
|
+
end
|
113
|
+
|
114
|
+
def partitions_with_clean(params = {})
|
115
|
+
clean_empty_partitions(params)
|
116
|
+
partitions_without_clean(params)
|
117
|
+
end
|
118
|
+
|
119
|
+
alias_method_chain :partitions, :clean
|
120
|
+
|
121
|
+
# Protected: Производит очистку expired - значений и пустых партиций.
|
122
|
+
#
|
123
|
+
# params - Hash - параметры кластера, если используется кластеризация.
|
124
|
+
#
|
125
|
+
# Returns nothing.
|
126
|
+
#
|
127
|
+
def clean_empty_partitions(params)
|
128
|
+
set_params(params)
|
129
|
+
clean
|
130
|
+
|
131
|
+
partitions_without_clean(params).each do |partition|
|
132
|
+
next if redis.zcard(key(partition.values)).nonzero?
|
133
|
+
delete_partition_direct!(params.merge(partition))
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Protected: Возвращает данные партиции в виде массива хешей.
|
138
|
+
#
|
139
|
+
# Каждый элемент массива, представлен в виде хеша, содержащего все параметры уникального значения.
|
140
|
+
#
|
141
|
+
# cluster - Array - листовой кластер - массив параметров однозначно идентифицирующий кластер.
|
142
|
+
# partition - Array - листовая партиция - массив параметров однозначно идентифицирующий партицию.
|
143
|
+
#
|
144
|
+
# Returns Array of WithIndifferentAccess.
|
145
|
+
#
|
146
|
+
def partition_data(cluster, partition)
|
147
|
+
keys = value_keys
|
148
|
+
redis.zrangebyscore(key(partition, cluster), '-inf', '+inf').inject(Array.new) do |result, (key, value)|
|
149
|
+
values = key.split(value_delimiter, -1) << value.to_i
|
150
|
+
result << Hash[keys.zip(values)].with_indifferent_access
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'redis_counters/unique_values_lists/base'
|
3
|
+
|
4
|
+
module RedisCounters
|
5
|
+
module UniqueValuesLists
|
6
|
+
|
7
|
+
# Список уникальных значений, на основе не блокирующего алгоритма.
|
8
|
+
#
|
9
|
+
# Особенности:
|
10
|
+
# * 2-х кратный расход памяти в случае использования партиций;
|
11
|
+
# * Не ведет список партиций;
|
12
|
+
# * Не транзакционен;
|
13
|
+
# * Методы delete_partitions! и delete_partition_direct!, удаляют только дублирующие партиции,
|
14
|
+
# но не удаляют данные из основной партиции.
|
15
|
+
# Для удаления основной партиции необходимо вызвать delete_main_partition!
|
16
|
+
# или воспользоваться методами delete_all! или delete_all_direct!,
|
17
|
+
# для удаления всех партиций кластера включая основную.
|
18
|
+
|
19
|
+
class NonBlocking < Base
|
20
|
+
|
21
|
+
# Public: Проверяет существует ли заданное значение.
|
22
|
+
#
|
23
|
+
# params - Hash - параметры кластера и значения.
|
24
|
+
#
|
25
|
+
# Returns Boolean.
|
26
|
+
#
|
27
|
+
def has_value?(params)
|
28
|
+
set_params(params)
|
29
|
+
redis.sismember(main_partition_key, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Public: Нетранзакционно удаляет все данные счетчика в кластере, включая основную партицию.
|
33
|
+
# Если кластеризация не используется, то удаляет все данные.
|
34
|
+
#
|
35
|
+
# cluster - Hash - хеш параметров, определяющих кластер.
|
36
|
+
# write_session - Redis - соединение с Redis, в рамках которого
|
37
|
+
# будет производится удаление (опционально).
|
38
|
+
# По умолчанию - основное соединение счетчика.
|
39
|
+
#
|
40
|
+
# Returns Nothing.
|
41
|
+
#
|
42
|
+
def delete_all_direct!(cluster, write_session = redis, parts = partitions(cluster))
|
43
|
+
super(cluster, write_session, parts)
|
44
|
+
delete_main_partition!(cluster, write_session)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Public: Удаляет основную партицию.
|
48
|
+
#
|
49
|
+
# cluster - Hash - хеш параметров, определяющих кластер.
|
50
|
+
# Опционально, если кластеризация не используется.
|
51
|
+
# write_session - Redis - соединение с Redis, в рамках которого
|
52
|
+
# будет производится удаление (опционально).
|
53
|
+
# По умолчанию - основное соединение счетчика.
|
54
|
+
#
|
55
|
+
# Returns Nothing.
|
56
|
+
#
|
57
|
+
def delete_main_partition!(cluster = {}, write_session = redis)
|
58
|
+
cluster = ::RedisCounters::Cluster.new(self, cluster).params
|
59
|
+
key = key(main_partition, cluster)
|
60
|
+
write_session.del(key)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def process_value
|
66
|
+
return unless add_value
|
67
|
+
yield redis if block_given?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_value
|
72
|
+
return unless redis.sadd(main_partition_key, value)
|
73
|
+
redis.sadd(current_partition_key, value) if use_partitions?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
def main_partition_key
|
78
|
+
key(main_partition)
|
79
|
+
end
|
80
|
+
|
81
|
+
def current_partition_key
|
82
|
+
key
|
83
|
+
end
|
84
|
+
|
85
|
+
def main_partition
|
86
|
+
[]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|