xunch 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/xunch.rb +25 -0
- data/lib/xunch/cache/cache.rb +88 -0
- data/lib/xunch/cache/cache_builder.rb +68 -0
- data/lib/xunch/cache/field_object_cache.rb +120 -0
- data/lib/xunch/cache/list_field_object_cache.rb +63 -0
- data/lib/xunch/cache/list_object_cache.rb +59 -0
- data/lib/xunch/cache/object_cache.rb +63 -0
- data/lib/xunch/codec/codec.rb +31 -0
- data/lib/xunch/codec/hash_codec.rb +98 -0
- data/lib/xunch/codec/json_codec.rb +81 -0
- data/lib/xunch/shard/redis.rb +270 -0
- data/lib/xunch/shard/shard_info.rb +37 -0
- data/lib/xunch/shard/shard_redis.rb +267 -0
- data/lib/xunch/shard/sharded.rb +50 -0
- data/lib/xunch/utils/exceptions.rb +11 -0
- data/lib/xunch/utils/nginx_cache_helper.rb +52 -0
- data/lib/xunch/utils/rb_tree.rb +634 -0
- data/lib/xunch/utils/rb_tree_node.rb +67 -0
- data/lib/xunch/utils/types.rb +8 -0
- data/lib/xunch/utils/utils.rb +24 -0
- data/test/benchmark_test.rb +68 -0
- data/test/cache_builder_test.rb +28 -0
- data/test/cache_object.rb +120 -0
- data/test/consistency_hash_test.rb +31 -0
- data/test/field_object_cache_test.rb +430 -0
- data/test/hash_codec_test.rb +57 -0
- data/test/json_codec_test.rb +57 -0
- data/test/list_field_object_cache_test.rb +211 -0
- data/test/list_object_cache_test.rb +211 -0
- data/test/nginx_cache_helper_test.rb +45 -0
- data/test/object_cache_test.rb +322 -0
- data/test/rb_tree_test.rb +48 -0
- data/test/redis_benchmark_test.rb +54 -0
- data/test/redis_test.rb +58 -0
- data/test/running_test.rb +212 -0
- data/test/test.rb +176 -0
- data/test/track_record_origin.rb +58 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 11095eadd1ac6cf93128811cd1bab2d818e345b1
|
4
|
+
data.tar.gz: 8e60835af4879fd33dfa4fe7cfc67d009548d5c2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6b7ca3c02e48930d5d7b551a8393c677493d3ac74ba6dc69fbf54249233ff2804d62f353e93324b62449b255b76635e39d25a8a4ba98dca17ee3a697e9d934fa
|
7
|
+
data.tar.gz: fed73c21df8039c4622c9ca91328f66aa5cc933f61a2230af0bd5c870804b41a1e502abeee45f875652168bcb04158947c2a2c1a6f734e183351d69f8e1041a3
|
data/lib/xunch.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yajl'
|
2
|
+
require 'date'
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'murmurhash'
|
5
|
+
require 'redis'
|
6
|
+
require 'yaml'
|
7
|
+
require 'xunch/utils/rb_tree'
|
8
|
+
require 'xunch/utils/rb_tree_node'
|
9
|
+
require 'xunch/utils/exceptions'
|
10
|
+
require 'xunch/utils/types'
|
11
|
+
require 'xunch/utils/utils'
|
12
|
+
require 'xunch/utils/nginx_cache_helper'
|
13
|
+
require 'xunch/shard/shard_info'
|
14
|
+
require 'xunch/shard/sharded'
|
15
|
+
require 'xunch/shard/shard_redis'
|
16
|
+
require 'xunch/shard/redis'
|
17
|
+
require 'xunch/codec/codec'
|
18
|
+
require 'xunch/codec/json_codec'
|
19
|
+
require 'xunch/codec/hash_codec'
|
20
|
+
require 'xunch/cache/cache'
|
21
|
+
require 'xunch/cache/object_cache'
|
22
|
+
require 'xunch/cache/field_object_cache'
|
23
|
+
require 'xunch/cache/list_field_object_cache'
|
24
|
+
require 'xunch/cache/list_object_cache'
|
25
|
+
require 'xunch/cache/cache_builder'
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Xunch
|
2
|
+
class Cache
|
3
|
+
|
4
|
+
def initialize(options, shard_infos)
|
5
|
+
@options = initialize_options(options)
|
6
|
+
@shard_redis = ShardRedis.new(@options[:regex],shard_infos)
|
7
|
+
end
|
8
|
+
|
9
|
+
def evict(key)
|
10
|
+
@shard_redis.del(assembleKey(key))
|
11
|
+
end
|
12
|
+
|
13
|
+
def batch_evict(keys)
|
14
|
+
new_keys = []
|
15
|
+
keys.each { |key|
|
16
|
+
new_keys.push assembleKey(key)
|
17
|
+
}
|
18
|
+
@shard_redis.batch_del(new_keys)
|
19
|
+
end
|
20
|
+
|
21
|
+
def destroy
|
22
|
+
@shard_redis.destroy
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
def getCacheObjectKey(value)
|
27
|
+
key = value.send(@options[:key_field_name])
|
28
|
+
raise ArgumentError("value #{value} key field can not be nil.") unless key != nil
|
29
|
+
key
|
30
|
+
end
|
31
|
+
|
32
|
+
def assembleKey(key)
|
33
|
+
name = @options[:name]
|
34
|
+
name + "_".concat(key.to_s).concat("_").concat(@options[:version].to_s)
|
35
|
+
end
|
36
|
+
|
37
|
+
def assembleTempKey(key)
|
38
|
+
name = @options[:name]
|
39
|
+
name + "_".concat(key.to_s).concat("_").concat(@options[:version].to_s).concat("_temp")
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize_options(options)
|
43
|
+
use_options = {}
|
44
|
+
expire_time = 60 * 60 * 24 * 1000
|
45
|
+
if(options["expire_time"] != nil)
|
46
|
+
expire_time = options["expire_time"]
|
47
|
+
end
|
48
|
+
use_options.store(:expire_time, expire_time)
|
49
|
+
|
50
|
+
if(options["cache_class"] != nil)
|
51
|
+
cache_class = eval(options["cache_class"])
|
52
|
+
elsif options["type"] != CacheType::LISTOBJECT && options["type"] != CacheType::LISTFIELDOBJECT
|
53
|
+
raise ArgumentError, "cache_class is nil"
|
54
|
+
end
|
55
|
+
use_options.store(:cache_class, cache_class)
|
56
|
+
|
57
|
+
version = 1
|
58
|
+
if(options["version"] != nil)
|
59
|
+
version = options["version"]
|
60
|
+
use_options.store(:version, version)
|
61
|
+
end
|
62
|
+
|
63
|
+
if(options["name"] != nil)
|
64
|
+
name = options["name"]
|
65
|
+
use_options.store(:name, name)
|
66
|
+
end
|
67
|
+
|
68
|
+
if(options["key_field_name"] != nil)
|
69
|
+
key_field_name = options["key_field_name"]
|
70
|
+
use_options.store(:key_field_name, key_field_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
if(options["timeout"] != nil)
|
74
|
+
timeout = options["timeout"]
|
75
|
+
use_options.store(:timeout, timeout)
|
76
|
+
end
|
77
|
+
|
78
|
+
regex = '[0-9]+'
|
79
|
+
if(options["regex"] != nil)
|
80
|
+
regex = options["regex"]
|
81
|
+
end
|
82
|
+
use_options.store(:regex, regex)
|
83
|
+
|
84
|
+
return use_options
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Xunch
|
2
|
+
class CacheBuilder
|
3
|
+
# every cache config hava attributes below:
|
4
|
+
# ['type'] => the cache type, have object|field_object|list_object
|
5
|
+
# ['name'] => the cache name, used for redis key prefix
|
6
|
+
# ['version'] => the cache version, maybe you change your cache object format and you will change a version of the cache
|
7
|
+
# ['expire_time'] => cache expire time for every key in millisecond
|
8
|
+
# ['cache_class'] => which type of object you cache, this will help us to encode/decode your object
|
9
|
+
# ['key_field_name'] => define which field in the object we used for redis key
|
10
|
+
# ['regex'] => a regex string which used for match consistency hash key
|
11
|
+
# ['shard_infos'] => define which redis instance we used for caching
|
12
|
+
#
|
13
|
+
#
|
14
|
+
def self.build(file)
|
15
|
+
configs = YAML.load_file(file)
|
16
|
+
shard_info_configs = configs["shard_infos"]
|
17
|
+
cache_configs = configs["caches"]
|
18
|
+
|
19
|
+
shards = {}
|
20
|
+
shard_info_configs.each_value { |shard_info_config|
|
21
|
+
options = {}
|
22
|
+
shard_info_config.each { |k,v|
|
23
|
+
options[k.to_sym] = v
|
24
|
+
}
|
25
|
+
shards[options[:name]] = ShardInfo.new(options)
|
26
|
+
}
|
27
|
+
caches = {}
|
28
|
+
lazy_caches = {}
|
29
|
+
cache_configs.each_value { |cache_config|
|
30
|
+
shard_names = cache_config["shards"].split(",")
|
31
|
+
shard_infos = []
|
32
|
+
shard_names.each { |shard_name|
|
33
|
+
shard_infos.push(shards[shard_name])
|
34
|
+
}
|
35
|
+
case cache_config["type"]
|
36
|
+
when CacheType::OBJECT
|
37
|
+
cache = Xunch::ObjectCache.new(cache_config,shard_infos)
|
38
|
+
caches[cache_config["name"]] = cache
|
39
|
+
when CacheType::FIELDOBJECT
|
40
|
+
cache = Xunch::FieldObjectCache.new(cache_config,shard_infos)
|
41
|
+
caches[cache_config["name"]] = cache
|
42
|
+
when CacheType::LISTOBJECT
|
43
|
+
lazy_caches[cache_config] = shard_infos
|
44
|
+
when CacheType::LISTFIELDOBJECT
|
45
|
+
lazy_caches[cache_config] = shard_infos
|
46
|
+
else
|
47
|
+
raise XunchConfigError.new("Unknown cache type #{cache_config["type"]}.")
|
48
|
+
end
|
49
|
+
}
|
50
|
+
lazy_caches.each { |cache_config,shard_infos|
|
51
|
+
delegate = caches[cache_config["delegate"]]
|
52
|
+
raise XunchConfigError.new("list_cache init error, delegate does not exist.") unless delegate != nil
|
53
|
+
cache = nil
|
54
|
+
case cache_config["type"]
|
55
|
+
when CacheType::LISTOBJECT
|
56
|
+
cache = Xunch::ListObjectCache.new(cache_config,shard_infos,delegate)
|
57
|
+
when CacheType::LISTFIELDOBJECT
|
58
|
+
cache = Xunch::ListFieldObjectCache.new(cache_config,shard_infos,delegate)
|
59
|
+
else
|
60
|
+
raise XunchConfigError.new("Unknown cache type #{cache_config["type"]}.")
|
61
|
+
end
|
62
|
+
|
63
|
+
caches[cache_config["name"]] = cache
|
64
|
+
}
|
65
|
+
caches
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Xunch
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
#
|
6
|
+
class FieldObjectCache < Cache
|
7
|
+
|
8
|
+
def initialize(options, shard_infos)
|
9
|
+
super
|
10
|
+
fields = options['fields']
|
11
|
+
if fields == nil
|
12
|
+
raise XunchConfigError.new("fields can not be nil")
|
13
|
+
end
|
14
|
+
fields_array = fields.split(",")
|
15
|
+
if fields_array.length == 1 and fields_array[0].strip.empty?
|
16
|
+
raise XunchConfigError.new("fields config error")
|
17
|
+
end
|
18
|
+
formatted_fields_array = Utils.format_fields(fields_array)
|
19
|
+
@fields_array = formatted_fields_array
|
20
|
+
@codec = HashCodec.new(@options[:cache_class],formatted_fields_array)
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(key)
|
24
|
+
redis_key = assembleKey(key)
|
25
|
+
data = @shard_redis.mapped_hget(redis_key,@fields_array)
|
26
|
+
@codec.decode(data)
|
27
|
+
end
|
28
|
+
|
29
|
+
def put(value)
|
30
|
+
putex(value,@options[:expire_time])
|
31
|
+
end
|
32
|
+
|
33
|
+
def putex(value, ttl)
|
34
|
+
if(value == nil)
|
35
|
+
return
|
36
|
+
end
|
37
|
+
key = getCacheObjectKey(value)
|
38
|
+
key = assembleKey(key)
|
39
|
+
data = @codec.encode(value)
|
40
|
+
@shard_redis.hsetall(key,data,ttl)
|
41
|
+
end
|
42
|
+
|
43
|
+
def multi_get(keys)
|
44
|
+
redis_keys = Array.new(keys.length)
|
45
|
+
for i in 0 .. keys.length - 1 do
|
46
|
+
redis_keys[i] = assembleKey(keys[i])
|
47
|
+
end
|
48
|
+
datas = @shard_redis.mapped_hmget(redis_keys,@fields_array)
|
49
|
+
for i in 0 .. datas.length - 1 do
|
50
|
+
datas[i] = @codec.decode(datas[i])
|
51
|
+
end
|
52
|
+
return datas
|
53
|
+
end
|
54
|
+
|
55
|
+
def multi_put(values)
|
56
|
+
multi_putex(values,@options[:expire_time])
|
57
|
+
end
|
58
|
+
|
59
|
+
def multi_putex(values,ttl)
|
60
|
+
kvs = Hash.new
|
61
|
+
values.each { | value |
|
62
|
+
if value == nil
|
63
|
+
next
|
64
|
+
end
|
65
|
+
key = getCacheObjectKey(value)
|
66
|
+
redis_key = assembleKey(key);
|
67
|
+
kvs[redis_key] = @codec.encode(value);
|
68
|
+
}
|
69
|
+
@shard_redis.hmsetall(kvs, ttl);
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_with_field(key, fields)
|
73
|
+
redis_key = assembleKey(key)
|
74
|
+
data = @shard_redis.mapped_hget(redis_key,fields)
|
75
|
+
@codec.decode_fields(data,fields)
|
76
|
+
end
|
77
|
+
|
78
|
+
def put_with_field(value, fields)
|
79
|
+
put_with_field_ex(value,@options[:expire_time],fields)
|
80
|
+
end
|
81
|
+
|
82
|
+
def put_with_field_ex(value, ttl, fields)
|
83
|
+
if(value == nil)
|
84
|
+
return
|
85
|
+
end
|
86
|
+
key = getCacheObjectKey(value)
|
87
|
+
key = assembleKey(key)
|
88
|
+
data = @codec.encode_fields(value,fields)
|
89
|
+
@shard_redis.hsetall(key,data,ttl)
|
90
|
+
end
|
91
|
+
|
92
|
+
def multi_put_with_field_ex(values, ttl, fields)
|
93
|
+
kvs = Hash.new
|
94
|
+
values.each { | value |
|
95
|
+
if value == nil
|
96
|
+
next
|
97
|
+
end
|
98
|
+
key = getCacheObjectKey(value)
|
99
|
+
key = assembleKey(key);
|
100
|
+
kvs[key] = @codec.encode_fields(value,fields);
|
101
|
+
}
|
102
|
+
@shard_redis.hmsetall(kvs, ttl);
|
103
|
+
end
|
104
|
+
|
105
|
+
def multi_put_with_field(values, fields)
|
106
|
+
multi_put_with_field_ex(values,@options[:expire_time],fields)
|
107
|
+
end
|
108
|
+
|
109
|
+
def multi_get_with_field(keys, fields)
|
110
|
+
for i in 0 .. keys.length - 1 do
|
111
|
+
keys[i] = assembleKey(keys[i])
|
112
|
+
end
|
113
|
+
datas = @shard_redis.mapped_hmget(keys,fields)
|
114
|
+
for i in 0 .. datas.length - 1 do
|
115
|
+
datas[i] = @codec.decode_fields(datas[i],fields)
|
116
|
+
end
|
117
|
+
return datas
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Xunch
|
2
|
+
#列表缓存目前不支持并发写入,未来也不打算支持并发
|
3
|
+
#主要的使用场景是发现页热门的单线程写入和并发的读取
|
4
|
+
#并且提供remove接口,帮助从列表中移除已经不存在的声音,用户,专辑
|
5
|
+
class ListFieldObjectCache < Cache
|
6
|
+
|
7
|
+
def initialize(options, shard_infos, object_cache)
|
8
|
+
super(options,shard_infos)
|
9
|
+
@delegate = object_cache
|
10
|
+
end
|
11
|
+
|
12
|
+
# 查询接口
|
13
|
+
# @key 列表的key
|
14
|
+
# @page 页码
|
15
|
+
# @size 页大小
|
16
|
+
#
|
17
|
+
def get(key, page, size)
|
18
|
+
raise "key can not be nil." unless key != nil
|
19
|
+
raise "page must be a positive number." unless page > 0
|
20
|
+
raise "size must be a positive number and less than 100." unless page != nil or size < 100
|
21
|
+
start = (page - 1) * size;
|
22
|
+
stop = page * size - 1;
|
23
|
+
new_key = assembleKey(key)
|
24
|
+
object_keys = @shard_redis.lrange(new_key,start,stop)
|
25
|
+
hash = {}
|
26
|
+
hash["keys"] = object_keys
|
27
|
+
hash["values"] = @delegate.multi_get(object_keys)
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def put(key, values)
|
32
|
+
raise "key can not be nil." unless key != nil
|
33
|
+
raise "values can not be nil." unless values != nil
|
34
|
+
sub_keys = []
|
35
|
+
values.each { | value |
|
36
|
+
raise "value in values can not be nil." unless value != nil
|
37
|
+
sub_keys.push(@delegate.getCacheObjectKey(value))
|
38
|
+
}
|
39
|
+
temp_key = assembleTempKey(key)
|
40
|
+
new_key = assembleKey(key)
|
41
|
+
@delegate.multi_putex(values,@options[:expire_time])
|
42
|
+
@shard_redis.lset(temp_key,new_key,sub_keys,@options[:expire_time])
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove(key, sub_key)
|
46
|
+
raise "key can not be nil." unless key != nil
|
47
|
+
raise "sub_key can not be nil." unless sub_key != nil
|
48
|
+
new_key = assembleKey(key)
|
49
|
+
@shard_redis.lremove(new_key,sub_key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def size(key)
|
53
|
+
raise "key can not be nil." unless key != nil
|
54
|
+
new_key = assembleKey(key)
|
55
|
+
@shard_redis.llen(new_key)
|
56
|
+
end
|
57
|
+
|
58
|
+
def delegate
|
59
|
+
@delegate
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Xunch
|
2
|
+
#列表缓存目前不支持并发写入,未来也不打算支持并发
|
3
|
+
#主要的使用场景是发现页热门的单线程写入和并发的读取
|
4
|
+
#并且提供remove接口,帮助从列表中移除已经不存在的声音,用户,专辑
|
5
|
+
class ListObjectCache < Cache
|
6
|
+
|
7
|
+
def initialize(options, shard_infos, object_cache)
|
8
|
+
super(options,shard_infos)
|
9
|
+
@delegate = object_cache
|
10
|
+
end
|
11
|
+
|
12
|
+
# 查询接口
|
13
|
+
# @key 列表的key
|
14
|
+
# @page 页码
|
15
|
+
# @size 页大小
|
16
|
+
#
|
17
|
+
def get(key, page, size)
|
18
|
+
raise "key can not be nil." unless key != nil
|
19
|
+
raise "page must be a positive number." unless page > 0
|
20
|
+
raise "size must be a positive number and less than 100." unless page != nil or size < 100
|
21
|
+
start = (page - 1) * size;
|
22
|
+
stop = page * size - 1;
|
23
|
+
new_key = assembleKey(key)
|
24
|
+
object_keys = @shard_redis.lrange(new_key,start,stop)
|
25
|
+
hash = {}
|
26
|
+
hash["keys"] = object_keys
|
27
|
+
hash["values"] = @delegate.multi_get(object_keys)
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def put(key, values)
|
32
|
+
raise "key can not be nil." unless key != nil
|
33
|
+
raise "values can not be nil." unless values != nil
|
34
|
+
sub_keys = []
|
35
|
+
values.each { | value |
|
36
|
+
raise "value in values can not be nil." unless value != nil
|
37
|
+
sub_keys.push(@delegate.getCacheObjectKey(value))
|
38
|
+
}
|
39
|
+
temp_key = assembleTempKey(key)
|
40
|
+
new_key = assembleKey(key)
|
41
|
+
@delegate.multi_putex(values,@options[:expire_time])
|
42
|
+
@shard_redis.lset(temp_key,new_key,sub_keys,@options[:expire_time])
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove(key, sub_key)
|
46
|
+
raise "key can not be nil." unless key != nil
|
47
|
+
raise "sub_key can not be nil." unless sub_key != nil
|
48
|
+
new_key = assembleKey(key)
|
49
|
+
@shard_redis.lremove(new_key,sub_key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def size(key)
|
53
|
+
raise "key can not be nil." unless key != nil
|
54
|
+
new_key = assembleKey(key)
|
55
|
+
@shard_redis.llen(new_key)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Xunch
|
2
|
+
class ObjectCache < Cache
|
3
|
+
|
4
|
+
def initialize(options, shard_infos)
|
5
|
+
super
|
6
|
+
@codec = JsonCodec.new(@options[:cache_class])
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(key)
|
10
|
+
redis_key = assembleKey(key)
|
11
|
+
data = @shard_redis.get(redis_key)
|
12
|
+
if data != nil
|
13
|
+
@codec.decode(data)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def put(value)
|
18
|
+
putex(value,@options[:expire_time])
|
19
|
+
end
|
20
|
+
|
21
|
+
def putex(value, ttl)
|
22
|
+
if(value == nil)
|
23
|
+
return
|
24
|
+
end
|
25
|
+
key = getCacheObjectKey(value)
|
26
|
+
key = assembleKey(key)
|
27
|
+
data = @codec.encode(value)
|
28
|
+
@shard_redis.set(key,data,ttl.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def multi_get(keys)
|
32
|
+
redis_keys = Array.new(keys.length)
|
33
|
+
for i in 0 .. keys.length - 1 do
|
34
|
+
redis_keys[i] = assembleKey(keys[i])
|
35
|
+
end
|
36
|
+
datas = @shard_redis.mget(redis_keys)
|
37
|
+
for i in 0 .. datas.length - 1 do
|
38
|
+
if datas[i] != nil
|
39
|
+
datas[i] = @codec.decode(datas[i])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
datas
|
43
|
+
end
|
44
|
+
|
45
|
+
def multi_put(values)
|
46
|
+
multi_putex(values,@options[:expire_time])
|
47
|
+
end
|
48
|
+
|
49
|
+
def multi_putex(values,ttl)
|
50
|
+
kvs = Hash.new
|
51
|
+
values.each { | value |
|
52
|
+
if value == nil
|
53
|
+
next
|
54
|
+
end
|
55
|
+
key = getCacheObjectKey(value)
|
56
|
+
key = assembleKey(key);
|
57
|
+
kvs[key] = @codec.encode(value);
|
58
|
+
}
|
59
|
+
@shard_redis.mset(kvs, ttl);
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|