couchbase 1.2.3-x86-mingw32 → 1.3.0-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,10 +16,9 @@
16
16
  #
17
17
 
18
18
  require 'couchbase/version'
19
- require 'multi_json'
20
- require 'ext/multi_json_fix'
21
19
  require 'yaji'
22
20
  require 'uri'
21
+ require 'couchbase/transcoder'
23
22
  require 'couchbase_ext'
24
23
  require 'couchbase/constants'
25
24
  require 'couchbase/utils'
@@ -29,9 +28,12 @@ require 'couchbase/view'
29
28
  require 'couchbase/result'
30
29
  require 'couchbase/cluster'
31
30
 
31
+
32
32
  # Couchbase ruby client
33
33
  module Couchbase
34
34
 
35
+ autoload(:ConnectionPool, 'couchbase/connection_pool')
36
+
35
37
  class << self
36
38
  # The method +connect+ initializes new Bucket instance with all arguments passed.
37
39
  #
@@ -0,0 +1,55 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 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 'connection_pool'
19
+
20
+ module Couchbase
21
+ class ConnectionPool
22
+
23
+ def initialize(pool_size = 5, *args)
24
+ @pool = ::ConnectionPool.new(:size => pool_size) { ::Couchbase::Bucket.new(*args) }
25
+ end
26
+
27
+ def with
28
+ yield @pool.checkout
29
+ ensure
30
+ @pool.checkin
31
+ end
32
+
33
+ def respond_to?(id, *args)
34
+ super || @pool.with { |c| c.respond_to?(id, *args) }
35
+ end
36
+
37
+ def method_missing(name, *args, &block)
38
+ define_proxy_method(name)
39
+ send(name, *args, &block)
40
+ end
41
+
42
+ protected
43
+
44
+ def define_proxy_method(name)
45
+ self.class.class_eval <<-RUBY
46
+ def #{name}(*args, &block)
47
+ @pool.with do |connection|
48
+ connection.send(#{name.inspect}, *args, &block)
49
+ end
50
+ end
51
+ RUBY
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,120 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 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 'multi_json'
19
+ require 'ext/multi_json_fix'
20
+
21
+ module Couchbase
22
+
23
+ module Transcoder
24
+
25
+ module Compat
26
+ def self.enable!
27
+ @disabled = false
28
+ end
29
+
30
+ def self.disable!
31
+ @disabled = true
32
+ end
33
+
34
+ def self.enabled?
35
+ !@disabled
36
+ end
37
+
38
+ def self.guess_and_load(blob, flags, options = {})
39
+ case flags & Bucket::FMT_MASK
40
+ when Bucket::FMT_DOCUMENT
41
+ MultiJson.load(blob)
42
+ when Bucket::FMT_MARSHAL
43
+ ::Marshal.load(blob)
44
+ when Bucket::FMT_PLAIN
45
+ blob
46
+ else
47
+ raise ArgumentError, "unexpected flags (0x%02x)" % flags
48
+ end
49
+ end
50
+ end
51
+
52
+ module Document
53
+ def self.dump(obj, flags, options = {})
54
+ [
55
+ MultiJson.dump(obj),
56
+ (flags & ~Bucket::FMT_MASK) | Bucket::FMT_DOCUMENT
57
+ ]
58
+ end
59
+
60
+ def self.load(blob, flags, options = {})
61
+ if (flags & Bucket::FMT_MASK) == Bucket::FMT_DOCUMENT || options[:forced]
62
+ MultiJson.load(blob)
63
+ else
64
+ if Compat.enabled?
65
+ return Compat.guess_and_load(blob, flags, options)
66
+ else
67
+ raise ArgumentError,
68
+ "unexpected flags (0x%02x instead of 0x%02x)" % [flags, Bucket::FMT_DOCUMENT]
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ module Marshal
75
+ def self.dump(obj, flags, options = {})
76
+ [
77
+ ::Marshal.dump(obj),
78
+ (flags & ~Bucket::FMT_MASK) | Bucket::FMT_MARSHAL
79
+ ]
80
+ end
81
+
82
+ def self.load(blob, flags, options = {})
83
+ if (flags & Bucket::FMT_MASK) == Bucket::FMT_MARSHAL || options[:forced]
84
+ ::Marshal.load(blob)
85
+ else
86
+ if Compat.enabled?
87
+ return Compat.guess_and_load(blob, flags, options)
88
+ else
89
+ raise ArgumentError,
90
+ "unexpected flags (0x%02x instead of 0x%02x)" % [flags, Bucket::FMT_MARSHAL]
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ module Plain
97
+ def self.dump(obj, flags, options = {})
98
+ [
99
+ obj,
100
+ (flags & ~Bucket::FMT_MASK) | Bucket::FMT_PLAIN
101
+ ]
102
+ end
103
+
104
+ def self.load(blob, flags, options = {})
105
+ if (flags & Bucket::FMT_MASK) == Bucket::FMT_PLAIN || options[:forced]
106
+ blob
107
+ else
108
+ if Compat.enabled?
109
+ return Compat.guess_and_load(blob, flags, options)
110
+ else
111
+ raise ArgumentError,
112
+ "unexpected flags (0x%02x instead of 0x%02x)" % [flags, Bucket::FMT_PLAIN]
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ end
119
+
120
+ end
@@ -17,5 +17,5 @@
17
17
 
18
18
  # Couchbase ruby client
19
19
  module Couchbase
20
- VERSION = "1.2.3"
20
+ VERSION = "1.3.0"
21
21
  end
@@ -84,7 +84,7 @@ namespace :ports do
84
84
  directory "ports"
85
85
 
86
86
  task :libcouchbase => ["ports"] do
87
- recipe = MiniPortile.new "libcouchbase", "2.0.3"
87
+ recipe = MiniPortile.new "libcouchbase", "2.0.6"
88
88
  recipe.files << "http://packages.couchbase.com/clients/c/libcouchbase-#{recipe.version}.tar.gz"
89
89
  recipe.configure_options.push("--disable-debug",
90
90
  "--disable-dependency-tracking",
@@ -128,7 +128,7 @@ class TestBucket < MiniTest::Unit::TestCase
128
128
  end
129
129
  end
130
130
 
131
- def test_it_unable_to_connect_to_protected_buckets_with_wrond_credentials
131
+ def test_it_unable_to_connect_to_protected_buckets_with_wrong_credentials
132
132
  with_mock(:buckets_spec => 'protected:secret') do |mock|
133
133
  assert_raises Couchbase::Error::Auth do
134
134
  Couchbase.new(:hostname => mock.host,
@@ -0,0 +1,73 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 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 File.join(File.dirname(__FILE__), 'setup')
19
+ require 'couchbase/connection_pool'
20
+
21
+ class TestCouchbaseConnectionPool < MiniTest::Unit::TestCase
22
+
23
+ def setup
24
+ @mock = start_mock
25
+ @pool = ::Couchbase::ConnectionPool.new(5, :hostname => @mock.host, :port => @mock.port)
26
+ end
27
+
28
+ def teardown
29
+ stop_mock(@mock)
30
+ end
31
+
32
+ def test_basic_multithreaded_usage
33
+ @pool.set('foo', 'bar')
34
+
35
+ threads = []
36
+ 15.times do
37
+ threads << Thread.new do
38
+ @pool.get('foo')
39
+ end
40
+ end
41
+
42
+ result = threads.map(&:value)
43
+ result.each do |val|
44
+ assert_equal 'bar', val
45
+ end
46
+ end
47
+
48
+ def test_set_and_get
49
+ @pool.set('fiz', 'buzz')
50
+ assert_equal 'buzz', @pool.get('fiz')
51
+ end
52
+
53
+ def test_set_and_delete
54
+ @pool.set('baz', 'bar')
55
+ @pool.delete('baz')
56
+ assert_raises Couchbase::Error::NotFound do
57
+ @pool.get('baz')
58
+ end
59
+ end
60
+
61
+ def test_incr
62
+ @pool.set('counter', 0)
63
+ @pool.incr('counter', 1)
64
+ assert_equal 1, @pool.get('counter')
65
+ end
66
+
67
+ def test_decr
68
+ @pool.set('counter', 1)
69
+ @pool.decr('counter', 1)
70
+ assert_equal 0, @pool.get('counter')
71
+ end
72
+
73
+ end
@@ -37,6 +37,12 @@ class TestCouchbaseRailsCacheStore < MiniTest::Unit::TestCase
37
37
  :port => @mock.port)
38
38
  end
39
39
 
40
+ def pool_store
41
+ @pool_store ||= ActiveSupport::Cache::CouchbaseStore.new(:hostname => @mock.host,
42
+ :port => @mock.port,
43
+ :connection_pool => 5)
44
+ end
45
+
40
46
  def test_it_supported_methods
41
47
  supported_methods = store.public_methods(false).map(&:to_sym)
42
48
  assert supported_methods.include?(:fetch)
@@ -78,18 +84,17 @@ class TestCouchbaseRailsCacheStore < MiniTest::Unit::TestCase
78
84
  end
79
85
  end
80
86
 
81
- if RUBY_VERSION.match /1\.9/
82
- def test_it_reads_raw_data
83
- store.write uniq_id, @foo
84
- assert_equal "\x04\bU:\x0FOpenStruct{\x06:\fpayloadI\"\bfoo\x06:\x06EF",
85
- store.read(uniq_id, :raw => true)
86
- end
87
- else
88
- def test_it_reads_raw_data
89
- store.write uniq_id, @foo
90
- assert_equal "\004\bU:\017OpenStruct{\006:\fpayload\"\bfoo",
91
- store.read(uniq_id, :raw => true)
92
- end
87
+ def test_it_reads_raw_data
88
+ store.write uniq_id, @foo
89
+ expected = case RUBY_VERSION
90
+ when /^2\.0/
91
+ "\x04\bU:\x0FOpenStruct{\x06:\fpayloadI\"\bfoo\x06:\x06ET"
92
+ when /^1\.9/
93
+ "\x04\bU:\x0FOpenStruct{\x06:\fpayloadI\"\bfoo\x06:\x06EF"
94
+ else
95
+ "\004\bU:\017OpenStruct{\006:\fpayload\"\bfoo"
96
+ end
97
+ assert_equal expected, store.read(uniq_id, :raw => true)
93
98
  end
94
99
 
95
100
  def test_it_writes_raw_data
@@ -303,6 +308,25 @@ class TestCouchbaseRailsCacheStore < MiniTest::Unit::TestCase
303
308
  workers.each { |w| w.join }
304
309
  end
305
310
 
311
+ def test_it_can_use_connection_pool_for_thread_safety
312
+ workers = []
313
+
314
+ 10.times do
315
+ workers << Thread.new do
316
+ 100.times do
317
+ pool_store.write('a', 9)
318
+ pool_store.write('b', 11)
319
+ assert_equal 9, pool_store.read('a')
320
+ assert_equal({ 'a' => 9, 'b' => 11 }, pool_store.read_multi('a', 'b'))
321
+ assert_equal 11, pool_store.read('b')
322
+ assert_equal %w(a b), pool_store.read_multi('a', 'b', 'c').keys.sort
323
+ end
324
+ end
325
+ end
326
+
327
+ workers.each { |w| w.join }
328
+ end
329
+
306
330
  private
307
331
 
308
332
  def collect_notifications
@@ -78,7 +78,7 @@ class TestFormat < MiniTest::Unit::TestCase
78
78
  connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
79
79
  connection.set(uniq_id, orig_doc, :format => :marshal)
80
80
  doc, flags, cas = connection.get(uniq_id, :extended => true)
81
- assert_equal 0x01, flags & 0x11
81
+ assert_equal Couchbase::Bucket::FMT_MARSHAL, flags & Couchbase::Bucket::FMT_MASK
82
82
  assert doc.is_a?(ArbitraryClass)
83
83
  assert_equal 'Twoflower', doc.name
84
84
  assert_equal 'The tourist', doc.role
@@ -106,4 +106,54 @@ class TestFormat < MiniTest::Unit::TestCase
106
106
  end
107
107
  end
108
108
 
109
+ def test_it_allows_to_turn_off_transcoder
110
+ connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port, :transcoder => nil)
111
+ connection.set(uniq_id, "value", :flags => 0xffff_ffff)
112
+ doc, flags, _ = connection.get(uniq_id, :extended => true)
113
+ assert_equal "value", doc
114
+ assert_equal 0xffff_ffff, flags
115
+ end
116
+
117
+ require 'zlib'
118
+ # This class wraps any other transcoder and performs compression
119
+ # using zlib
120
+ class ZlibTranscoder
121
+ FMT_ZLIB = 0x04
122
+
123
+ def initialize(base)
124
+ @base = base
125
+ end
126
+
127
+ def dump(obj, flags, options = {})
128
+ obj, flags = @base.dump(obj, flags, options)
129
+ z = Zlib::Deflate.new(Zlib::BEST_SPEED)
130
+ buffer = z.deflate(obj, Zlib::FINISH)
131
+ z.close
132
+ [buffer, flags|FMT_ZLIB]
133
+ end
134
+
135
+ def load(blob, flags, options = {})
136
+ # decompress value only if Zlib flag set
137
+ if (flags & FMT_ZLIB) == FMT_ZLIB
138
+ z = Zlib::Inflate.new
139
+ blob = z.inflate(blob)
140
+ z.finish
141
+ z.close
142
+ end
143
+ @base.load(blob, flags, options)
144
+ end
145
+ end
146
+
147
+ def test_it_can_use_custom_transcoder
148
+ connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
149
+ connection.transcoder = ZlibTranscoder.new(Couchbase::Transcoder::Document)
150
+ connection.set(uniq_id, {"foo" => "bar"})
151
+ doc, flags, _ = connection.get(uniq_id, :extended => true)
152
+ assert_equal({"foo" => "bar"}, doc)
153
+ assert_equal(ZlibTranscoder::FMT_ZLIB|Couchbase::Bucket::FMT_DOCUMENT, flags)
154
+ connection.transcoder = nil
155
+ doc = connection.get(uniq_id)
156
+ assert_equal "x\x01\xABVJ\xCB\xCFW\xB2RJJ,R\xAA\x05\0\x1Dz\x044", doc
157
+ end
158
+
109
159
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: x86-mingw32
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-02 00:00:00.000000000 Z
12
+ date: 2013-05-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yaji
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: '1.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: connection_pool
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.2
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: rake
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -175,6 +191,16 @@ files:
175
191
  - examples/chat-em/Gemfile
176
192
  - examples/chat-em/README.markdown
177
193
  - examples/chat-em/server.rb
194
+ - examples/chat-goliath-grape/Gemfile
195
+ - examples/chat-goliath-grape/README.markdown
196
+ - examples/chat-goliath-grape/app.rb
197
+ - examples/chat-goliath-grape/config/app.rb
198
+ - examples/transcoders/Gemfile
199
+ - examples/transcoders/README.markdown
200
+ - examples/transcoders/cb-zcat
201
+ - examples/transcoders/cb-zcp
202
+ - examples/transcoders/gzip_transcoder.rb
203
+ - examples/transcoders/options.rb
178
204
  - ext/couchbase_ext/.gitignore
179
205
  - ext/couchbase_ext/arguments.c
180
206
  - ext/couchbase_ext/arithmetic.c
@@ -204,8 +230,10 @@ files:
204
230
  - lib/couchbase.rb
205
231
  - lib/couchbase/bucket.rb
206
232
  - lib/couchbase/cluster.rb
233
+ - lib/couchbase/connection_pool.rb
207
234
  - lib/couchbase/constants.rb
208
235
  - lib/couchbase/result.rb
236
+ - lib/couchbase/transcoder.rb
209
237
  - lib/couchbase/utils.rb
210
238
  - lib/couchbase/version.rb
211
239
  - lib/couchbase/view.rb
@@ -225,6 +253,7 @@ files:
225
253
  - test/test_bucket.rb
226
254
  - test/test_cas.rb
227
255
  - test/test_couchbase.rb
256
+ - test/test_couchbase_connection_pool.rb
228
257
  - test/test_couchbase_rails_cache_store.rb
229
258
  - test/test_delete.rb
230
259
  - test/test_errors.rb
@@ -256,7 +285,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
256
285
  version: '0'
257
286
  segments:
258
287
  - 0
259
- hash: -322659644960790893
288
+ hash: 3514560369886917635
260
289
  required_rubygems_version: !ruby/object:Gem::Requirement
261
290
  none: false
262
291
  requirements:
@@ -265,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
265
294
  version: '0'
266
295
  segments:
267
296
  - 0
268
- hash: -322659644960790893
297
+ hash: 3514560369886917635
269
298
  requirements: []
270
299
  rubyforge_project:
271
300
  rubygems_version: 1.8.23