Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 196 lines (180 sloc) 5.751 kB
78a286c @avsej README and script skeleton
authored
1 #!/usr/bin/env ruby
2 # Author:: Couchbase <info@couchbase.com>
3 # Copyright:: 2012 Couchbase, Inc.
4 # License:: Apache License, Version 2.0
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18
19 require 'rubygems'
20 begin
21 require 'bundler/setup'
22 rescue LoadError
23 # don't worry if bundler isn't available
24 # the script could be installed somewhere in PATH
25 end
26 require 'em-couchbase'
27 require 'optparse'
28 require 'logger'
29
30 options = {
1836150 @avsej fix fix
authored
31 :hostname => "127.0.0.1",
32 :port => 8091,
78a286c @avsej README and script skeleton
authored
33 :bucket => "default",
34 :concurrency => 1,
35 :ratio => 0.5,
36 :operations => 10_000,
37 :prefix => 'em-couchbase:',
38 :size => 256,
39 :slice => 1_000,
cc31edc @avsej Allow to select I/O mechanism
authored
40 :tick => 1,
eeca418 @avsej Add switch to disable fork
authored
41 :use_fork => true,
cc31edc @avsej Allow to select I/O mechanism
authored
42 :mechanism => :select
78a286c @avsej README and script skeleton
authored
43 }
44
45 LOGGER = Logger.new(STDOUT)
46
47 trap("INT") do
48 LOGGER.info("Caught SIGINT. Terminating...")
49 exit
50 end
51
52 OptionParser.new do |opts|
53 opts.banner = "Usage: #{__FILE__} [options]"
eeca418 @avsej Add switch to disable fork
authored
54 opts.on("-f", "--[no-]use-fork", "Use fork, if it is available (default: #{options[:use_fork].inspect})") do |v|
55 options[:use_fork] = v
56 end
cc31edc @avsej Allow to select I/O mechanism
authored
57 opts.on("-m", "--mechanism MECH", "The mechanism for multiplexing I/O. EventMachine supports (:select, :epoll, :kqueue) (default: #{options[:mechanism].inspect})") do |v|
58 options[:mechanism] = v.to_sym
59 end
78a286c @avsej README and script skeleton
authored
60 opts.on("-t", "--tick SECONDS", "The interval for timer (default: #{options[:tick].inspect})") do |v|
61 options[:tick] = v.to_i
62 end
63 opts.on("-S", "--slice NUM", "The number of operation scheduled each timer occurence (default: #{options[:slice].inspect})") do |v|
64 options[:slice] = v.to_i
65 end
66 opts.on("-P", "--prefix PREFIX", "The prefix used for keys (default: #{options[:prefix].inspect})") do |v|
67 options[:prefix] = v.to_i
68 end
69 opts.on("-c", "--concurrency NUM", "Use NUM processes to run the test (default: #{options[:concurrency].inspect})") do |v|
70 options[:concurrency] = v.to_i
71 end
72 opts.on("-n", "--operations NUM", "Number of operations (default: #{options[:operations].inspect})") do |v|
73 options[:operations] = v.to_i
74 end
75 opts.on("-r", "--ratio RATIO", "The percent of GETs from 1 (default: #{options[:ratio].inspect})") do |v|
76 options[:ratio] = v.to_f
77 end
78 opts.on("-s", "--size SIZE", "Number of bytes for values (default: #{options[:size].inspect})") do |v|
79 options[:size] = v.to_i
80 end
81 opts.on("-h", "--hostname HOSTNAME", "Hostname to connect to (default: #{options[:hostname].inspect})") do |v|
82 host, port = v.split(':')
83 options[:hostname] = host.empty? ? '127.0.0.1' : host
84 options[:port] = port.to_i > 0 ? port.to_i : 8091
85 end
86 opts.on("-b", "--bucket NAME", "Name of the bucket to connect to (default: #{options[:bucket].inspect})") do |v|
87 options[:bucket] = v.empty? ? "default" : v
88 end
89 opts.on("-u", "--user USERNAME", "Username to log with (default: none)") do |v|
90 options[:user] = v
91 end
92 opts.on("-p", "--passwd PASSWORD", "Password to log with (default: none)") do |v|
93 options[:passwd] = v
94 end
f85fc1b @avsej Add verbose mode
authored
95 opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
96 options[:verbose] = v
97 end
78a286c @avsej README and script skeleton
authored
98 opts.on_tail("-?", "--help", "Show this message") do
99 puts opts
100 exit
101 end
102 end.parse!
103
cc31edc @avsej Allow to select I/O mechanism
authored
104 case options[:mechanism]
105 when :epoll
106 EM.epoll = true
107 when :kqueue
108 EM.kqueue = true
109 else
110 # select
111 end
112
1836150 @avsej fix fix
authored
113 IGNORED_ERRORS = [
114 EM::Protocols::Couchbase::Error::NotFound
115 ]
116
eeca418 @avsej Add switch to disable fork
authored
117 HAVE_FORK = begin
118 Process.fork { exit }
119 true
120 rescue NotImplementedError
121 false
122 end
123
124 USE_FORK = options[:use_fork]
125
126 def spawn_worker(&block)
127 if HAVE_FORK && USE_FORK
128 Process.fork(&block)
129 else
130 Thread.new(&block)
131 end
132 end
133
134 def wait_for(workers)
135 if HAVE_FORK && USE_FORK
136 workers.each do |pid|
137 Process.wait(pid)
138 end
139 else
140 workers.each do |tid|
141 tid.join
142 end
143 end
144 end
145
146 ops_per_fork = (options[:operations] / options[:concurrency].to_f).ceil
147 workers = []
148
78a286c @avsej README and script skeleton
authored
149 options[:concurrency].times do |n|
eeca418 @avsej Add switch to disable fork
authored
150 workers << spawn_worker do
78a286c @avsej README and script skeleton
authored
151 $0 = "#{__FILE__}: fork ##{n}"
152 value = $0.dup
153 value << ('.' * (options[:size] - value.size))
154
155 EM.run do
1836150 @avsej fix fix
authored
156 cc = EM::Protocols::Couchbase.connect(:hostname => options[:hostname],
157 :port => options[:port],
158 :bucket => options[:bucket])
159 cc.on_error do |_, error|
160 warn "Failed to connect to #{options[:hostname]}:#{options[:port]}: #{error}"
161 EM.stop
162 end
78a286c @avsej README and script skeleton
authored
163 on_complete = lambda do |ret|
164 ops_per_fork -= 1
f85fc1b @avsej Add verbose mode
authored
165 if options[:verbose]
1836150 @avsej fix fix
authored
166 if ret.success? || IGNORED_ERRORS.include?(ret.error.class)
167 case ret.operation
168 when :set
169 STDERR.print("s")
170 when :get
171 STDERR.print("g")
172 end
173 else
174 STDERR.print("E")
f85fc1b @avsej Add verbose mode
authored
175 end
176 end
78a286c @avsej README and script skeleton
authored
177 EM.stop if ops_per_fork < 0
178 end
1836150 @avsej fix fix
authored
179 EM.add_periodic_timer(options[:tick]) do
f85fc1b @avsej Add verbose mode
authored
180 if options[:verbose]
181 STDERR.print(".")
182 end
1836150 @avsej fix fix
authored
183 options[:slice].times do |t|
78a286c @avsej README and script skeleton
authored
184 if rand > options[:ratio]
1836150 @avsej fix fix
authored
185 cc.set("#{options[:prefix]}fork-#{n}:#{t}", value, &on_complete)
78a286c @avsej README and script skeleton
authored
186 else
1836150 @avsej fix fix
authored
187 cc.get("#{options[:prefix]}fork-#{n}:#{t}", &on_complete)
78a286c @avsej README and script skeleton
authored
188 end
189 end
190 end
191 end
192 end
193 end
194
eeca418 @avsej Add switch to disable fork
authored
195 wait_for(workers)
Something went wrong with that request. Please try again.