Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 196 lines (180 sloc) 5.751 kb
78a286c Sergey Avseyev 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 Sergey Avseyev fix fix
authored
31 :hostname => "127.0.0.1",
32 :port => 8091,
78a286c Sergey Avseyev 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 Sergey Avseyev Allow to select I/O mechanism
authored
40 :tick => 1,
eeca418 Sergey Avseyev Add switch to disable fork
authored
41 :use_fork => true,
cc31edc Sergey Avseyev Allow to select I/O mechanism
authored
42 :mechanism => :select
78a286c Sergey Avseyev 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 Sergey Avseyev 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 Sergey Avseyev 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 Sergey Avseyev 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 Sergey Avseyev Add verbose mode
authored
95 opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
96 options[:verbose] = v
97 end
78a286c Sergey Avseyev 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 Sergey Avseyev 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 Sergey Avseyev fix fix
authored
113 IGNORED_ERRORS = [
114 EM::Protocols::Couchbase::Error::NotFound
115 ]
116
eeca418 Sergey Avseyev 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 Sergey Avseyev README and script skeleton
authored
149 options[:concurrency].times do |n|
eeca418 Sergey Avseyev Add switch to disable fork
authored
150 workers << spawn_worker do
78a286c Sergey Avseyev 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 Sergey Avseyev 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 Sergey Avseyev README and script skeleton
authored
163 on_complete = lambda do |ret|
164 ops_per_fork -= 1
f85fc1b Sergey Avseyev Add verbose mode
authored
165 if options[:verbose]
1836150 Sergey Avseyev 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 Sergey Avseyev Add verbose mode
authored
175 end
176 end
78a286c Sergey Avseyev README and script skeleton
authored
177 EM.stop if ops_per_fork < 0
178 end
1836150 Sergey Avseyev fix fix
authored
179 EM.add_periodic_timer(options[:tick]) do
f85fc1b Sergey Avseyev Add verbose mode
authored
180 if options[:verbose]
181 STDERR.print(".")
182 end
1836150 Sergey Avseyev fix fix
authored
183 options[:slice].times do |t|
78a286c Sergey Avseyev README and script skeleton
authored
184 if rand > options[:ratio]
1836150 Sergey Avseyev fix fix
authored
185 cc.set("#{options[:prefix]}fork-#{n}:#{t}", value, &on_complete)
78a286c Sergey Avseyev README and script skeleton
authored
186 else
1836150 Sergey Avseyev fix fix
authored
187 cc.get("#{options[:prefix]}fork-#{n}:#{t}", &on_complete)
78a286c Sergey Avseyev README and script skeleton
authored
188 end
189 end
190 end
191 end
192 end
193 end
194
eeca418 Sergey Avseyev Add switch to disable fork
authored
195 wait_for(workers)
Something went wrong with that request. Please try again.