couchbase-jruby-client 0.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +203 -0
- data/README.md +347 -0
- data/Rakefile +10 -0
- data/couchbase-jruby-client.gemspec +30 -0
- data/lib/couchbase/async/callback.rb +19 -0
- data/lib/couchbase/async/queue.rb +26 -0
- data/lib/couchbase/async.rb +139 -0
- data/lib/couchbase/bucket.rb +663 -0
- data/lib/couchbase/cluster.rb +105 -0
- data/lib/couchbase/constants.rb +12 -0
- data/lib/couchbase/error.rb +28 -0
- data/lib/couchbase/jruby/couchbase_client.rb +22 -0
- data/lib/couchbase/jruby/future.rb +8 -0
- data/lib/couchbase/operations/arithmetic.rb +301 -0
- data/lib/couchbase/operations/delete.rb +104 -0
- data/lib/couchbase/operations/get.rb +298 -0
- data/lib/couchbase/operations/stats.rb +16 -0
- data/lib/couchbase/operations/store.rb +468 -0
- data/lib/couchbase/operations/touch.rb +123 -0
- data/lib/couchbase/operations/utils.rb +49 -0
- data/lib/couchbase/operations.rb +23 -0
- data/lib/couchbase/result.rb +43 -0
- data/lib/couchbase/transcoder.rb +83 -0
- data/lib/couchbase/utils.rb +62 -0
- data/lib/couchbase/version.rb +3 -0
- data/lib/couchbase/view.rb +506 -0
- data/lib/couchbase/view_row.rb +272 -0
- data/lib/couchbase.rb +177 -0
- data/lib/jars/commons-codec-1.5.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-javadoc.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0-sources.jar +0 -0
- data/lib/jars/couchbase-client-1.2.0.jar +0 -0
- data/lib/jars/httpcore-4.1.1.jar +0 -0
- data/lib/jars/httpcore-nio-4.1.1.jar +0 -0
- data/lib/jars/jettison-1.1.jar +0 -0
- data/lib/jars/netty-3.5.5.Final.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-javadoc.jar +0 -0
- data/lib/jars/spymemcached-2.10.0-sources.jar +0 -0
- data/lib/jars/spymemcached-2.10.0.jar +0 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +201 -0
- data/test/test_arithmetic.rb +177 -0
- data/test/test_async.rb +324 -0
- data/test/test_bucket.rb +213 -0
- data/test/test_cas.rb +78 -0
- data/test/test_couchbase.rb +29 -0
- data/test/test_couchbase_rails_cache_store.rb +341 -0
- data/test/test_delete.rb +125 -0
- data/test/test_errors.rb +82 -0
- data/test/test_format.rb +161 -0
- data/test/test_get.rb +417 -0
- data/test/test_stats.rb +57 -0
- data/test/test_store.rb +216 -0
- data/test/test_timer.rb +42 -0
- data/test/test_touch.rb +97 -0
- data/test/test_unlock.rb +119 -0
- data/test/test_utils.rb +58 -0
- data/test/test_version.rb +52 -0
- metadata +226 -0
@@ -0,0 +1,272 @@
|
|
1
|
+
# Author:: Couchbase <info@couchbase.com>
|
2
|
+
# Copyright:: 2011-2012 Couchbase, Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
module Couchbase
|
19
|
+
# This class encapsulates structured JSON document
|
20
|
+
#
|
21
|
+
# @since 1.2.0
|
22
|
+
#
|
23
|
+
# It behaves like Hash for document included into row, and has access methods to row data as well.
|
24
|
+
#
|
25
|
+
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-datastore.html
|
26
|
+
class ViewRow
|
27
|
+
include Constants
|
28
|
+
|
29
|
+
# Undefine as much methods as we can to free names for views
|
30
|
+
instance_methods.each do |m|
|
31
|
+
undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$|^class$|)/
|
32
|
+
end
|
33
|
+
|
34
|
+
# The hash built from JSON document.
|
35
|
+
#
|
36
|
+
# @since 1.2.0
|
37
|
+
#
|
38
|
+
# This is complete response from the Couchbase
|
39
|
+
#
|
40
|
+
# @return [Hash]
|
41
|
+
attr_accessor :data
|
42
|
+
|
43
|
+
# The key which was emitted by map function
|
44
|
+
#
|
45
|
+
# @since 1.2.0
|
46
|
+
#
|
47
|
+
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-map.html
|
48
|
+
#
|
49
|
+
# Usually it is String (the object +_id+) but it could be also any
|
50
|
+
# compount JSON value.
|
51
|
+
#
|
52
|
+
# @return [Object]
|
53
|
+
attr_accessor :key
|
54
|
+
|
55
|
+
# The value which was emitted by map function
|
56
|
+
#
|
57
|
+
# @since 1.2.0
|
58
|
+
#
|
59
|
+
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-writing-map.html
|
60
|
+
#
|
61
|
+
# @return [Object]
|
62
|
+
attr_accessor :value
|
63
|
+
|
64
|
+
# The document hash.
|
65
|
+
#
|
66
|
+
# @since 1.2.0
|
67
|
+
#
|
68
|
+
# It usually available when view executed with +:include_doc+ argument.
|
69
|
+
#
|
70
|
+
# @return [Hash]
|
71
|
+
attr_accessor :doc
|
72
|
+
|
73
|
+
# The identificator of the document
|
74
|
+
#
|
75
|
+
# @since 1.2.0
|
76
|
+
#
|
77
|
+
# @return [String]
|
78
|
+
attr_accessor :id
|
79
|
+
|
80
|
+
# The meta data linked to the document
|
81
|
+
#
|
82
|
+
# @since 1.2.0
|
83
|
+
#
|
84
|
+
# @return [Hash]
|
85
|
+
attr_accessor :meta
|
86
|
+
|
87
|
+
# Initialize the document instance
|
88
|
+
#
|
89
|
+
# @since 1.2.0
|
90
|
+
#
|
91
|
+
# It takes reference to the bucket, data hash.
|
92
|
+
#
|
93
|
+
# @param [Couchbase::Bucket] bucket the reference to connection
|
94
|
+
# @param [Hash] data the data hash, which was built from JSON document
|
95
|
+
# representation
|
96
|
+
def initialize(bucket, data)
|
97
|
+
@bucket = bucket
|
98
|
+
@data = data
|
99
|
+
@key = data[S_KEY]
|
100
|
+
@value = data[S_VALUE]
|
101
|
+
if data[S_DOC]
|
102
|
+
@meta = data[S_DOC][S_META]
|
103
|
+
@doc = data[S_DOC][S_VALUE]
|
104
|
+
end
|
105
|
+
@id = data[S_ID] || @meta && @meta[S_ID]
|
106
|
+
@last = data.delete(S_IS_LAST) || false
|
107
|
+
end
|
108
|
+
|
109
|
+
# Wraps data hash into ViewRow instance
|
110
|
+
#
|
111
|
+
# @since 1.2.0
|
112
|
+
#
|
113
|
+
# @see ViewRow#initialize
|
114
|
+
#
|
115
|
+
# @param [Couchbase::Bucket] bucket the reference to connection
|
116
|
+
# @param [Hash] data the data hash, which was built from JSON document
|
117
|
+
# representation
|
118
|
+
#
|
119
|
+
# @return [ViewRow]
|
120
|
+
def self.wrap(bucket, data)
|
121
|
+
self.new(bucket, data)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Get attribute of the document
|
125
|
+
#
|
126
|
+
# @since 1.2.0
|
127
|
+
#
|
128
|
+
# Fetches attribute from underlying document hash
|
129
|
+
#
|
130
|
+
# @param [String] key the attribute name
|
131
|
+
#
|
132
|
+
# @return [Object] property value or nil
|
133
|
+
def [](key)
|
134
|
+
@doc[key]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Check attribute existence
|
138
|
+
#
|
139
|
+
# @since 1.2.0
|
140
|
+
#
|
141
|
+
# @param [String] key the attribute name
|
142
|
+
#
|
143
|
+
# @return [true, false] +true+ if the given attribute is present in in
|
144
|
+
# the document.
|
145
|
+
def has_key?(key)
|
146
|
+
@doc.has_key?(key)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Set document attribute
|
150
|
+
#
|
151
|
+
# @since 1.2.0
|
152
|
+
#
|
153
|
+
# Set or update the attribute in the document hash
|
154
|
+
#
|
155
|
+
# @param [String] key the attribute name
|
156
|
+
# @param [Object] value the attribute value
|
157
|
+
#
|
158
|
+
# @return [Object] the value
|
159
|
+
def []=(key, value)
|
160
|
+
@doc[key] = value
|
161
|
+
end
|
162
|
+
|
163
|
+
# Signals if this row is last in a stream
|
164
|
+
#
|
165
|
+
# @since 1.2.1
|
166
|
+
#
|
167
|
+
# @return [true, false] +true+ if this row is last in a stream
|
168
|
+
def last?
|
169
|
+
@last
|
170
|
+
end
|
171
|
+
|
172
|
+
def inspect
|
173
|
+
desc = "#<#{self.class.name}:#{self.object_id}"
|
174
|
+
[:@id, :@key, :@value, :@doc, :@meta].each do |iv|
|
175
|
+
desc << " #{iv}=#{instance_variable_get(iv).inspect}"
|
176
|
+
end
|
177
|
+
desc << ">"
|
178
|
+
desc
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# This class encapsulates information about design docs
|
183
|
+
#
|
184
|
+
# @since 1.2.1
|
185
|
+
#
|
186
|
+
# It is subclass of ViewRow, but also gives access to view creation through method_missing
|
187
|
+
#
|
188
|
+
# @see http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-views-datastore.html
|
189
|
+
class DesignDoc < ViewRow
|
190
|
+
# It isn't allowed to change design document ID after
|
191
|
+
# initialization
|
192
|
+
undef id=
|
193
|
+
|
194
|
+
# Initialize the design doc instance
|
195
|
+
#
|
196
|
+
# @since 1.2.1
|
197
|
+
#
|
198
|
+
# It takes reference to the bucket, data hash. It will define view
|
199
|
+
# methods if the data object looks like design document.
|
200
|
+
#
|
201
|
+
# @param [Couchbase::Bucket] bucket the reference to connection
|
202
|
+
# @param [Hash] data the data hash, which was built from JSON document
|
203
|
+
# representation
|
204
|
+
def initialize(bucket, data)
|
205
|
+
super
|
206
|
+
@all_views = {}
|
207
|
+
@views = @doc.has_key?('views') ? @doc['views'].keys : []
|
208
|
+
@spatial = @doc.has_key?('spatial') ? @doc['spatial'].keys : []
|
209
|
+
@views.each{|name| @all_views[name] = "#{@id}/_view/#{name}"}
|
210
|
+
@spatial.each{|name| @all_views[name] = "#{@id}/_spatial/#{name}"}
|
211
|
+
end
|
212
|
+
|
213
|
+
def method_missing(meth, *args)
|
214
|
+
if path = @all_views[meth.to_s]
|
215
|
+
View.new(@bucket, path, *args)
|
216
|
+
else
|
217
|
+
super
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def respond_to?(meth, *args)
|
222
|
+
if @all_views[meth.to_s]
|
223
|
+
true
|
224
|
+
else
|
225
|
+
super
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def method(meth, *args)
|
230
|
+
if path = @all_views[meth.to_s]
|
231
|
+
lambda{|*p| View.new(@bucket, path, *p)}
|
232
|
+
else
|
233
|
+
super
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# The list of views defined or empty array
|
238
|
+
#
|
239
|
+
# @since 1.2.1
|
240
|
+
#
|
241
|
+
# @return [Array<View>]
|
242
|
+
attr_accessor :views
|
243
|
+
|
244
|
+
# The list of spatial views defined or empty array
|
245
|
+
#
|
246
|
+
# @since 1.2.1
|
247
|
+
#
|
248
|
+
# @return [Array<View>]
|
249
|
+
attr_accessor :spatial
|
250
|
+
|
251
|
+
# Check if the document has views defines
|
252
|
+
#
|
253
|
+
# @since 1.2.1
|
254
|
+
#
|
255
|
+
# @see DesignDoc#views
|
256
|
+
#
|
257
|
+
# @return [true, false] +true+ if the document have views
|
258
|
+
def has_views?
|
259
|
+
!@views.empty?
|
260
|
+
end
|
261
|
+
|
262
|
+
def inspect
|
263
|
+
desc = "#<#{self.class.name}:#{self.object_id}"
|
264
|
+
[:@id, :@views, :@spatial].each do |iv|
|
265
|
+
desc << " #{iv}=#{instance_variable_get(iv).inspect}"
|
266
|
+
end
|
267
|
+
desc << ">"
|
268
|
+
desc
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
data/lib/couchbase.rb
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
|
2
|
+
unless RUBY_PLATFORM =~ /java/
|
3
|
+
error "This gem is only compatible with a java-based ruby environment like JRuby."
|
4
|
+
exit 255
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'java'
|
8
|
+
require 'jars/commons-codec-1.5.jar'
|
9
|
+
require 'jars/couchbase-client-1.2.0.jar'
|
10
|
+
require 'jars/jettison-1.1.jar'
|
11
|
+
require 'jars/httpcore-4.1.1.jar'
|
12
|
+
require 'jars/netty-3.5.5.Final.jar'
|
13
|
+
require 'jars/spymemcached-2.10.0.jar'
|
14
|
+
require 'jars/httpcore-nio-4.1.1.jar'
|
15
|
+
require 'couchbase/version'
|
16
|
+
require 'uri'
|
17
|
+
require 'atomic'
|
18
|
+
require 'couchbase/transcoder'
|
19
|
+
require 'couchbase/async'
|
20
|
+
require 'couchbase/operations'
|
21
|
+
require 'couchbase/error'
|
22
|
+
require 'couchbase/constants'
|
23
|
+
require 'couchbase/utils'
|
24
|
+
require 'couchbase/bucket'
|
25
|
+
require 'couchbase/view_row'
|
26
|
+
require 'couchbase/view'
|
27
|
+
require 'couchbase/result'
|
28
|
+
require 'couchbase/cluster'
|
29
|
+
|
30
|
+
include Java
|
31
|
+
|
32
|
+
import Java::com.couchbase.client.CouchbaseClient;
|
33
|
+
|
34
|
+
at_exit do
|
35
|
+
Couchbase.disconnect
|
36
|
+
end
|
37
|
+
|
38
|
+
# Couchbase jruby client
|
39
|
+
module Couchbase
|
40
|
+
|
41
|
+
@@bucket = Atomic.new(nil)
|
42
|
+
|
43
|
+
class << self
|
44
|
+
|
45
|
+
# The method +connect+ initializes new Bucket instance with all arguments passed.
|
46
|
+
#
|
47
|
+
# @since 1.0.0
|
48
|
+
#
|
49
|
+
# @see Bucket#initialize
|
50
|
+
#
|
51
|
+
# @example Use default values for all options
|
52
|
+
# Couchbase.connect
|
53
|
+
#
|
54
|
+
# @example Establish connection with couchbase default pool and default bucket
|
55
|
+
# Couchbase.connect("http://localhost:8091/pools/default")
|
56
|
+
#
|
57
|
+
# @example Select custom bucket
|
58
|
+
# Couchbase.connect("http://localhost:8091/pools/default", :bucket => 'blog')
|
59
|
+
#
|
60
|
+
# @example Specify bucket credentials
|
61
|
+
# Couchbase.connect("http://localhost:8091/pools/default", :bucket => 'blog', :username => 'bucket', :password => 'secret')
|
62
|
+
#
|
63
|
+
# @example Use URL notation
|
64
|
+
# Couchbase.connect("http://bucket:secret@localhost:8091/pools/default/buckets/blog")
|
65
|
+
#
|
66
|
+
# @return [Bucket] connection instance
|
67
|
+
def connect(*options)
|
68
|
+
disconnect
|
69
|
+
@@bucket.update { |bucket| bucket ||= Bucket.new(*(options.flatten)) }
|
70
|
+
@@bucket.value
|
71
|
+
end
|
72
|
+
alias :new :connect
|
73
|
+
|
74
|
+
# Default connection options
|
75
|
+
#
|
76
|
+
# @since 1.1.0
|
77
|
+
#
|
78
|
+
# @example Using {Couchbase#connection_options} to change the bucket
|
79
|
+
# Couchbase.connection_options = {:bucket => 'blog'}
|
80
|
+
# Couchbase.bucket.name #=> "blog"
|
81
|
+
#
|
82
|
+
# @return [Hash, String]
|
83
|
+
attr_accessor :connection_options
|
84
|
+
|
85
|
+
# The connection instance for current thread
|
86
|
+
#
|
87
|
+
# @since 1.1.0
|
88
|
+
#
|
89
|
+
# @see Couchbase.connection_options
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# Couchbase.bucket.set("foo", "bar")
|
93
|
+
#
|
94
|
+
# @return [Bucket]
|
95
|
+
def bucket
|
96
|
+
if !connected?
|
97
|
+
connect(connection_options)
|
98
|
+
end
|
99
|
+
@@bucket.value
|
100
|
+
end
|
101
|
+
|
102
|
+
# Set a connection instance for current thread
|
103
|
+
#
|
104
|
+
# @since 1.1.0
|
105
|
+
#
|
106
|
+
# @return [Bucket]
|
107
|
+
def bucket=(connection)
|
108
|
+
@@bucket.update { |bucket| bucket = connection }
|
109
|
+
end
|
110
|
+
|
111
|
+
def connected?
|
112
|
+
!!@@bucket.value
|
113
|
+
end
|
114
|
+
|
115
|
+
def disconnect
|
116
|
+
@@bucket.value.disconnect if connected?
|
117
|
+
@@bucket = Atomic.new(nil)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
__END__
|
123
|
+
|
124
|
+
def self.connect(*options)
|
125
|
+
disconnect
|
126
|
+
Bucket.new(*(options.flatten))
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.new(*options)
|
130
|
+
connect(options)
|
131
|
+
end
|
132
|
+
|
133
|
+
# Default connection options
|
134
|
+
#
|
135
|
+
# @since 1.1.0
|
136
|
+
#
|
137
|
+
# @example Using {Couchbase#connection_options} to change the bucket
|
138
|
+
# Couchbase.connection_options = {:bucket => 'blog'}
|
139
|
+
# Couchbase.bucket.name #=> "blog"
|
140
|
+
#
|
141
|
+
# @return [Hash, String]
|
142
|
+
attr_accessor :connection_options
|
143
|
+
|
144
|
+
# The connection instance for current thread
|
145
|
+
#
|
146
|
+
# @since 1.1.0
|
147
|
+
#
|
148
|
+
# @see Couchbase.connection_options
|
149
|
+
#
|
150
|
+
# @example
|
151
|
+
# Couchbase.bucket.set("foo", "bar")
|
152
|
+
#
|
153
|
+
# @return [Bucket]
|
154
|
+
def self.bucket
|
155
|
+
@bucket ||= connect(connection_options)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Set a connection instance for current thread
|
159
|
+
#
|
160
|
+
# @since 1.1.0
|
161
|
+
#
|
162
|
+
# @return [Bucket]
|
163
|
+
def self.bucket=(connection)
|
164
|
+
@bucket = connection
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.connected?
|
168
|
+
!!@bucket
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.disconnect
|
172
|
+
bucket.disconnect if connected?
|
173
|
+
@bucket = nil
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
benchmark*.log
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# Useful environment variables:
|
2
|
+
#
|
3
|
+
# LOOPS (50000)
|
4
|
+
# how many time run exercises
|
5
|
+
#
|
6
|
+
# HOST (127.0.0.1)
|
7
|
+
# the host where cluster is running. benchmark will use default ports to
|
8
|
+
# connect to it (11211 and 8091)
|
9
|
+
#
|
10
|
+
# STACK_DEPTH (0)
|
11
|
+
# the depth of stack where exercises are run. the benchmark will
|
12
|
+
# recursively go to given depth before run
|
13
|
+
#
|
14
|
+
# TEST ('')
|
15
|
+
# use to run specific test (possible values are: set, get, get-multi,
|
16
|
+
# append, prepend, delete, get-missing, append-missing, prepend-missing,
|
17
|
+
# set-large, get-large)
|
18
|
+
#
|
19
|
+
# CLIENT ('')
|
20
|
+
# use to run with specific client (possible values are: couchbase, dalli,
|
21
|
+
# memcached, memcached:buffer)
|
22
|
+
#
|
23
|
+
# DEBUG ('')
|
24
|
+
# show exceptions
|
25
|
+
#
|
26
|
+
|
27
|
+
require "rubygems"
|
28
|
+
require "bundler/setup"
|
29
|
+
|
30
|
+
require 'benchmark'
|
31
|
+
|
32
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "..", "lib")
|
33
|
+
require 'couchbase'
|
34
|
+
require 'memcached'
|
35
|
+
require 'dalli'
|
36
|
+
|
37
|
+
puts `uname -a`
|
38
|
+
puts File.readlines('/proc/cpuinfo').sort.uniq.grep(/model name|cpu cores/) rescue nil
|
39
|
+
puts RUBY_DESCRIPTION
|
40
|
+
|
41
|
+
class Bench
|
42
|
+
|
43
|
+
def initialize(loops = nil, stack_depth = nil)
|
44
|
+
@loops = (loops || 50000).to_i
|
45
|
+
@stack_depth = (stack_depth || 0).to_i
|
46
|
+
|
47
|
+
puts "PID is #{Process.pid}"
|
48
|
+
puts "Loops is #{@loops}"
|
49
|
+
puts "Stack depth is #{@stack_depth}"
|
50
|
+
|
51
|
+
@m_value = Marshal.dump(
|
52
|
+
@small_value = ["testing"])
|
53
|
+
@m_large_value = Marshal.dump(
|
54
|
+
@large_value = [{"test" => "1", "test2" => "2", Object.new => "3", 4 => 4, "test5" => 2**65}] * 2048)
|
55
|
+
|
56
|
+
puts "Small value size is: #{@m_value.size} bytes"
|
57
|
+
puts "Large value size is: #{@m_large_value.size} bytes"
|
58
|
+
|
59
|
+
@keys = [
|
60
|
+
@k1 = "Short",
|
61
|
+
@k2 = "Sym1-2-3::45" * 8,
|
62
|
+
@k3 = "Long" * 40,
|
63
|
+
@k4 = "Medium" * 8,
|
64
|
+
@k5 = "Medium2" * 8,
|
65
|
+
@k6 = "Long3" * 40]
|
66
|
+
|
67
|
+
reset_clients
|
68
|
+
|
69
|
+
Benchmark.bm(36) do |x|
|
70
|
+
@benchmark = x
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def run(level = @stack_depth)
|
75
|
+
level > 0 ? run(level - 1) : run_without_recursion
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def reset_clients
|
81
|
+
host = ENV['HOST'] || '127.0.0.1'
|
82
|
+
@clients = {
|
83
|
+
"dalli" => lambda { Dalli::Client.new("#{host}:11211", :marshal => true, :threadsafe => false) },
|
84
|
+
"memcached" => lambda { Memcached::Rails.new("#{host}:11211", :no_block => false, :buffer_requests => false, :binary_protocol => true) },
|
85
|
+
"memcached:buffer" => lambda { Memcached::Rails.new("#{host}:11211", :no_block => true, :buffer_requests => true, :binary_protocol => true) },
|
86
|
+
"couchbase" => lambda { Couchbase.new("http://#{host}:8091/pools/default/buckets/default", :default_format => :marshal) }
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def benchmark_clients(test_name, populate_keys = true)
|
91
|
+
return if ENV["TEST"] and !test_name.include?(ENV["TEST"])
|
92
|
+
|
93
|
+
@clients.keys.each do |client_name|
|
94
|
+
next if ENV["CLIENT"] and !client_name.include?(ENV["CLIENT"])
|
95
|
+
|
96
|
+
kid = fork do
|
97
|
+
client = @clients[client_name].call
|
98
|
+
begin
|
99
|
+
if populate_keys
|
100
|
+
client.set @k1, @m_value
|
101
|
+
client.set @k2, @m_value
|
102
|
+
client.set @k3, @m_value
|
103
|
+
else
|
104
|
+
client.delete @k1
|
105
|
+
client.delete @k2
|
106
|
+
client.delete @k3
|
107
|
+
end
|
108
|
+
|
109
|
+
GC.disable
|
110
|
+
@benchmark.report("#{test_name}: #{client_name}") { @loops.times { yield client } }
|
111
|
+
STDOUT.flush
|
112
|
+
rescue Exception => e
|
113
|
+
puts "#{test_name}: #{client_name} => #{e.inspect}" if ENV["DEBUG"]
|
114
|
+
end
|
115
|
+
exit
|
116
|
+
end
|
117
|
+
Signal.trap("INT") { Process.kill("KILL", kid); exit }
|
118
|
+
Process.wait(kid)
|
119
|
+
end
|
120
|
+
puts
|
121
|
+
end
|
122
|
+
|
123
|
+
def run_without_recursion
|
124
|
+
benchmark_clients("set") do |c|
|
125
|
+
c.set @k1, @m_value
|
126
|
+
c.set @k2, @m_value
|
127
|
+
c.set @k3, @m_value
|
128
|
+
end
|
129
|
+
|
130
|
+
benchmark_clients("get") do |c|
|
131
|
+
c.get @k1
|
132
|
+
c.get @k2
|
133
|
+
c.get @k3
|
134
|
+
end
|
135
|
+
|
136
|
+
benchmark_clients("get_multi") do |c|
|
137
|
+
if c.respond_to?(:get_multi)
|
138
|
+
c.get_multi @keys
|
139
|
+
else
|
140
|
+
c.get @keys
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
benchmark_clients("append") do |c|
|
145
|
+
c.append @k1, @m_value
|
146
|
+
c.append @k2, @m_value
|
147
|
+
c.append @k3, @m_value
|
148
|
+
end
|
149
|
+
|
150
|
+
benchmark_clients("prepend") do |c|
|
151
|
+
c.prepend @k1, @m_value
|
152
|
+
c.prepend @k2, @m_value
|
153
|
+
c.prepend @k3, @m_value
|
154
|
+
end
|
155
|
+
|
156
|
+
benchmark_clients("delete") do |c|
|
157
|
+
c.delete @k1
|
158
|
+
c.delete @k2
|
159
|
+
c.delete @k3
|
160
|
+
end
|
161
|
+
|
162
|
+
benchmark_clients("get_missing", false) do |c|
|
163
|
+
c.get @k1 rescue nil
|
164
|
+
c.get @k2 rescue nil
|
165
|
+
c.get @k3 rescue nil
|
166
|
+
end
|
167
|
+
|
168
|
+
benchmark_clients("append_missing", false) do |c|
|
169
|
+
c.append @k1, @m_value rescue nil
|
170
|
+
c.append @k2, @m_value rescue nil
|
171
|
+
c.append @k3, @m_value rescue nil
|
172
|
+
end
|
173
|
+
|
174
|
+
benchmark_clients("prepend_missing", false) do |c|
|
175
|
+
c.prepend @k1, @m_value rescue nil
|
176
|
+
c.prepend @k2, @m_value rescue nil
|
177
|
+
c.prepend @k3, @m_value rescue nil
|
178
|
+
end
|
179
|
+
|
180
|
+
benchmark_clients("set_large") do |c|
|
181
|
+
c.set @k1, @m_large_value
|
182
|
+
c.set @k2, @m_large_value
|
183
|
+
c.set @k3, @m_large_value
|
184
|
+
end
|
185
|
+
|
186
|
+
benchmark_clients("get_large") do |c|
|
187
|
+
c.get @k1
|
188
|
+
c.get @k2
|
189
|
+
c.get @k3
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
Bench.new(ENV["LOOPS"], ENV["STACK_DEPTH"]).run
|