spymemcached.jruby 1.0.3-java → 1.0.4-java

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5780ea53b6d60b038125beb9dd617f8add8cbbc7
4
- data.tar.gz: e55cd318622f535a5351ab76d02b666b2294dbab
3
+ metadata.gz: de172a58da9de394e290392fe8e3797e917d98ca
4
+ data.tar.gz: c73d9b51e084d5858d7191a4a5ab93f6bd6642bd
5
5
  SHA512:
6
- metadata.gz: a78224ec0b00eb60041e3e0ccfaf2a97b37b79c139e6f7e766fafe9d0133fa292edd77b4b5e5e17bacd1d6bf2d2f880a37439c491f584d4e236da4bc96ce15d1
7
- data.tar.gz: e022c6ef66b52a9da19958a9753dcda754d536050305a3c0e87e62095894e0f8c16e3bb103fcec378bbdfacb26af09e932644c1b0c7c75c6e90c27a64c9b3303
6
+ metadata.gz: e7533c8391fb29bf4cabdfcdfb97319d4b0924f164d87e8e67e1fdda173135fd03bbb24ab863eadb0670928a1dbf345f3f29f8e36b1c3e523c35f7215d4eebbe
7
+ data.tar.gz: f035eca85fbb17adc7e5d493a8f0d84880f9e38fa7270893a7beac3bd5e7adffb1798971fae850ae9c756aad446897cc5c68d76980abe8cbc0314ac22f58536a
data/README.md CHANGED
@@ -0,0 +1,43 @@
1
+ Spymemcached.jruby
2
+ ================
3
+
4
+ A JRuby extension wraps the latest spymemcached client.
5
+
6
+ Usage
7
+ ----------------
8
+
9
+
10
+ Start a local networked memcached server:
11
+
12
+ $ memcached -p 11211
13
+
14
+ Require the library and instantiate a Spymemcached object at a global level:
15
+
16
+ require 'spymemcached'
17
+ $cache = Spymemcached.new("localhost:11211")
18
+
19
+ Setup multiple servers with options
20
+
21
+ require 'spymemcached'
22
+ $cache = Spymemcached.new(['memcached1.host:11211', 'memcached2.host:11211', 'memcached3.host:11211'],
23
+ {:namespace => 'appName', :timeout => 0.1, :binary => true})
24
+
25
+ Valid +options+ are:
26
+
27
+ [:namespace] Prepends this value to all keys added or retrieved.
28
+ [:timeout] Time to use as the socket read timeout, seconds. Defaults to 0.5 sec.
29
+ [:binary] Talks binary protocol with Memcached server. Default to true.
30
+
31
+ Rails 3 & 4
32
+
33
+ TODO
34
+
35
+ Rails 2.3
36
+
37
+ ActionController::Base.cache_store = :mem_cache_store, Spymemcached.new(servers).rails23
38
+
39
+
40
+ Performance
41
+ ---------------
42
+
43
+ [Benchmark result](https://github.com/ThoughtWorksStudios/memcached-client-benchmark) compared with gem dalli and jruby-memcached
data/lib/spymemcached.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'spymemcached-2.11.4.jar'
2
2
  require 'spymemcached_adapter.jar'
3
3
  require 'spymemcached_adapter'
4
+ require 'digest/md5'
4
5
 
5
6
  #
6
7
  # Memcached client Spymemcached JRuby extension
@@ -9,6 +10,7 @@ class Spymemcached
9
10
  class Error < StandardError; end
10
11
  class TimeoutError < Error; end
11
12
 
13
+ ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
12
14
  # default options for client
13
15
  DEFAULT_OPTIONS = {
14
16
  :timeout => 0.5, # second
@@ -49,53 +51,54 @@ class Spymemcached
49
51
  end
50
52
 
51
53
  def get(key)
52
- @client.get(ns(key))
54
+ @client.get(encode(key))
53
55
  end
54
56
  alias :[] :get
55
57
 
56
58
  def get_multi(*keys)
57
- Hash[@client.get_multi(keys.map(&method(:ns))).map {|k, v| [unns(k), v]}]
59
+ key_map = Hash[keys.flatten.compact.map {|k| [encode(k), k]}]
60
+ Hash[@client.get_multi(key_map.keys).map {|k, v| [key_map[k], v]}]
58
61
  end
59
62
 
60
- def add(key, value, ttl=0, opts={})
61
- @client.add(ns(key), value, ttl)
63
+ def add(key, value, ttl=0)
64
+ @client.add(encode(key), value, ttl)
62
65
  end
63
66
 
64
- def set(key, value, ttl=0, opts={})
65
- @client.set(ns(key), value, ttl)
67
+ def set(key, value, ttl=0)
68
+ @client.set(encode(key), value, ttl)
66
69
  end
67
70
  alias :[]= :set
68
71
 
69
72
  def cas(key, ttl=0, &block)
70
- @client.cas(ns(key), ttl, &block)
73
+ @client.cas(encode(key), ttl, &block)
71
74
  end
72
75
 
73
76
  def replace(key, value, ttl=0)
74
- @client.replace(ns(key), value, ttl)
77
+ @client.replace(encode(key), value, ttl)
75
78
  end
76
79
 
77
80
  def delete(key)
78
- @client.delete(ns(key))
81
+ @client.delete(encode(key))
79
82
  end
80
83
 
81
84
  def incr(key, by=1)
82
- @client.incr(ns(key), by)
85
+ @client.incr(encode(key), by)
83
86
  end
84
87
 
85
88
  def decr(key, by=1)
86
- @client.decr(ns(key), by)
89
+ @client.decr(encode(key), by)
87
90
  end
88
91
 
89
92
  def append(key, value)
90
- @client.append(ns(key), value)
93
+ @client.append(encode(key), value)
91
94
  end
92
95
 
93
96
  def prepend(key, value)
94
- @client.prepend(ns(key), value)
97
+ @client.prepend(encode(key), value)
95
98
  end
96
99
 
97
100
  def touch(key, ttl=0)
98
- @client.touch(ns(key), ttl)
101
+ @client.touch(encode(key), ttl)
99
102
  end
100
103
 
101
104
  def stats
@@ -116,29 +119,31 @@ class Spymemcached
116
119
  @client.shutdown
117
120
  end
118
121
 
119
- # compatible api
122
+ # compatible api with Rails 2.3 MemcacheStore
123
+ # ActionController::Base.cache_store = :mem_cache_store, Spymemcached.new(servers).rails23
120
124
  def rails23
121
125
  require 'spymemcached/rails23'
122
126
  Rails23.new(self)
123
127
  end
124
128
 
125
129
  private
126
- def raw?(opts)
127
- opts.is_a?(Hash) ? opts[:raw] : opts
130
+ def encode(key)
131
+ escape_key(namespace ? "#{namespace.call}:#{key}" : key)
128
132
  end
129
133
 
130
- def ns(key)
131
- return key unless namespace
132
- "#{namespace.call}:#{key}"
134
+ def namespace
135
+ @namespace
133
136
  end
134
137
 
135
- def unns(k)
136
- return k unless namespace
137
- @ns_size ||= namespace.call.size + 1
138
- k[@ns_size..-1]
138
+ # Memcache keys are binaries. So we need to force their encoding to binary
139
+ # before applying the regular expression to ensure we are escaping all
140
+ # characters properly.
141
+ def escape_key(key)
142
+ key = key.to_s.dup
143
+ key = key.force_encoding(Encoding::ASCII_8BIT)
144
+ key = key.gsub(ESCAPE_KEY_CHARS){ |match| "%#{match.getbyte(0).to_s(16).upcase}" }
145
+ key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
146
+ key
139
147
  end
140
148
 
141
- def namespace
142
- @namespace
143
- end
144
149
  end
@@ -74,6 +74,7 @@ class SpymemcachedBinaryProtocolTest < Test::Unit::TestCase
74
74
  assert_equal(2, ret.size)
75
75
  assert_equal('v1', ret['k1'])
76
76
  assert_equal(Msg.new('v2'), ret['k2'])
77
+ assert_equal(ret, @client.get_multi(['k1', 'k2', 'k3']))
77
78
  end
78
79
 
79
80
  def test_cas
@@ -74,6 +74,7 @@ class SpymemcachedPlainProtocolTest < Test::Unit::TestCase
74
74
  assert_equal(2, ret.size)
75
75
  assert_equal('v1', ret['k1'])
76
76
  assert_equal(Msg.new('v2'), ret['k2'])
77
+ assert_equal(ret, @client.get_multi(['k1', 'k2', 'k3']))
77
78
  end
78
79
 
79
80
  def test_cas
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'test_helper'
2
3
 
3
4
  class SpymemcachedTest < Test::Unit::TestCase
@@ -172,4 +173,12 @@ class SpymemcachedTest < Test::Unit::TestCase
172
173
  assert_match(/\:11211/, v.keys.first)
173
174
  assert_match(/\d\.\d+\.\d+/, v.values.first)
174
175
  end
176
+
177
+ def test_escape_key
178
+ k = 'k 开' * 250
179
+ @client.add(k, 'v1')
180
+ assert_equal('v1', @client.get(k))
181
+ @client.set(k, 'v2')
182
+ assert_equal({k => 'v2'}, @client.get_multi(k))
183
+ end
175
184
  end
data/test/test_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'test/unit'
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
3
  require "spymemcached"
3
4
 
4
5
  class Msg < Struct.new(:name)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spymemcached.jruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: java
6
6
  authors:
7
7
  - Xiao Li
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-27 00:00:00.000000000 Z
11
+ date: 2014-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake