jmoses-couchbase 1.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +15 -0
  2. data/.travis.yml +22 -0
  3. data/.yardopts +5 -0
  4. data/CONTRIBUTING.markdown +75 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +201 -0
  7. data/Makefile +3 -0
  8. data/README.markdown +665 -0
  9. data/RELEASE_NOTES.markdown +819 -0
  10. data/Rakefile +20 -0
  11. data/couchbase.gemspec +49 -0
  12. data/examples/chat-em/Gemfile +7 -0
  13. data/examples/chat-em/README.markdown +45 -0
  14. data/examples/chat-em/server.rb +82 -0
  15. data/examples/chat-goliath-grape/Gemfile +5 -0
  16. data/examples/chat-goliath-grape/README.markdown +50 -0
  17. data/examples/chat-goliath-grape/app.rb +67 -0
  18. data/examples/chat-goliath-grape/config/app.rb +20 -0
  19. data/examples/transcoders/Gemfile +3 -0
  20. data/examples/transcoders/README.markdown +59 -0
  21. data/examples/transcoders/cb-zcat +40 -0
  22. data/examples/transcoders/cb-zcp +45 -0
  23. data/examples/transcoders/gzip_transcoder.rb +49 -0
  24. data/examples/transcoders/options.rb +54 -0
  25. data/ext/couchbase_ext/.gitignore +4 -0
  26. data/ext/couchbase_ext/arguments.c +956 -0
  27. data/ext/couchbase_ext/arithmetic.c +316 -0
  28. data/ext/couchbase_ext/bucket.c +1373 -0
  29. data/ext/couchbase_ext/context.c +65 -0
  30. data/ext/couchbase_ext/couchbase_ext.c +1364 -0
  31. data/ext/couchbase_ext/couchbase_ext.h +644 -0
  32. data/ext/couchbase_ext/delete.c +163 -0
  33. data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
  34. data/ext/couchbase_ext/extconf.rb +169 -0
  35. data/ext/couchbase_ext/get.c +316 -0
  36. data/ext/couchbase_ext/gethrtime.c +129 -0
  37. data/ext/couchbase_ext/http.c +432 -0
  38. data/ext/couchbase_ext/multithread_plugin.c +1090 -0
  39. data/ext/couchbase_ext/observe.c +171 -0
  40. data/ext/couchbase_ext/plugin_common.c +171 -0
  41. data/ext/couchbase_ext/result.c +129 -0
  42. data/ext/couchbase_ext/stats.c +163 -0
  43. data/ext/couchbase_ext/store.c +542 -0
  44. data/ext/couchbase_ext/timer.c +192 -0
  45. data/ext/couchbase_ext/touch.c +186 -0
  46. data/ext/couchbase_ext/unlock.c +176 -0
  47. data/ext/couchbase_ext/utils.c +551 -0
  48. data/ext/couchbase_ext/version.c +142 -0
  49. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  50. data/lib/active_support/cache/couchbase_store.rb +430 -0
  51. data/lib/couchbase.rb +155 -0
  52. data/lib/couchbase/bucket.rb +457 -0
  53. data/lib/couchbase/cluster.rb +119 -0
  54. data/lib/couchbase/connection_pool.rb +58 -0
  55. data/lib/couchbase/constants.rb +12 -0
  56. data/lib/couchbase/result.rb +26 -0
  57. data/lib/couchbase/transcoder.rb +120 -0
  58. data/lib/couchbase/utils.rb +62 -0
  59. data/lib/couchbase/version.rb +21 -0
  60. data/lib/couchbase/view.rb +506 -0
  61. data/lib/couchbase/view_row.rb +272 -0
  62. data/lib/ext/multi_json_fix.rb +56 -0
  63. data/lib/rack/session/couchbase.rb +108 -0
  64. data/tasks/benchmark.rake +6 -0
  65. data/tasks/compile.rake +160 -0
  66. data/tasks/test.rake +100 -0
  67. data/tasks/util.rake +21 -0
  68. data/test/profile/.gitignore +1 -0
  69. data/test/profile/Gemfile +6 -0
  70. data/test/profile/benchmark.rb +195 -0
  71. data/test/setup.rb +178 -0
  72. data/test/test_arithmetic.rb +185 -0
  73. data/test/test_async.rb +316 -0
  74. data/test/test_bucket.rb +276 -0
  75. data/test/test_cas.rb +235 -0
  76. data/test/test_couchbase.rb +77 -0
  77. data/test/test_couchbase_connection_pool.rb +77 -0
  78. data/test/test_couchbase_rails_cache_store.rb +361 -0
  79. data/test/test_delete.rb +120 -0
  80. data/test/test_errors.rb +82 -0
  81. data/test/test_eventmachine.rb +70 -0
  82. data/test/test_format.rb +164 -0
  83. data/test/test_get.rb +407 -0
  84. data/test/test_stats.rb +57 -0
  85. data/test/test_store.rb +216 -0
  86. data/test/test_timer.rb +42 -0
  87. data/test/test_touch.rb +97 -0
  88. data/test/test_unlock.rb +119 -0
  89. data/test/test_utils.rb +58 -0
  90. data/test/test_version.rb +52 -0
  91. metadata +353 -0
@@ -0,0 +1,100 @@
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
+ require 'rake/testtask'
19
+ require 'rake/clean'
20
+
21
+ rule 'test/CouchbaseMock.jar' do |task|
22
+ jar_path = "0.5-SNAPSHOT/CouchbaseMock-0.5-20120726.220757-19.jar"
23
+ sh %{wget -q -O test/CouchbaseMock.jar http://files.couchbase.com/maven2/org/couchbase/mock/CouchbaseMock/#{jar_path}}
24
+ end
25
+
26
+ CLOBBER << 'test/CouchbaseMock.jar'
27
+
28
+ module FileUtils
29
+ alias :orig_ruby :ruby
30
+
31
+ def ruby(*args, &block)
32
+ executable = [ENV['RUBY_PREFIX'], RUBY].flatten.compact.join(' ')
33
+ options = (Hash === args.last) ? args.pop : {}
34
+ if args.length > 1 then
35
+ sh(*([executable] + args + [options]), &block)
36
+ else
37
+ sh("#{executable} #{args.first}", options, &block)
38
+ end
39
+ end
40
+ end
41
+
42
+ Rake::TestTask.new do |test|
43
+ test.libs << "test" << "."
44
+ test.pattern = 'test/test_*.rb'
45
+ test.options = '--verbose'
46
+ end
47
+
48
+ Rake::Task['test'].prerequisites.unshift('test/CouchbaseMock.jar')
49
+
50
+ common_flags = %w[
51
+ --tool=memcheck
52
+ --error-limit=no
53
+ --undef-value-errors=no
54
+ --leak-check=full
55
+ --show-reachable=yes
56
+ --num-callers=50
57
+ --track-fds=yes
58
+ --workaround-gcc296-bugs=yes
59
+ --leak-resolution=med
60
+ --max-stackframe=7304328
61
+ --partial-loads-ok=yes
62
+ ]
63
+
64
+ desc "Run the test suite under Valgrind memcheck."
65
+ task "test:valgrind" do
66
+ ENV['RUBY_PREFIX'] = "valgrind #{common_flags.join(' ')}"
67
+ Rake::Task['test'].invoke
68
+ end
69
+
70
+ desc "Run the test suite under Valgrind memcheck with memory-fill."
71
+ task "test:valgrind:mem_fill" do
72
+ local_flags = %w[
73
+ --malloc-fill=6D
74
+ --freelist-vol=100000000
75
+ --free-fill=66
76
+ ]
77
+ ENV['RUBY_PREFIX'] = "valgrind #{common_flags.join(' ')} #{local_flags.join(' ')}"
78
+ Rake::Task['test'].invoke
79
+ end
80
+
81
+ desc "Run the test suite under Valgrind memcheck with memory-zero."
82
+ task "test:valgrind:mem_zero" do
83
+ local_flags = %w[
84
+ --freelist-vol=100000000
85
+ --malloc-fill=00
86
+ --free-fill=00
87
+ ]
88
+ ENV['RUBY_PREFIX'] = "valgrind #{common_flags.join(' ')} #{local_flags.join(' ')}"
89
+ Rake::Task['test'].invoke
90
+ end
91
+
92
+ desc "Run the test suite under Valgrind massif."
93
+ task "test:valgrind:massif" do
94
+ local_flags = %w[
95
+ --tool=massif
96
+ --time-unit=B
97
+ ]
98
+ ENV['RUBY_PREFIX'] = "valgrind #{local_flags.join(' ')}"
99
+ Rake::Task['test'].invoke
100
+ end
@@ -0,0 +1,21 @@
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
+ desc 'Start an irb session and load the library.'
19
+ task :console do
20
+ exec "irb -I lib -rcouchbase"
21
+ end
@@ -0,0 +1 @@
1
+ benchmark*.log
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+
3
+ gem "memcached", "~> 1.3.6"
4
+ gem "kgio", "~> 2.7.2"
5
+ gem "dalli", "~> 1.1.4"
6
+ gem "yajl-ruby", "~> 1.1.0"
@@ -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
@@ -0,0 +1,178 @@
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
+ require 'minitest/autorun'
19
+ require 'couchbase'
20
+
21
+ require 'socket'
22
+ require 'open-uri'
23
+
24
+ class CouchbaseServer
25
+ attr_accessor :host, :port, :num_nodes, :buckets_spec
26
+
27
+ def real?
28
+ true
29
+ end
30
+
31
+ def initialize(params = {})
32
+ @host, @port = ENV['COUCHBASE_SERVER'].split(':')
33
+ @port = @port.to_i
34
+
35
+ if @host.nil? || @host.empty? || @port == 0
36
+ raise ArgumentError, "Check COUCHBASE_SERVER variable. It should be hostname:port"
37
+ end
38
+
39
+ @config = MultiJson.load(open("http://#{@host}:#{@port}/pools/default"))
40
+ @num_nodes = @config["nodes"].size
41
+ @buckets_spec = params[:buckets_spec] || "default:" # "default:,protected:secret,cache::memcache"
42
+ end
43
+
44
+ def start
45
+ # flush all buckets
46
+ @buckets_spec.split(',') do |bucket|
47
+ name, password, _ = bucket.split(':')
48
+ connection = Couchbase.new(:hostname => @host,
49
+ :port => @port,
50
+ :username => name,
51
+ :bucket => name,
52
+ :password => password)
53
+ begin
54
+ connection.flush
55
+ rescue Couchbase::Error::NotSupported
56
+ # on recent server flush is disabled
57
+ end
58
+ end if ENV['COUCHBASE_FLUSH_BUCKETS']
59
+ end
60
+ def stop; end
61
+ end
62
+
63
+ class CouchbaseMock
64
+ Monitor = Struct.new(:pid, :client, :socket, :port)
65
+
66
+ attr_accessor :host, :port, :buckets_spec, :num_nodes, :num_vbuckets
67
+
68
+ def real?
69
+ false
70
+ end
71
+
72
+ def initialize(params = {})
73
+ @host = "127.0.0.1"
74
+ @port = 0
75
+ @num_nodes = 10
76
+ @num_vbuckets = 4096
77
+ @buckets_spec = "default:" # "default:,protected:secret,cache::memcache"
78
+ params.each do |key, value|
79
+ send("#{key}=", value)
80
+ end
81
+ yield self if block_given?
82
+ if @num_vbuckets < 1 || (@num_vbuckets & (@num_vbuckets - 1) != 0)
83
+ raise ArgumentError, "Number of vbuckets should be a power of two and greater than zero"
84
+ end
85
+ end
86
+
87
+ def start
88
+ @monitor = Monitor.new
89
+ @monitor.socket = TCPServer.new(nil, 0)
90
+ @monitor.socket.listen(10)
91
+ _, @monitor.port, _, _ = @monitor.socket.addr
92
+ trap("CLD") do
93
+ puts "CouchbaseMock.jar died unexpectedly during startup"
94
+ exit(1)
95
+ end
96
+ @monitor.pid = fork
97
+ if @monitor.pid.nil?
98
+ rc = exec(command_line("--harakiri-monitor=:#{@monitor.port}"))
99
+ else
100
+ trap("CLD", "SIG_DFL")
101
+ @monitor.client, _ = @monitor.socket.accept
102
+ @port = @monitor.client.recv(100).to_i
103
+ end
104
+ end
105
+
106
+ def stop
107
+ @monitor.client.close
108
+ @monitor.socket.close
109
+ Process.kill("TERM", @monitor.pid)
110
+ Process.wait(@monitor.pid)
111
+ end
112
+
113
+ def failover_node(index, bucket = "default")
114
+ @monitor.client.send("failover,#{index},#{bucket}", 0)
115
+ end
116
+
117
+ def respawn_node(index, bucket = "default")
118
+ @monitor.client.send("respawn,#{index},#{bucket}", 0)
119
+ end
120
+
121
+ protected
122
+
123
+ def command_line(extra = nil)
124
+ cmd = "java -jar #{File.dirname(__FILE__)}/CouchbaseMock.jar"
125
+ cmd << " --host #{@host}" if @host
126
+ cmd << " --port #{@port}" if @port
127
+ cmd << " --nodes #{@num_nodes}" if @num_nodes
128
+ cmd << " --vbuckets #{@num_vbuckets}" if @num_vbuckets
129
+ cmd << " --buckets #{@buckets_spec}" if @buckets_spec
130
+ cmd << " #{extra}"
131
+ cmd
132
+ end
133
+ end
134
+
135
+ class MiniTest::Test
136
+
137
+ def start_mock(params = {})
138
+ mock = nil
139
+ if ENV['COUCHBASE_SERVER']
140
+ mock = CouchbaseServer.new(params)
141
+ if (params[:port] && mock.port != params[:port]) ||
142
+ (params[:host] && mock.host != params[:host]) ||
143
+ mock.buckets_spec != "default:"
144
+ skip("Unable to configure real cluster. Requested config is: #{params.inspect}")
145
+ end
146
+ else
147
+ mock = CouchbaseMock.new(params)
148
+ end
149
+ mock.start
150
+ mock
151
+ end
152
+
153
+ def stop_mock(mock)
154
+ assert(mock)
155
+ mock.stop
156
+ end
157
+
158
+ def with_mock(params = {})
159
+ mock = nil
160
+ if block_given?
161
+ mock = start_mock(params)
162
+ yield mock
163
+ end
164
+ ensure
165
+ stop_mock(mock) if mock
166
+ end
167
+
168
+ def uniq_id(*suffixes)
169
+ test_id = [caller.first[/.*[` ](.*)'/, 1], suffixes].compact.join("_")
170
+ @ids ||= {}
171
+ @ids[test_id] ||= Time.now.to_f
172
+ [test_id, @ids[test_id]].join("_")
173
+ end
174
+
175
+ def after_teardown
176
+ GC.start
177
+ end
178
+ end