jruby-memcache-client-thoughtworks 1.8.0

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2008 Abhi Yerra <abhi@traytwo.com>
2
+ Copyright (c) 2009 Ikai Lan <ikai.lan@gmail.com>
3
+ Copyright (c) 2009 Tiago Bastos <comechao@gmail.com>
4
+ Copyright (c) 2009 Frederic Jean <frederic.jean@sun.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
data/README ADDED
@@ -0,0 +1,84 @@
1
+ This is forked version of jruby-memcached-client gem. It was forked and published as its own gem because the original owners have not published an updated gem for 3 years. Also the published gem depends on the development version of the jar and throws ugly exceptions when connection is lost.
2
+ - Sudhindra Rao
3
+ _____________________________________________________________________________________________________________________
4
+
5
+ This projects provides memcached based stores for JRuby. It is a gem based on Ikai Lan's jruby-memcache-client project hosted at http://github.com/ikai/jruby-memcache-client/tree
6
+
7
+ This project is a JRuby wrapper of the Java MemCache library by Greg Whalin
8
+
9
+ http://www.whalin.com/memcached/
10
+
11
+ In production, the standard Ruby MemCache client can cause a thread to hang. In the Glassfish application server, by default there are 5 Grizzly connectors that handle incoming requests. A site that uses MemCache heavily can quickly cause all Grizzly connectors to block and take down a site. I'm hoping that this work I am doing here will help others adopt JRuby as a production platform for their Ruby on Rails applications.
12
+
13
+ The Ruby MemCache library was never written with threaded applications in mind. All threads use the same socket, and multithreaded mode basically wraps the IO with a Mutex. The Java library provides several features that are not available in the Ruby MemCache library:
14
+
15
+ - connection pooling
16
+ - socket timeouts. In forks of the Ruby MemCache library this is achieved either with a Mongrel timeout or use of the Ruby Timeout class, which, at least at the writing of this README, will work unpredictably when being used as a failsafe against hanging IO.
17
+
18
+ As of right now this code only provides a very minimal amount of functionality, but it is enough to use with the Rails cache and cache_fu.
19
+
20
+ Installation
21
+ ------------
22
+ This is a ruby gem that can be installed from gemcutter.org.
23
+
24
+ You will first need to install the gemcutter gem and configure your system to use it:
25
+
26
+ jruby -S gem install gemcutter
27
+ jruby -S gem tumble
28
+
29
+ You will then be able to install the JRuby Memcache Client gem:
30
+
31
+ jruby -S gem install jruby-memcache-client
32
+
33
+ Java Requirements
34
+ -----------------
35
+
36
+ The underlying library used for this project was compiled using Java 6. You will not be able to run this gem under Java 5 out of the box. You can however clone http://github.com/gwhalin/Memcached-Java-Client and attempt to build it under Java 5 if you must. (You really should consider upgrading to Java 6 since Oracle no longer supports Java 5.)
37
+
38
+ Replacing Rail's MemCache Client
39
+ --------------------------------
40
+
41
+ Rails ships with a bundled copy of the MemCache client. This client will prevent you from using this gem instead. Adding the following code into your environment.rb file:
42
+
43
+ if RUBY_PLATFORM =~ /java/i
44
+ # Based on instructions from http://www.mikeperham.com/2009/03/03/using-memcache-client-16x-in-rails-23/
45
+ # Brain surgery to use our own version of memcache-client without
46
+ # having to modify activesupport directly.
47
+ # Unload any previous instance of the class
48
+ if Object.const_defined? :MemCache
49
+ Object.instance_eval { remove_const :MemCache }
50
+ end
51
+ # Pull in the exact version we want
52
+ gem 'jruby-memcache-client', '1.6.1'
53
+
54
+ # Ensure that the memcache-client path is at the front of the loadpath
55
+ $LOAD_PATH.each do |path|
56
+ if path =~ /jruby-memcache-client/
57
+ $LOAD_PATH.delete(path)
58
+ $LOAD_PATH.unshift(path)
59
+ end
60
+ end
61
+ # If Ruby thinks it's already loaded memcache.rb, force
62
+ # a reload otherwise just require.
63
+ if $".find { |file| file =~ /\Amemcache.rb\Z/ }
64
+ load 'memcache.rb'
65
+ else
66
+ require 'memcache'
67
+ end
68
+ end
69
+
70
+ This will remove the original MemCache client and load our version of the MemCache class instead.
71
+
72
+ Configuration
73
+ -------------
74
+ The JRuby MemCache client uses the same configuration options as the regular MemCache client. Here is how to build the configuration in your environment.rb file:
75
+
76
+ memcache_options = {
77
+ :namespace => 'fortaleza:production_live:',
78
+ }
79
+ memcached_servers = [ ENV['MEMCACHED_LOCATION'] || '0.0.0.0:11211']
80
+
81
+ # Constant used by libs
82
+ CACHE = MemCache.new memcached_servers, memcache_options if RUBY_PLATFORM =~ /java/
83
+
84
+ Note that this may vary based on your particular configuration method and environment.
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.version = "1.8.0"
5
+ gemspec.name = "jruby-memcache-client-thoughtworks"
6
+ gemspec.summary = "A drop in replacement for Ruby's memcache-client. Now with a stable jruby-memcached-release jar."
7
+ gemspec.email = "sudhindra.r.rao@gmail.com"
8
+ gemspec.homepage = "http://github.com/ThoughtWorksStudios/jruby-memcache-client"
9
+ gemspec.description = "A drop in replacement for Ruby's memcache-client.Now with a stable jruby-memcached-release jar."
10
+ gemspec.authors = ["Abhi Yerra", "Ikai Lan", "Frederic Jean", "Lennon Day-Reynolds",
11
+ "slyphon", "Brayn Helmkamp", "Travis Tilley", "Sudhindra Rao(ThoughtWorksStudios)"]
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
15
+ end
16
+
17
+ if RUBY_PLATFORM =~ /java/i
18
+ begin
19
+ require 'spec/rake/spectask'
20
+
21
+ task :default => :spec
22
+
23
+ desc "Run the specs for the jruby-memcache-client gem"
24
+ Spec::Rake::SpecTask.new
25
+ rescue LoadError
26
+ puts "You must have rspec installed in order to run the tests."
27
+ end
28
+ else
29
+ puts "You must run rake under JRuby."
30
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 1
3
+ :minor: 7
4
+ :patch: 0
@@ -0,0 +1,42 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "jruby-memcache-client-thoughtworks"
8
+ s.version = "1.8.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Abhi Yerra", "Ikai Lan", "Frederic Jean", "Lennon Day-Reynolds", "slyphon", "Brayn Helmkamp", "Travis Tilley", "Sudhindra Rao(ThoughtWorksStudios)"]
12
+ s.date = "2013-01-24"
13
+ s.description = "A drop in replacement for Ruby's memcache-client.Now with a stable jruby-memcached-release jar."
14
+ s.email = "sudhindra.r.rao@gmail.com"
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ "MIT-LICENSE",
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION.yml",
23
+ "jruby-memcache-client-thoughtworks.gemspec",
24
+ "lib/java/java_memcached-release_2.5.1.jar",
25
+ "lib/memcache.rb",
26
+ "spec/jruby_memcache_spec.rb"
27
+ ]
28
+ s.homepage = "http://github.com/ThoughtWorksStudios/jruby-memcache-client"
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = "1.8.10"
31
+ s.summary = "A drop in replacement for Ruby's memcache-client. Now with a stable jruby-memcached-release jar."
32
+
33
+ if s.respond_to? :specification_version then
34
+ s.specification_version = 3
35
+
36
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
37
+ else
38
+ end
39
+ else
40
+ end
41
+ end
42
+
data/lib/memcache.rb ADDED
@@ -0,0 +1,345 @@
1
+ require 'java'
2
+ require 'base64'
3
+
4
+ require File.dirname(__FILE__) + '/java/java_memcached-release_2.5.1.jar'
5
+
6
+ class MemCache
7
+ include_class 'com.danga.MemCached.MemCachedClient'
8
+ include_class 'com.danga.MemCached.SockIOPool'
9
+ include_class 'com.danga.MemCached.Logger'
10
+
11
+ VERSION = '1.7.0'
12
+
13
+ ##
14
+ # Default options for the cache object.
15
+
16
+ DEFAULT_OPTIONS = {
17
+ :namespace => nil,
18
+ :readonly => false,
19
+ :multithread => true,
20
+ :pool_initial_size => 10,
21
+ :pool_min_size => 5,
22
+ :pool_max_size => 100,
23
+ :pool_max_idle => (1000 * 60 * 5),
24
+ :pool_max_busy => (1000 * 30),
25
+ :pool_maintenance_thread_sleep => (1000 * 30),
26
+ :pool_socket_timeout => (1000 * 3),
27
+ :pool_socket_connect_timeout => (1000 * 3),
28
+ :pool_use_alive => false,
29
+ :pool_use_failover => true,
30
+ :pool_use_failback => true,
31
+ :pool_use_nagle => false,
32
+ :pool_name => 'default',
33
+ :log_level => 2
34
+ }
35
+
36
+ ## CHARSET for Marshalling
37
+ MARSHALLING_CHARSET = 'UTF-8'
38
+
39
+ ##
40
+ # Default memcached port.
41
+
42
+ DEFAULT_PORT = 11211
43
+
44
+ ##
45
+ # Default memcached server weight.
46
+
47
+ DEFAULT_WEIGHT = 1
48
+
49
+ attr_accessor :request_timeout
50
+
51
+ ##
52
+ # The namespace for this instance
53
+
54
+ attr_reader :namespace
55
+
56
+ ##
57
+ # The multithread setting for this instance
58
+
59
+ attr_reader :multithread
60
+
61
+ ##
62
+ # The configured socket pool name for this client.
63
+ attr_reader :pool_name
64
+
65
+ ##
66
+ # Configures the client
67
+ def initialize(*args)
68
+ @servers = []
69
+ opts = {}
70
+
71
+ case args.length
72
+ when 0 then # NOP
73
+ when 1 then
74
+ arg = args.shift
75
+ case arg
76
+ when Hash then opts = arg
77
+ when Array then @servers = arg
78
+ when String then @servers = [arg]
79
+ else raise ArgumentError, 'first argument must be Array, Hash or String'
80
+ end
81
+ when 2 then
82
+ @servers, opts = args
83
+ @servers = [@servers].flatten
84
+ else
85
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
86
+ end
87
+
88
+ # Normalizing the server(s) so they all have a port number.
89
+
90
+ @servers = @servers.map do |server|
91
+ server =~ /(.+):(\d+)/ ? server : "#{server}:#{DEFAULT_PORT}"
92
+ end
93
+
94
+ Logger.getLogger('com.meetup.memcached.MemcachedClient').setLevel(opts[:log_level])
95
+ Logger.getLogger('com.meetup.memcached.SockIOPool').setLevel(opts[:log_level])
96
+
97
+ opts = DEFAULT_OPTIONS.merge opts
98
+
99
+ @namespace = opts[:namespace] || opts["namespace"]
100
+ @pool_name = opts[:pool_name] || opts["pool_name"]
101
+ @readonly = opts[:readonly] || opts["readonly"]
102
+
103
+ @client = MemCachedClient.new(@pool_name)
104
+
105
+ @client.error_handler = opts[:error_handler] if opts[:error_handler]
106
+ @client.primitiveAsString = true
107
+ @client.sanitizeKeys = false
108
+
109
+ weights = Array.new(@servers.size, DEFAULT_WEIGHT)
110
+
111
+ @pool = SockIOPool.getInstance(@pool_name)
112
+ unless @pool.initialized?
113
+ @pool.servers = @servers.to_java(:string)
114
+ @pool.weights = weights.to_java(:Integer)
115
+
116
+ @pool.initConn = opts[:pool_initial_size]
117
+ @pool.minConn = opts[:pool_min_size]
118
+ @pool.maxConn = opts[:pool_max_size]
119
+
120
+ @pool.maxIdle = opts[:pool_max_idle]
121
+ @pool.maxBusyTime = opts[:pool_max_busy]
122
+ @pool.maintSleep = opts[:pool_maintenance_thread_sleep]
123
+ @pool.socketTO = opts[:pool_socket_timeout]
124
+ @pool.socketConnectTO = opts[:pool_socket_connect_timeout]
125
+
126
+ @pool.failover = opts[:pool_use_failover]
127
+ @pool.failback = opts[:pool_use_failback]
128
+ @pool.aliveCheck = opts[:pool_use_alive]
129
+ @pool.nagle = opts[:pool_use_nagle]
130
+
131
+ # public static final int NATIVE_HASH = 0;
132
+ # // native String.hashCode();
133
+ # public static final int OLD_COMPAT_HASH = 1;
134
+ # // original compatibility hashing algorithm (works with other clients)
135
+ # public static final int NEW_COMPAT_HASH = 2;
136
+ # // new CRC32 based compatibility hashing algorithm (works with other clients)
137
+ # public static final int CONSISTENT_HASH = 3;
138
+ # // MD5 Based -- Stops thrashing when a server added or removed
139
+ @pool.hashingAlg = opts[:pool_hashing_algorithm]
140
+
141
+ # __method methods have been removed in jruby 1.5
142
+ @pool.java_send :initialize rescue @pool.initialize__method
143
+ end
144
+
145
+ end
146
+
147
+ def reset
148
+ @pool.shut_down
149
+ @pool.java_send :initialize rescue @pool.initialize__method
150
+ end
151
+
152
+ ##
153
+ # Returns the servers that the client has been configured to
154
+ # use. Injects an alive? method into the string so it works with the
155
+ # updated Rails MemCacheStore session store class.
156
+ def servers
157
+ @pool.servers.to_a.collect do |s|
158
+ s.instance_eval(<<-EOIE)
159
+ def alive?
160
+ #{!!stats[s]}
161
+ end
162
+ EOIE
163
+ s
164
+ end rescue []
165
+ end
166
+
167
+ ##
168
+ # Determines whether any of the connections to the servers is
169
+ # alive. We are alive if it is the case.
170
+ def alive?
171
+ servers.to_a.any? { |s| s.alive? }
172
+ end
173
+
174
+ alias :active? :alive?
175
+
176
+ ##
177
+ # Retrieves a value associated with the key from the
178
+ # cache. Retrieves the raw value if the raw parameter is set.
179
+ def get(key, raw = false)
180
+ value = @client.get(make_cache_key(key))
181
+ return nil if value.nil?
182
+ unless raw
183
+ begin
184
+ marshal_bytes = java.lang.String.new(value).getBytes(MARSHALLING_CHARSET)
185
+ decoded = Base64.decode64(String.from_java_bytes(marshal_bytes))
186
+ value = Marshal.load(decoded)
187
+ rescue
188
+ value = case value
189
+ when /^\d+\.\d+$/ then value.to_f
190
+ when /^\d+$/ then value.to_i
191
+ else value
192
+ end
193
+ end
194
+ end
195
+ value
196
+ end
197
+
198
+ alias :[] :get
199
+
200
+ ##
201
+ # Retrieves the values associated with the keys parameter.
202
+ def get_multi(keys, raw = false)
203
+ keys = keys.map {|k| make_cache_key(k)}
204
+ keys = keys.to_java :String
205
+ values = {}
206
+ values_j = @client.getMulti(keys)
207
+ values_j.to_a.each {|kv|
208
+ k,v = kv
209
+ next if v.nil?
210
+ unless raw
211
+ begin
212
+ marshal_bytes = java.lang.String.new(v).getBytes(MARSHALLING_CHARSET)
213
+ decoded = Base64.decode64(String.from_java_bytes(marshal_bytes))
214
+ v = Marshal.load(decoded)
215
+ rescue
216
+ v = case v
217
+ when /^\d+\.\d+$/ then v.to_f
218
+ when /^\d+$/ then v.to_i
219
+ else v
220
+ end
221
+ end
222
+ end
223
+ values[k] = v
224
+ }
225
+ values
226
+ end
227
+
228
+ ##
229
+ # Associates a value with a key in the cache. MemCached will expire
230
+ # the value if an expiration is provided. The raw parameter allows
231
+ # us to store a value without marshalling it first.
232
+ def set(key, value, expiry = 0, raw = false)
233
+ raise MemCacheError, "Update of readonly cache" if @readonly
234
+ value = marshal_value(value) unless raw
235
+ key = make_cache_key(key)
236
+ if expiry == 0
237
+ @client.set key, value
238
+ else
239
+ @client.set key, value, expiration(expiry)
240
+ end
241
+ end
242
+
243
+ alias :[]= :set
244
+
245
+ ##
246
+ # Add a new value to the cache following the same conventions that
247
+ # are used in the set method.
248
+ def add(key, value, expiry = 0, raw = false)
249
+ raise MemCacheError, "Update of readonly cache" if @readonly
250
+ value = marshal_value(value) unless raw
251
+ if expiry == 0
252
+ @client.add make_cache_key(key), value
253
+ else
254
+ @client.add make_cache_key(key), value, expiration(expiry)
255
+ end
256
+ end
257
+
258
+ ##
259
+ # Removes the value associated with the key from the cache. This
260
+ # will ignore values that are not already present in the cache,
261
+ # which makes this safe to use without first checking for the
262
+ # existance of the key in the cache first.
263
+ def delete(key, expires = 0)
264
+ raise MemCacheError, "Update of readonly cache" if @readonly
265
+ @client.delete(make_cache_key(key))
266
+ end
267
+
268
+ ##
269
+ # Replaces the value associated with a key in the cache if it
270
+ # already is stored. It will not add the value to the cache if it
271
+ # isn't already present.
272
+ def replace(key, value, expiry = 0, raw = false)
273
+ raise MemCacheError, "Update of readonly cache" if @readonly
274
+ value = marshal_value(value) unless raw
275
+ if expiry == 0
276
+ @client.replace make_cache_key(key), value
277
+ else
278
+ @client.replace make_cache_key(key), value
279
+ end
280
+ end
281
+
282
+ ##
283
+ # Increments the value associated with the key by a certain amount.
284
+ def incr(key, amount = 1)
285
+ raise MemCacheError, "Update of readonly cache" if @readonly
286
+ value = @client.incr(make_cache_key(key), amount)
287
+ return nil if value == "NOT_FOUND\r\n"
288
+ return value.to_i
289
+ end
290
+
291
+ ##
292
+ # Decrements the value associated with the key by a certain amount.
293
+ def decr(key, amount = 1)
294
+ raise MemCacheError, "Update of readonly cache" if @readonly
295
+ value = @client.decr(make_cache_key(key),amount)
296
+ return nil if value == "NOT_FOUND\r\n"
297
+ return value.to_i
298
+ end
299
+
300
+ ##
301
+ # Clears the cache.
302
+ def flush_all
303
+ @client.flush_all
304
+ end
305
+
306
+ ##
307
+ # Reports statistics on the cache.
308
+ def stats
309
+ stats_hash = {}
310
+ @client.stats.each do |server, stats|
311
+ stats_hash[server] = Hash.new
312
+ stats.each do |key, value|
313
+ unless key == 'version'
314
+ value = value.to_f
315
+ value = value.to_i if value == value.ceil
316
+ end
317
+ stats_hash[server][key] = value
318
+ end
319
+ end
320
+ stats_hash
321
+ end
322
+
323
+ class MemCacheError < RuntimeError; end
324
+
325
+ protected
326
+ def make_cache_key(key)
327
+ if namespace.nil? then
328
+ key
329
+ else
330
+ "#{@namespace}:#{key}"
331
+ end
332
+ end
333
+
334
+ def expiration(expiry)
335
+ java.util.Date.new((Time.now.to_i + expiry) * 1000)
336
+ end
337
+
338
+ def marshal_value(value)
339
+ return value if value.kind_of?(Numeric)
340
+ encoded = Base64.encode64(Marshal.dump(value))
341
+ marshal_bytes = encoded.to_java_bytes
342
+ java.lang.String.new(marshal_bytes, MARSHALLING_CHARSET)
343
+ end
344
+ end
345
+
@@ -0,0 +1,272 @@
1
+ require 'java'
2
+ require File.dirname(__FILE__) + '/../lib/memcache'
3
+
4
+ describe MemCache do
5
+
6
+ hostname = `hostname`.strip
7
+
8
+ ["127.0.0.1:11211", "127.0.0.1", hostname, "#{hostname}:11211"].each do |server|
9
+ before :all do
10
+ @server = server
11
+ @normalized_server = @server =~ /(.+):(\d+)/ ? @server : "#{@server}:11211"
12
+ end
13
+
14
+ before :each do
15
+ @client = MemCache.new @server
16
+ @client.should_not be_nil
17
+ @client.flush_all
18
+ end
19
+
20
+ after :each do
21
+ @client.flush_all
22
+ end
23
+
24
+ it "should return nil for a non-existent key" do
25
+ @client.get('non-existent-key').should be_nil
26
+ end
27
+
28
+ describe "setting servers" do
29
+ it "should work if the instance is created with a single String argument" do
30
+ @client = MemCache.new @server
31
+ @client.servers.should == [@normalized_server]
32
+ end
33
+
34
+ it "should work if the instance is created with an Array" do
35
+ @client = MemCache.new [ @server ]
36
+ @client.servers.should == [@normalized_server]
37
+ end
38
+
39
+ it "should work if the instance is created with a Hash" do
40
+ @client = MemCache.new [ @server ], :namespace => 'test'
41
+ @client.servers.should == [@normalized_server]
42
+ end
43
+
44
+ it "should work with an explicit pool name" do
45
+ @client = MemCache.new([@server], :pool_name => 'new_pool')
46
+ @client.pool_name.should == 'new_pool'
47
+ end
48
+
49
+ it "should work with an error handler" do
50
+ include_class 'com.danga.MemCached.MemCachedClient'
51
+ java_memcache_client = mock.as_null_object
52
+ MemCachedClient.stub!(:new => java_memcache_client)
53
+ error_handler = Object.new
54
+ java_memcache_client.should_receive(:error_handler=).with(error_handler)
55
+ @client = MemCache.new([@server], :error_handler => error_handler)
56
+ end
57
+ end
58
+
59
+ describe "namespacing" do
60
+ before(:each) do
61
+ @ns = 'namespace'
62
+ @nsclient = MemCache.new [ @server ] , :namespace => @ns
63
+ @nsclient.flush_all
64
+ @nsclient.set "test", 333, 0
65
+ end
66
+
67
+ it "should set and get values transparently" do
68
+ @nsclient.get("test").should == 333
69
+ end
70
+
71
+ it "should set values to the given namespace" do
72
+ @nsclient.get("test").to_i.should == 333
73
+ end
74
+
75
+ it "should not set a value without the given namespace" do
76
+ @client.get("test").to_i.should_not == 333
77
+ end
78
+
79
+ it "should delete values in the given namespace" do
80
+ @nsclient.delete "test"
81
+ @nsclient.get("test").should be_nil
82
+ end
83
+
84
+ it "should increment in the given namespace" do
85
+ @nsclient.incr("test").to_i.should == 334
86
+ end
87
+
88
+ it "should decrement values in the given namespace" do
89
+ @nsclient.decr("test").should == 332
90
+ end
91
+ end
92
+
93
+ describe "after setting a value to MemCache" do
94
+ before(:each) do
95
+ @client.set 'key', 'value'
96
+ end
97
+
98
+ it "should be able to retrieve the value" do
99
+ @client.get('key').should == 'value'
100
+ end
101
+
102
+ it "should not be able to retrieve the value after deleting" do
103
+ @client.delete('key')
104
+ @client.get('key').should be_nil
105
+ end
106
+
107
+ it "should not be able to retrieve the value after flushing everything" do
108
+ @client.flush_all
109
+ @client.get("key").should be_nil
110
+ end
111
+
112
+ it "should work exactly the same if the []= operator were used" do
113
+ @client['key'] = 'val'
114
+ @client.get('key').should == 'val'
115
+ end
116
+ end
117
+
118
+ describe "replacing values from the cache." do
119
+ before :each do
120
+ @client['key'] = 'value'
121
+ end
122
+
123
+ it "should be able to replace the stored value." do
124
+ @client.replace('key', 'new value').should be_true
125
+ @client['key'].should == 'new value'
126
+ end
127
+
128
+ it "should not replace values that are not in the cache." do
129
+ @client.replace('notthere', 'value').should be_false
130
+ end
131
+ end
132
+
133
+ describe "using the Hash notation" do
134
+ before :each do
135
+ @client['key'] = 'value'
136
+ end
137
+
138
+ it "should be able to retrieve the value using []" do
139
+ @client['key'].should == 'value'
140
+ end
141
+
142
+ it "should be able to retrieve the value using get" do
143
+ @client.get('key').should == 'value'
144
+ end
145
+ end
146
+
147
+ describe "#stats" do
148
+ it "should return a hash" do
149
+ @client.stats.should be_instance_of(Hash)
150
+ end
151
+
152
+ it "should return a float for rusage_system and rusage_user" do
153
+ @client.stats[@normalized_server]['rusage_system'].should be_instance_of(Float)
154
+ @client.stats[@normalized_server]['rusage_user'].should be_instance_of(Float)
155
+ end
156
+
157
+ it "should return a String for version" do
158
+ @client.stats[@normalized_server]['version'].should be_instance_of(String)
159
+ end
160
+
161
+ end
162
+
163
+ describe "#incr" do
164
+
165
+ it "should increment a value by 1 without a second parameter" do
166
+ @client.set 'incr', 100, 0
167
+ @client.incr 'incr'
168
+ @client.get('incr').to_i.should == 101
169
+ end
170
+
171
+ it "should increment a value by a given second parameter" do
172
+ @client.set 'incr', 100, 0
173
+ @client.incr 'incr', 20
174
+ @client.get('incr').to_i.should == 120
175
+ end
176
+ end
177
+
178
+ describe "#decr" do
179
+
180
+ it "should decrement a value by 1 without a second parameter" do
181
+ @client.set 'decr', 100, 0
182
+ @client.decr 'decr'
183
+ @client.get('decr').to_i.should == 99
184
+ end
185
+
186
+ it "should decrement a value by a given second parameter" do
187
+ @client.set 'decr', 100, 0
188
+ @client.decr 'decr', 20
189
+ @client.get('decr').to_i.should == 80
190
+ end
191
+ end
192
+
193
+ describe "with Ruby Objects" do
194
+ it "should be able to transparently set and get equivalent Ruby objects" do
195
+ obj = { :test => :hi }
196
+ @client.set('obj', obj)
197
+ @client.get('obj').should == obj
198
+ end
199
+
200
+ it %[should work with those whose marshalled stream contains invalid UTF8 byte sequences] do
201
+ # this test fails w/o the Base64 encoding step
202
+ obj = { :foo => 900 }
203
+ @client.set('obj', obj)
204
+ @client.get('obj').should == obj
205
+ end
206
+
207
+ it %[should work with binary blobs] do
208
+ # this test fails w/o the Base64 encoding step
209
+ blob = "\377\330\377\340\000\020JFIF\000\001\001\000\000\001\000\001\000\000\377"
210
+ @client.set('blob', blob)
211
+ @client.get('blob').should == blob
212
+ end
213
+ end
214
+
215
+ describe "using set with an expiration" do
216
+ it "should make a value unretrievable if the expiry is set to a negative value" do
217
+ @client.set('key', 'val', -1)
218
+ @client.get('key').should be_nil
219
+ end
220
+
221
+ it "should make a value retrievable for only the amount of time if a value is given" do
222
+ @client.set('key', 'val', 2)
223
+ @client.get('key').should == 'val'
224
+ sleep(3)
225
+ @client.get('key').should be_nil
226
+ end
227
+ end
228
+
229
+ describe "#get_multi" do
230
+ it "should get 2 keys" do
231
+ @client.set('key', 'val')
232
+ @client.set('key2', 'val2')
233
+ @client.get_multi(%w/key key2/).should == {'key' => 'val', 'key2' => 'val2'}
234
+ end
235
+
236
+ it "should ignore nil values" do
237
+ @client.set('key', 'val')
238
+ @client.set('key2', 'val2')
239
+ @client.get_multi(%w/key key2 key3/).should == {'key' => 'val', 'key2' => 'val2'}
240
+ end
241
+
242
+ it "should not marshall if requested" do
243
+ @client.set('key', 'val', 0, true)
244
+ @client.set('key2', 'val2', 0, true)
245
+ @client.get_multi(%w/key key2/, true).should == {'key' => 'val', 'key2' => 'val2'}
246
+ end
247
+ end
248
+
249
+ describe "aliveness of the MemCache server." do
250
+ before :each do
251
+ @servers = ["localhost:11211", "localhost:11212", {:pool_name => "test"}]
252
+ @client = MemCache.new @servers
253
+ @client.flush_all
254
+ end
255
+
256
+ it "should report the client as being alive." do
257
+ @client.should be_alive
258
+ end
259
+
260
+ it "should report localhost:11211 as being alive." do
261
+ servers = @client.servers
262
+ servers.first.should be_alive
263
+ end
264
+
265
+ it "should report localhost:11212 as not being alive." do
266
+ servers = @client.servers
267
+ servers.find {|s| s.to_s == "localhost:11212"}.should be_nil
268
+ end
269
+ end
270
+ end
271
+ end
272
+
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jruby-memcache-client-thoughtworks
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.8.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Abhi Yerra
9
+ - Ikai Lan
10
+ - Frederic Jean
11
+ - Lennon Day-Reynolds
12
+ - slyphon
13
+ - Brayn Helmkamp
14
+ - Travis Tilley
15
+ - Sudhindra Rao(ThoughtWorksStudios)
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+ date: 2013-01-24 00:00:00.000000000 Z
20
+ dependencies: []
21
+ description: A drop in replacement for Ruby's memcache-client.Now with a stable jruby-memcached-release
22
+ jar.
23
+ email: sudhindra.r.rao@gmail.com
24
+ executables: []
25
+ extensions: []
26
+ extra_rdoc_files:
27
+ - README
28
+ files:
29
+ - MIT-LICENSE
30
+ - README
31
+ - Rakefile
32
+ - VERSION.yml
33
+ - jruby-memcache-client-thoughtworks.gemspec
34
+ - lib/java/java_memcached-release_2.5.1.jar
35
+ - lib/memcache.rb
36
+ - spec/jruby_memcache_spec.rb
37
+ homepage: http://github.com/ThoughtWorksStudios/jruby-memcache-client
38
+ licenses: []
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project:
57
+ rubygems_version: 1.8.10
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: A drop in replacement for Ruby's memcache-client. Now with a stable jruby-memcached-release
61
+ jar.
62
+ test_files: []