couchbase 1.2.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -1
- data/README.markdown +12 -8
- data/RELEASE_NOTES.markdown +19 -0
- data/couchbase.gemspec +1 -0
- data/examples/chat-goliath-grape/Gemfile +5 -0
- data/examples/chat-goliath-grape/README.markdown +50 -0
- data/examples/chat-goliath-grape/app.rb +67 -0
- data/examples/chat-goliath-grape/config/app.rb +20 -0
- data/examples/transcoders/Gemfile +3 -0
- data/examples/transcoders/README.markdown +59 -0
- data/examples/transcoders/cb-zcat +40 -0
- data/examples/transcoders/cb-zcp +45 -0
- data/examples/transcoders/gzip_transcoder.rb +49 -0
- data/examples/transcoders/options.rb +54 -0
- data/ext/couchbase_ext/arguments.c +67 -22
- data/ext/couchbase_ext/bucket.c +64 -20
- data/ext/couchbase_ext/context.c +2 -1
- data/ext/couchbase_ext/couchbase_ext.c +59 -9
- data/ext/couchbase_ext/couchbase_ext.h +18 -9
- data/ext/couchbase_ext/get.c +19 -23
- data/ext/couchbase_ext/store.c +1 -1
- data/ext/couchbase_ext/utils.c +38 -81
- data/lib/active_support/cache/couchbase_store.rb +60 -23
- data/lib/couchbase.rb +4 -2
- data/lib/couchbase/connection_pool.rb +55 -0
- data/lib/couchbase/transcoder.rb +120 -0
- data/lib/couchbase/version.rb +1 -1
- data/tasks/compile.rake +1 -1
- data/test/test_bucket.rb +1 -1
- data/test/test_couchbase_connection_pool.rb +73 -0
- data/test/test_couchbase_rails_cache_store.rb +36 -12
- data/test/test_format.rb +51 -1
- metadata +184 -127
- checksums.yaml +0 -15
data/.yardopts
CHANGED
data/README.markdown
CHANGED
@@ -387,18 +387,22 @@ The result is represented as a hash with the server node address as
|
|
387
387
|
the key and stats as key-value pairs.
|
388
388
|
|
389
389
|
{
|
390
|
-
"
|
390
|
+
"threads"=>
|
391
391
|
{
|
392
|
-
"
|
393
|
-
"
|
394
|
-
"ep_max_txn_size"=>"10000",
|
392
|
+
"172.16.16.76:12008"=>"4",
|
393
|
+
"172.16.16.76:12000"=>"4",
|
395
394
|
# ...
|
396
395
|
},
|
397
|
-
"
|
396
|
+
"connection_structures"=>
|
398
397
|
{
|
399
|
-
"
|
400
|
-
"
|
401
|
-
|
398
|
+
"172.16.16.76:12008"=>"22",
|
399
|
+
"172.16.16.76:12000"=>"447",
|
400
|
+
# ...
|
401
|
+
},
|
402
|
+
"ep_max_txn_size"=>
|
403
|
+
{
|
404
|
+
"172.16.16.76:12008"=>"1000",
|
405
|
+
"172.16.16.76:12000"=>"1000",
|
402
406
|
# ...
|
403
407
|
},
|
404
408
|
# ...
|
data/RELEASE_NOTES.markdown
CHANGED
@@ -3,6 +3,25 @@
|
|
3
3
|
This document is a list of user visible feature changes and important
|
4
4
|
bugfixes. Do not forget to update this doc in every important patch.
|
5
5
|
|
6
|
+
## 1.3.0 (2014-05-07)
|
7
|
+
|
8
|
+
* [major] RCBC-46 implement Couchbase::ConnectionPool to allow
|
9
|
+
applications (and ActiveSupport::Cache::CouchbaseStore) use it in
|
10
|
+
multi-threaded environment
|
11
|
+
|
12
|
+
* [major] Introduce Transcoders. This mechanism is more flexible, and
|
13
|
+
similar to how other clients encode values.
|
14
|
+
|
15
|
+
* [minor] Deprecate numeric argument to 'default_format'. Instead
|
16
|
+
of this style:
|
17
|
+
|
18
|
+
Couchbase.connect(:default_format => Couchbase::Bucket::FMT_MARSHAL)
|
19
|
+
|
20
|
+
Symbol notation or explicit transcoder entity should be used
|
21
|
+
|
22
|
+
Couchbase.connect(:default_format => :marshal)
|
23
|
+
Couchbase.connect(:transcoder => Couchbase::Transcoder::Marshal)
|
24
|
+
|
6
25
|
## 1.2.3 (2013-04-02)
|
7
26
|
|
8
27
|
* [major] Make ActiveSupport::Cache::CouchbaseStore threadsafe
|
data/couchbase.gemspec
CHANGED
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
|
|
37
37
|
|
38
38
|
s.add_runtime_dependency 'yaji', '~> 0.3.2'
|
39
39
|
s.add_runtime_dependency 'multi_json', '~> 1.0'
|
40
|
+
s.add_runtime_dependency 'connection_pool', '~> 0.9.2'
|
40
41
|
|
41
42
|
s.add_development_dependency 'rake'
|
42
43
|
s.add_development_dependency 'minitest'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Couchbase + Grape + Goliath = <3
|
2
|
+
|
3
|
+
This demo shows how to integrate these cool things to build
|
4
|
+
asynchronous REST service
|
5
|
+
|
6
|
+
# Usage
|
7
|
+
|
8
|
+
1. Clone the repository. Navigate to `examples/chat-goliath-grape/`
|
9
|
+
directory
|
10
|
+
|
11
|
+
2. Install libcouchbase (http://www.couchbase.com/develop/c/current).
|
12
|
+
For MacOS users it will look like:
|
13
|
+
|
14
|
+
brew update
|
15
|
+
brew install libcouchbase
|
16
|
+
|
17
|
+
3. Install all ruby dependencies. This demo has been tested on latest
|
18
|
+
stable version of ruby (`ruby 2.0.0p0 (2013-02-24 revision 39474)
|
19
|
+
[x86_64-linux]`)
|
20
|
+
|
21
|
+
gem install bundler
|
22
|
+
bundle install
|
23
|
+
|
24
|
+
4. Setup your Couchbase server
|
25
|
+
(http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-getting-started.html).
|
26
|
+
It should have `default` bucket. Or you can edit connection options
|
27
|
+
in `config/app.rb` file.
|
28
|
+
|
29
|
+
5. Start the server up
|
30
|
+
|
31
|
+
ruby app.rb -sv
|
32
|
+
|
33
|
+
6. Create an message:
|
34
|
+
|
35
|
+
$ curl -X POST -Fmessage="Hello world" http://localhost:9000/messages
|
36
|
+
{"ok":true,"id":"msg:1","cas":11880713153673363456}
|
37
|
+
|
38
|
+
7. If you create a design document called `messages` and put a view
|
39
|
+
named `all` with this map function:
|
40
|
+
|
41
|
+
function(doc, meta) {
|
42
|
+
if (doc.timestamp) {
|
43
|
+
emit(meta.id, doc)
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
You can fetch all messages with this command:
|
48
|
+
|
49
|
+
curl -X GET http://localhost:9000/messages
|
50
|
+
{"ok":true,"messages":[{"id":"msg:1","key":"msg:1","value":{"timestamp":"2013-04-11T12:43:42+03:00","message":"Hello world"},"cas":11880713153673363456}]}
|
@@ -0,0 +1,67 @@
|
|
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 'em-synchrony'
|
19
|
+
require 'couchbase'
|
20
|
+
require 'goliath'
|
21
|
+
require 'grape'
|
22
|
+
require 'date'
|
23
|
+
|
24
|
+
class Chat < Grape::API
|
25
|
+
|
26
|
+
format :json
|
27
|
+
|
28
|
+
resource 'messages' do
|
29
|
+
get do
|
30
|
+
view = env.couchbase.design_docs["messages"].all(:include_docs => true)
|
31
|
+
msgs = view.map do |r|
|
32
|
+
{
|
33
|
+
"id" => r.id,
|
34
|
+
"key" => r.key,
|
35
|
+
"value" => r.value,
|
36
|
+
"cas" => r.meta["cas"],
|
37
|
+
# "doc" => r.doc
|
38
|
+
}
|
39
|
+
end
|
40
|
+
{"ok" => true, "messages" => msgs}
|
41
|
+
end
|
42
|
+
|
43
|
+
post do
|
44
|
+
payload = {
|
45
|
+
"timestamp" => DateTime.now.iso8601,
|
46
|
+
"message" => params["message"]
|
47
|
+
}
|
48
|
+
id = env.couchbase.incr("msgid", :initial => 1)
|
49
|
+
id = "msg:#{id}"
|
50
|
+
cas = env.couchbase.set(id, payload)
|
51
|
+
{"ok" => true, "id" => id, "cas" => cas}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class App < Goliath::API
|
58
|
+
def response(env)
|
59
|
+
Chat.call(env)
|
60
|
+
rescue => e
|
61
|
+
[
|
62
|
+
500,
|
63
|
+
{'Content-Type' => 'application/json'},
|
64
|
+
MultiJson.dump(:error => e, :stacktrace => e.backtrace)
|
65
|
+
]
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,20 @@
|
|
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
|
+
config['couchbase'] = EventMachine::Synchrony::ConnectionPool.new(:size => 5) do
|
19
|
+
Couchbase::Bucket.new(:engine => :eventmachine)
|
20
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Gzip Transcoder
|
2
|
+
|
3
|
+
This example demonstrates advanced usage of client-side transcoders.
|
4
|
+
In particular it uses GzipWriter and GzipReader classes from ruby
|
5
|
+
standard library to keep documents compressed. The example shows basic
|
6
|
+
technique, so that it can be used as a starting point to write your
|
7
|
+
custom data filters and adaptors.
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
1. Clone the repository. Navigate to directory `examples/transcoders`.
|
12
|
+
|
13
|
+
2. Install libcouchbase (http://www.couchbase.com/develop/c/current).
|
14
|
+
For MacOS users it will look like:
|
15
|
+
|
16
|
+
brew update
|
17
|
+
brew install libcouchbase
|
18
|
+
|
19
|
+
3. Install all ruby dependencies. This demo has been tested on latest
|
20
|
+
stable version of ruby (`ruby 2.0.0p0 (2013-02-24 revision 39474)
|
21
|
+
[x86_64-linux]`)
|
22
|
+
|
23
|
+
gem install bundler
|
24
|
+
bundle install
|
25
|
+
|
26
|
+
4. Setup your Couchbase server
|
27
|
+
(http://www.couchbase.com/docs/couchbase-manual-2.0/couchbase-getting-started.html).
|
28
|
+
It should have `default` bucket. Or you can specify different
|
29
|
+
bucket using CLI options.
|
30
|
+
|
31
|
+
5. Store some file to the cluster:
|
32
|
+
|
33
|
+
$ ./cb-zcp Gemfile
|
34
|
+
Run with arguments: {:bucket=>"default", :hostname=>"127.0.0.1", :port=>8091, :username=>nil, :password=>nil}
|
35
|
+
store "Gemfile" ... ok
|
36
|
+
|
37
|
+
6. Get the data back:
|
38
|
+
|
39
|
+
$ ./cb-zcat Gemfile
|
40
|
+
Run with arguments: {:bucket=>"default", :hostname=>"127.0.0.1", :port=>8091, :username=>nil, :password=>nil}
|
41
|
+
Gemfile:
|
42
|
+
source 'https://rubygems.org'
|
43
|
+
|
44
|
+
gem 'couchbase'
|
45
|
+
|
46
|
+
7. To make sure that the data is in compressed state, you can check it in `irb`:
|
47
|
+
|
48
|
+
$ bundle exec irb
|
49
|
+
2.0.0p0 (main):001:0> require 'couchbase'
|
50
|
+
true
|
51
|
+
2.0.0p0 (main):002:0> conn = Couchbase.connect(:transcoder => nil)
|
52
|
+
#<Couchbase::Bucket:0x007fa344886fc8 "http://localhost:8091/pools/default/buckets/default/" transcoder=nil, default_flags=0x0, quiet=false, connected=true, timeout=2500000>
|
53
|
+
2.0.0p0 (main):003:0> File.open("Gemfile.gz", "w+"){|f| f.write(conn.get("Gemfile"))}
|
54
|
+
65
|
55
|
+
|
56
|
+
$ zcat Gemfile.gz
|
57
|
+
source 'https://rubygems.org'
|
58
|
+
|
59
|
+
gem 'couchbase'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Author:: Couchbase <info@couchbase.com>
|
3
|
+
# Copyright:: 2013 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 'bundler'
|
20
|
+
Bundler.setup
|
21
|
+
|
22
|
+
require 'couchbase'
|
23
|
+
|
24
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
25
|
+
require 'gzip_transcoder'
|
26
|
+
require 'options'
|
27
|
+
|
28
|
+
STDERR.puts "Run with arguments: #{OPTIONS.inspect}"
|
29
|
+
begin
|
30
|
+
conn = Couchbase.connect(OPTIONS)
|
31
|
+
conn.transcoder = GzipTranscoder.new
|
32
|
+
|
33
|
+
ARGV.each do |filename|
|
34
|
+
STDERR.puts "#{filename}:"
|
35
|
+
STDOUT.puts(conn.get(filename))
|
36
|
+
end
|
37
|
+
rescue Couchbase::Error::Base => ex
|
38
|
+
STDERR.puts "ERROR: #{ex}"
|
39
|
+
exit 1
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Author:: Couchbase <info@couchbase.com>
|
3
|
+
# Copyright:: 2013 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 'bundler'
|
20
|
+
Bundler.setup
|
21
|
+
|
22
|
+
require 'couchbase'
|
23
|
+
|
24
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
25
|
+
require 'gzip_transcoder'
|
26
|
+
require 'options'
|
27
|
+
|
28
|
+
STDERR.puts "Run with arguments: #{OPTIONS.inspect}"
|
29
|
+
begin
|
30
|
+
conn = Couchbase.connect(OPTIONS)
|
31
|
+
conn.transcoder = GzipTranscoder.new
|
32
|
+
|
33
|
+
ARGV.each do |filename|
|
34
|
+
STDERR.print "store \"#{filename}\" ... "
|
35
|
+
if File.exists?(filename)
|
36
|
+
conn.set(filename, File.read(filename))
|
37
|
+
STDERR.puts "ok"
|
38
|
+
else
|
39
|
+
STDERR.puts "not found"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
rescue Couchbase::Error::Base => ex
|
43
|
+
STDERR.puts "ERROR: #{ex}"
|
44
|
+
exit 1
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
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 'zlib'
|
19
|
+
require 'stringio'
|
20
|
+
|
21
|
+
# This class wraps any other transcoder and performs compression
|
22
|
+
# using zlib
|
23
|
+
class GzipTranscoder
|
24
|
+
FMT_GZIP = 0x04
|
25
|
+
|
26
|
+
def initialize(base = nil)
|
27
|
+
@base = base || Couchbase::Transcoder::Plain
|
28
|
+
end
|
29
|
+
|
30
|
+
def dump(obj, flags, options = {})
|
31
|
+
obj, flags = @base.dump(obj, flags, options)
|
32
|
+
io = StringIO.new
|
33
|
+
gz = Zlib::GzipWriter.new(io)
|
34
|
+
gz.write(obj)
|
35
|
+
gz.close
|
36
|
+
[io.string, flags|FMT_GZIP]
|
37
|
+
end
|
38
|
+
|
39
|
+
def load(blob, flags, options = {})
|
40
|
+
# decompress value only if gzip flag set
|
41
|
+
if (flags & FMT_GZIP) == FMT_GZIP
|
42
|
+
io = StringIO.new(blob)
|
43
|
+
gz = Zlib::GzipReader.new(io)
|
44
|
+
blob = gz.read
|
45
|
+
gz.close
|
46
|
+
end
|
47
|
+
@base.load(blob, flags, options)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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 'optparse'
|
19
|
+
|
20
|
+
# just output extra empty line on CTRL-C
|
21
|
+
trap("INT") do
|
22
|
+
STDERR.puts
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
OPTIONS = {
|
27
|
+
:bucket => "default",
|
28
|
+
:hostname => "127.0.0.1",
|
29
|
+
:port => 8091,
|
30
|
+
:username => nil,
|
31
|
+
:password => nil
|
32
|
+
}
|
33
|
+
|
34
|
+
OptionParser.new do |opts|
|
35
|
+
opts.banner = "Usage: #{$0} [options] keys"
|
36
|
+
opts.on("-h", "--hostname HOSTNAME", "Hostname to connect to (default: #{OPTIONS[:hostname]}:#{OPTIONS[:port]})") do |v|
|
37
|
+
host, port = v.split(':')
|
38
|
+
OPTIONS[:hostname] = host.empty? ? '127.0.0.1' : host
|
39
|
+
OPTIONS[:port] = port.to_i > 0 ? port.to_i : 8091
|
40
|
+
end
|
41
|
+
opts.on("-u", "--user USERNAME", "Username to log with (default: none)") do |v|
|
42
|
+
OPTIONS[:username] = v
|
43
|
+
end
|
44
|
+
opts.on("-p", "--password PASSWORD", "Password to log with (default: none)") do |v|
|
45
|
+
OPTIONS[:password] = v
|
46
|
+
end
|
47
|
+
opts.on("-b", "--bucket NAME", "Name of the bucket to connect to (default: #{OPTIONS[:bucket]})") do |v|
|
48
|
+
OPTIONS[:bucket] = v
|
49
|
+
end
|
50
|
+
opts.on_tail("-?", "--help", "Show this message") do
|
51
|
+
STDERR.puts opts
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
end.parse!
|