jruby-memcache-client-thoughtworks 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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: []