couchbase 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
- data/.yardopts +5 -0
- data/HISTORY.markdown +14 -10
- data/README.markdown +293 -98
- data/Rakefile +19 -24
- data/couchbase.gemspec +25 -7
- data/ext/couchbase_ext/couchbase_ext.c +2332 -0
- data/ext/couchbase_ext/extconf.rb +102 -0
- data/lib/couchbase.rb +20 -30
- data/lib/couchbase/bucket.rb +43 -112
- data/lib/couchbase/version.rb +3 -2
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +52 -0
- data/tasks/doc.rake +27 -0
- data/tasks/test.rake +94 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +107 -18
- data/test/test_arithmetic.rb +98 -0
- data/test/test_async.rb +211 -0
- data/test/test_bucket.rb +126 -23
- data/test/test_cas.rb +59 -0
- data/test/test_couchbase.rb +22 -3
- data/test/test_delete.rb +63 -0
- data/test/test_errors.rb +82 -0
- data/test/test_flush.rb +49 -0
- data/test/test_format.rb +98 -0
- data/test/test_get.rb +236 -0
- data/test/test_stats.rb +53 -0
- data/test/test_store.rb +186 -0
- data/test/test_touch.rb +57 -0
- data/test/test_version.rb +17 -0
- metadata +72 -58
- data/lib/couchbase/couchdb.rb +0 -107
- data/lib/couchbase/document.rb +0 -71
- data/lib/couchbase/http_status.rb +0 -118
- data/lib/couchbase/latch.rb +0 -71
- data/lib/couchbase/memcached.rb +0 -372
- data/lib/couchbase/node.rb +0 -49
- data/lib/couchbase/rest_client.rb +0 -124
- data/lib/couchbase/view.rb +0 -182
- data/test/support/buckets-config.json +0 -843
- data/test/support/sample_design_doc.json +0 -9
- data/test/test_couchdb.rb +0 -98
- data/test/test_document.rb +0 -11
- data/test/test_latch.rb +0 -88
- data/test/test_memcached.rb +0 -59
- data/test/test_rest_client.rb +0 -14
- data/test/test_view.rb +0 -98
@@ -0,0 +1,102 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Author:: Couchbase <info@couchbase.com>
|
3
|
+
# Copyright:: 2011, 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
|
+
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
20
|
+
|
21
|
+
require 'mkmf'
|
22
|
+
|
23
|
+
LIBDIR = Config::CONFIG['libdir']
|
24
|
+
INCLUDEDIR = Config::CONFIG['includedir']
|
25
|
+
|
26
|
+
HEADER_DIRS = [
|
27
|
+
# First search /opt/local for macports
|
28
|
+
'/opt/local/include',
|
29
|
+
# Then search /usr/local for people that installed from source
|
30
|
+
'/usr/local/include',
|
31
|
+
# Check the ruby install locations
|
32
|
+
INCLUDEDIR,
|
33
|
+
# Finally fall back to /usr
|
34
|
+
'/usr/include'
|
35
|
+
]
|
36
|
+
|
37
|
+
LIB_DIRS = [
|
38
|
+
# First search /opt/local for macports
|
39
|
+
'/opt/local/lib',
|
40
|
+
# Then search /usr/local for people that installed from source
|
41
|
+
'/usr/local/lib',
|
42
|
+
# Check the ruby install locations
|
43
|
+
LIBDIR,
|
44
|
+
# Finally fall back to /usr
|
45
|
+
'/usr/lib'
|
46
|
+
]
|
47
|
+
|
48
|
+
# For people using homebrew
|
49
|
+
brew_prefix = `brew --prefix libevent 2> /dev/null`.chomp
|
50
|
+
unless brew_prefix.empty?
|
51
|
+
LIB_DIRS.unshift File.join(brew_prefix, 'lib')
|
52
|
+
HEADER_DIRS.unshift File.join(brew_prefix, 'include')
|
53
|
+
end
|
54
|
+
|
55
|
+
HEADER_DIRS.delete_if{|d| !File.exists?(d)}
|
56
|
+
LIB_DIRS.delete_if{|d| !File.exists?(d)}
|
57
|
+
|
58
|
+
def define(macro, value = nil)
|
59
|
+
$defs.push("-D #{[macro.upcase, value].compact.join('=')}")
|
60
|
+
end
|
61
|
+
|
62
|
+
# it will find the libcouchbase likely. you can specify its path otherwise
|
63
|
+
#
|
64
|
+
# ruby extconf.rb [--with-libcouchbase-include=<dir>] [--with-libcouchbase-lib=<dir>]
|
65
|
+
#
|
66
|
+
# or
|
67
|
+
#
|
68
|
+
# ruby extconf.rb [--with-libcouchbase-dir=<dir>]
|
69
|
+
#
|
70
|
+
dir_config("libcouchbase", HEADER_DIRS, LIB_DIRS)
|
71
|
+
|
72
|
+
if COMMON_HEADERS !~ /"ruby\.h"/
|
73
|
+
COMMON_HEADERS << %(#include "ruby.h"\n)
|
74
|
+
end
|
75
|
+
|
76
|
+
$CFLAGS << ' -std=c99 -Wall -Wextra '
|
77
|
+
if ENV['DEBUG']
|
78
|
+
$CFLAGS << ' -O0 -ggdb3 -pedantic'
|
79
|
+
end
|
80
|
+
|
81
|
+
if try_compile(<<-SRC)
|
82
|
+
#include <stdarg.h>
|
83
|
+
int foo(int x, ...) {
|
84
|
+
va_list va;
|
85
|
+
va_start(va, x);
|
86
|
+
va_arg(va, int);
|
87
|
+
va_arg(va, char *);
|
88
|
+
va_arg(va, double);
|
89
|
+
return 0;
|
90
|
+
}
|
91
|
+
int main() {
|
92
|
+
return foo(10, "", 3.14);
|
93
|
+
return 0;
|
94
|
+
}
|
95
|
+
SRC
|
96
|
+
define("HAVE_STDARG_PROTOTYPES")
|
97
|
+
end
|
98
|
+
|
99
|
+
have_library("event", "event_init", "event.h") || abort
|
100
|
+
have_library("couchbase", "libcouchbase_create", "libcouchbase/couchbase.h") || abort
|
101
|
+
create_header("couchbase_config.h")
|
102
|
+
create_makefile("couchbase_ext")
|
data/lib/couchbase.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Author:: Couchbase <info@couchbase.com>
|
2
|
-
# Copyright:: 2011 Couchbase, Inc.
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
3
|
# License:: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -15,40 +15,30 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
autoload :HttpStatus, 'couchbase/http_status'
|
23
|
-
autoload :Latch, 'couchbase/latch'
|
24
|
-
autoload :Memcached, 'couchbase/memcached'
|
25
|
-
autoload :Node, 'couchbase/node'
|
26
|
-
autoload :RestClient, 'couchbase/rest_client'
|
27
|
-
autoload :VERSION, 'couchbase/version'
|
28
|
-
autoload :View, 'couchbase/view'
|
29
|
-
|
30
|
-
# This error is raising when library detects that some operation
|
31
|
-
# doesn't implemented by the server. For example views API doesn't
|
32
|
-
# implemented by Membase 1.7.x
|
33
|
-
class NotImplemented < Exception; end
|
34
|
-
|
35
|
-
class ViewError < Exception
|
36
|
-
attr_reader :from, :reason
|
18
|
+
require 'couchbase/version'
|
19
|
+
require 'yajl/json_gem'
|
20
|
+
require 'couchbase_ext'
|
21
|
+
require 'couchbase/bucket'
|
37
22
|
|
38
|
-
|
39
|
-
|
40
|
-
@reason = reason
|
41
|
-
super("#{from}: #{reason}")
|
42
|
-
end
|
43
|
-
end
|
23
|
+
# Couchbase ruby client
|
24
|
+
module Couchbase
|
44
25
|
|
45
26
|
class << self
|
46
27
|
# The method +new+ initializes new Bucket instance with all arguments passed.
|
47
28
|
#
|
48
|
-
#
|
49
|
-
# Couchbase.new
|
50
|
-
#
|
51
|
-
#
|
29
|
+
# @example Use default values for all options
|
30
|
+
# Couchbase.new
|
31
|
+
#
|
32
|
+
# @example Establish connection with couchbase default pool and default bucket
|
33
|
+
# Couchbase.new("http://localhost:8091/pools/default")
|
34
|
+
#
|
35
|
+
# @example Select custom bucket
|
36
|
+
# Couchbase.new("http://localhost:8091/pools/default", :bucket => 'blog')
|
37
|
+
#
|
38
|
+
# @example Specify bucket credentials
|
39
|
+
# Couchbase.new("http://localhost:8091/pools/default", :bucket => 'blog', :username => 'bucket', :password => 'secret')
|
40
|
+
#
|
41
|
+
# @return [Bucket] connection instance
|
52
42
|
def new(*args)
|
53
43
|
Bucket.new(*args)
|
54
44
|
end
|
data/lib/couchbase/bucket.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Author:: Couchbase <info@couchbase.com>
|
2
|
-
# Copyright:: 2011 Couchbase, Inc.
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
3
|
# License:: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -15,125 +15,56 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
-
require 'uri'
|
19
|
-
|
20
18
|
module Couchbase
|
21
|
-
|
22
|
-
# This class in charge of all stuff connected to communication with
|
23
|
-
# Couchbase. It includes CouchDB and Memcached APIs. Also it includes
|
24
|
-
# methods for HTTP transport from RestClient.
|
25
|
-
|
26
19
|
class Bucket
|
27
|
-
include RestClient
|
28
|
-
include Couchdb
|
29
|
-
include Memcached
|
30
|
-
|
31
|
-
attr_accessor :pool_uri, :environment, :type, :nodes,
|
32
|
-
:streaming_uri, :name, :uri, :vbuckets
|
33
20
|
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# use when it applicable (for example it skips/preserves design
|
40
|
-
# documents with 'dev_' prefix for CouchDB API). You can specify
|
41
|
-
# any string starting from 'dev' or 'test' to activate development
|
42
|
-
# mode.
|
21
|
+
# Reads a key's value from the server and yields it to a block. Replaces
|
22
|
+
# the key's value with the result of the block as long as the key hasn't
|
23
|
+
# been updated in the meantime, otherwise raises
|
24
|
+
# Couchbase::Error::KeyExists. CAS stands for "compare and swap", and
|
25
|
+
# avoids the need for manual key mutexing. Read more info here:
|
43
26
|
#
|
44
|
-
#
|
45
|
-
# configuration update via +streaming_uri+. Server should push
|
46
|
-
# update notification about adding or removing nodes from cluster.
|
27
|
+
# http://docs.couchbase.org/memcached-api/memcached-api-protocol-text_cas.html
|
47
28
|
#
|
48
|
-
#
|
49
|
-
# pool.
|
50
|
-
def initialize(pool_uri, options = {})
|
51
|
-
@latch = Latch.new(:in_progress, :ready)
|
52
|
-
@name = options[:bucket_name] || "default"
|
53
|
-
@pool_uri = URI.parse(pool_uri)
|
54
|
-
@environment = if options[:environment].to_s =~ /^(dev|test)/
|
55
|
-
:development
|
56
|
-
else
|
57
|
-
:production
|
58
|
-
end
|
59
|
-
config = http_get("#{@pool_uri}/buckets").detect do |bucket|
|
60
|
-
bucket['name'] == @name
|
61
|
-
end
|
62
|
-
unless config
|
63
|
-
raise ArgumentError,
|
64
|
-
"There no such bucket with name '#{@name}' in pool #{pool_uri}"
|
65
|
-
end
|
66
|
-
@uri = @pool_uri.merge(config['uri'])
|
67
|
-
@streaming_uri = @pool_uri.merge(config['streamingUri'])
|
68
|
-
# credentials is used to choose the bucket
|
69
|
-
if @name != "default"
|
70
|
-
@credentials = {:username => @name, :password => options[:bucket_password] || ''}
|
71
|
-
end
|
72
|
-
super
|
73
|
-
|
74
|
-
# Considering all initialization stuff completed and now we can
|
75
|
-
# start config listener
|
76
|
-
listen_for_config_changes
|
77
|
-
|
78
|
-
@latch.wait
|
79
|
-
end
|
80
|
-
|
81
|
-
# Select next node for work with Couchbase. Currently it makes sense
|
82
|
-
# only for couchdb API, because memcached client works using moxi.
|
83
|
-
def next_node
|
84
|
-
nodes.shuffle.first
|
85
|
-
end
|
86
|
-
|
87
|
-
# Perform configuration using configuration cache. It turn all URIs
|
88
|
-
# into full form (with schema, host and port).
|
29
|
+
# @param [String] key
|
89
30
|
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def mk_curl(url)
|
123
|
-
Curl::Easy.new(url) do |curl|
|
124
|
-
curl.useragent = "couchbase-ruby-client/#{Couchbase::VERSION}"
|
125
|
-
if @credentials
|
126
|
-
curl.http_auth_types = :basic
|
127
|
-
curl.username = @credentials[:username]
|
128
|
-
curl.password = @credentials[:password]
|
129
|
-
end
|
130
|
-
curl.verbose = true if Kernel.respond_to?(:debugger)
|
131
|
-
curl.on_body do |data|
|
132
|
-
config = Yajl::Parser.parse(data)
|
133
|
-
setup(config) if config
|
134
|
-
data.bytesize
|
31
|
+
# @param [Hash] options the options for operation
|
32
|
+
# @option options [String] :ttl (self.default_ttl) the time to live of this key
|
33
|
+
# @option options [Symbol] :format (self.default_format) format of the value
|
34
|
+
# @option options [Fixnum] :flags (self.default_flags) flags for this key
|
35
|
+
#
|
36
|
+
# @yieldparam [Object, Result] value old value in synchronous mode and
|
37
|
+
# +Result+ object in asynchronous mode.
|
38
|
+
# @yieldreturn [Object] new value.
|
39
|
+
#
|
40
|
+
# @raise [Couchbase::Errors:KeyExists] if the key was updated before the the
|
41
|
+
# code in block has been completed (the CAS value has been changed).
|
42
|
+
#
|
43
|
+
# @example Implement append to JSON encoded value
|
44
|
+
#
|
45
|
+
# c.default_format = :document
|
46
|
+
# c.set("foo", {"bar" => 1})
|
47
|
+
# c.cas("foo") do |val|
|
48
|
+
# val["baz"] = 2
|
49
|
+
# val
|
50
|
+
# end
|
51
|
+
# c.get("foo") #=> {"bar" => 1, "baz" => 2}
|
52
|
+
#
|
53
|
+
# @return [Fixnum] the CAS of new value
|
54
|
+
def cas(key, options = {})
|
55
|
+
options = options.merge(:extended => true)
|
56
|
+
if async?
|
57
|
+
get(key, options) do |ret|
|
58
|
+
val = yield(ret) # get new value from caller
|
59
|
+
set(ret.key, val, :cas => ret.cas)
|
135
60
|
end
|
61
|
+
else
|
62
|
+
val, flags, ver = get(key, options)
|
63
|
+
val = yield(val) # get new value from caller
|
64
|
+
set(key, val, :cas => ver)
|
136
65
|
end
|
137
66
|
end
|
67
|
+
alias :compare_and_swap :cas
|
68
|
+
|
138
69
|
end
|
139
70
|
end
|
data/lib/couchbase/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Author:: Couchbase <info@couchbase.com>
|
2
|
-
# Copyright:: 2011 Couchbase, Inc.
|
2
|
+
# Copyright:: 2011, 2012 Couchbase, Inc.
|
3
3
|
# License:: Apache License, Version 2.0
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -15,6 +15,7 @@
|
|
15
15
|
# limitations under the License.
|
16
16
|
#
|
17
17
|
|
18
|
+
# Couchbase ruby client
|
18
19
|
module Couchbase
|
19
|
-
VERSION = "0.
|
20
|
+
VERSION = "1.0.0"
|
20
21
|
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
desc 'Run benchmarks and compare them to memcached and dalli gems'
|
2
|
+
task :benchmark => [:clean, :compile] do
|
3
|
+
cd File.expand_path(File.join(__FILE__, '..', '..', 'test', 'profile')) do
|
4
|
+
sh "bundle install && bundle exec ruby benchmark.rb | tee benchmark-#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}.log"
|
5
|
+
end
|
6
|
+
end
|
data/tasks/compile.rake
ADDED
@@ -0,0 +1,52 @@
|
|
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
|
+
gem 'rake-compiler', '>= 0.7.5'
|
19
|
+
require "rake/extensiontask"
|
20
|
+
|
21
|
+
def gemspec
|
22
|
+
@clean_gemspec ||= eval(File.read(File.expand_path('../../couchbase.gemspec', __FILE__)))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Setup compile tasks. Configuration can be passed via ENV.
|
26
|
+
# Example:
|
27
|
+
# rake compile with_libcouchbase_include=/opt/couchbase/include
|
28
|
+
# with_libcouchbase_lib=/opt/couchbase/lib
|
29
|
+
#
|
30
|
+
# or
|
31
|
+
#
|
32
|
+
# rake compile with_libcouchbase_dir=/opt/couchbase
|
33
|
+
#
|
34
|
+
Rake::ExtensionTask.new("couchbase_ext", gemspec) do |ext|
|
35
|
+
CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
|
36
|
+
|
37
|
+
ENV.each do |key, val|
|
38
|
+
next unless key =~ /\Awith_(\w+)\z/i
|
39
|
+
opt = $1.downcase.tr('_', '-')
|
40
|
+
if File.directory?(path = File.expand_path(val))
|
41
|
+
ext.config_options << "--with-#{opt}=#{path}"
|
42
|
+
else
|
43
|
+
warn "No such directory: #{opt}: #{path}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'rubygems/package_task'
|
49
|
+
Gem::PackageTask.new(gemspec) do |pkg|
|
50
|
+
pkg.need_zip = true
|
51
|
+
pkg.need_tar = true
|
52
|
+
end
|
data/tasks/doc.rake
ADDED
@@ -0,0 +1,27 @@
|
|
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/clean'
|
19
|
+
require 'yard'
|
20
|
+
require 'yard/rake/yardoc_task'
|
21
|
+
|
22
|
+
YARD::Rake::YardocTask.new do |t|
|
23
|
+
t.options = %w(--protected --no-private)
|
24
|
+
t.files.push('-', 'README.markdown', 'HISTORY.markdown')
|
25
|
+
end
|
26
|
+
|
27
|
+
#CLOBBER << 'test/CouchbaseMock.jar'
|