couchbase 0.9.8 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/.gitignore +8 -0
  2. data/.yardopts +5 -0
  3. data/HISTORY.markdown +14 -10
  4. data/README.markdown +293 -98
  5. data/Rakefile +19 -24
  6. data/couchbase.gemspec +25 -7
  7. data/ext/couchbase_ext/couchbase_ext.c +2332 -0
  8. data/ext/couchbase_ext/extconf.rb +102 -0
  9. data/lib/couchbase.rb +20 -30
  10. data/lib/couchbase/bucket.rb +43 -112
  11. data/lib/couchbase/version.rb +3 -2
  12. data/tasks/benchmark.rake +6 -0
  13. data/tasks/compile.rake +52 -0
  14. data/tasks/doc.rake +27 -0
  15. data/tasks/test.rake +94 -0
  16. data/tasks/util.rake +21 -0
  17. data/test/profile/.gitignore +1 -0
  18. data/test/profile/Gemfile +6 -0
  19. data/test/profile/benchmark.rb +195 -0
  20. data/test/setup.rb +107 -18
  21. data/test/test_arithmetic.rb +98 -0
  22. data/test/test_async.rb +211 -0
  23. data/test/test_bucket.rb +126 -23
  24. data/test/test_cas.rb +59 -0
  25. data/test/test_couchbase.rb +22 -3
  26. data/test/test_delete.rb +63 -0
  27. data/test/test_errors.rb +82 -0
  28. data/test/test_flush.rb +49 -0
  29. data/test/test_format.rb +98 -0
  30. data/test/test_get.rb +236 -0
  31. data/test/test_stats.rb +53 -0
  32. data/test/test_store.rb +186 -0
  33. data/test/test_touch.rb +57 -0
  34. data/test/test_version.rb +17 -0
  35. metadata +72 -58
  36. data/lib/couchbase/couchdb.rb +0 -107
  37. data/lib/couchbase/document.rb +0 -71
  38. data/lib/couchbase/http_status.rb +0 -118
  39. data/lib/couchbase/latch.rb +0 -71
  40. data/lib/couchbase/memcached.rb +0 -372
  41. data/lib/couchbase/node.rb +0 -49
  42. data/lib/couchbase/rest_client.rb +0 -124
  43. data/lib/couchbase/view.rb +0 -182
  44. data/test/support/buckets-config.json +0 -843
  45. data/test/support/sample_design_doc.json +0 -9
  46. data/test/test_couchdb.rb +0 -98
  47. data/test/test_document.rb +0 -11
  48. data/test/test_latch.rb +0 -88
  49. data/test/test_memcached.rb +0 -59
  50. data/test/test_rest_client.rb +0 -14
  51. data/test/test_view.rb +0 -98
@@ -1,107 +0,0 @@
1
- # Author:: Couchbase <info@couchbase.com>
2
- # Copyright:: 2011 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
- module Couchbase
19
- module Couchdb
20
-
21
- # Initializes CouchDB related part of connection.
22
- #
23
- # @param [ String ] pool_uri Couchbase pool URI.
24
- #
25
- # @param [ Hash ] options Connection options. This is the hash the client
26
- # passed to Couchbase.new to start the session
27
- def initialize(pool_uri, options = {})
28
- super
29
- end
30
-
31
- # Fetch design docs stored in current bucket
32
- #
33
- # @return [ Hash ]
34
- def design_docs
35
- docs = http_get("#{next_node.couch_api_base}/_all_docs",
36
- :params => {:startkey => "_design/", :endkey => "_design0", :include_docs => true})
37
- result = {}
38
- docs['rows'].each do |doc|
39
- doc = Document.wrap(self, doc)
40
- key = doc['_id'].sub(/^_design\//, '')
41
- next if @environment == :production && key =~ /dev_/
42
- result[key] = doc
43
- end
44
- result
45
- end
46
-
47
- # Update or create design doc with supplied views
48
- #
49
- # @param [ Hash, IO, String ] data The source object containing JSON
50
- # encoded design document. It must have
51
- # <tt>_id</tt> key set, this key should
52
- # start with <tt>_design/</tt>.
53
- #
54
- # @return [ Couchbase::Document ] instance
55
- def save_design_doc(data)
56
- doc = parse_design_document(data)
57
- rv = http_put("#{next_node.couch_api_base}/#{doc['_id']}", {}, doc)
58
- doc['_rev'] = rv['rev']
59
- doc
60
- end
61
-
62
- # Fetch all documents from the bucket.
63
- #
64
- # @param [ Hash ] params Params for CouchDB <tt>/_all_docs</tt> query
65
- #
66
- # @return [ Couchbase::View ] View object
67
- def all_docs(params = {})
68
- View.new(self, "#{next_node.couch_api_base}/_all_docs", params)
69
- end
70
-
71
- # Delete design doc with given id and revision.
72
- #
73
- # @param [ String ] id Design document id. It might have '_design/'
74
- # prefix.
75
- #
76
- # @param [ String ] rev Document revision. It uses latest revision if
77
- # <tt>rev</tt> parameter is nil.
78
- #
79
- def delete_design_doc(id, rev = nil)
80
- ddoc = design_docs[id.sub(/^_design\//, '')]
81
- return nil unless ddoc
82
- http_delete("#{next_node.couch_api_base}/#{ddoc['_id']}",
83
- :params => {:rev => rev || ddoc['_rev']})
84
- end
85
-
86
- protected
87
-
88
- def parse_design_document(doc)
89
- data = case doc
90
- when String
91
- Yajl::Parser.parse(doc)
92
- when IO
93
- Yajl::Parser.parse(doc.read)
94
- when Hash
95
- doc
96
- else
97
- raise ArgumentError, "Document should be Hash, String or IO instance"
98
- end
99
-
100
- if data['_id'].to_s !~ /^_design\//
101
- raise ArgumentError, "'_id' key must be set and start with '_design/'."
102
- end
103
- data['language'] ||= 'javascript'
104
- Document.wrap(self, data)
105
- end
106
- end
107
- end
@@ -1,71 +0,0 @@
1
- # Author:: Couchbase <info@couchbase.com>
2
- # Copyright:: 2011 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
- module Couchbase
19
- class Document
20
- # Undefine as much methods as we can to free names for views
21
- instance_methods.each do |m|
22
- undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$|^class$|)/
23
- end
24
-
25
- attr_accessor :data, :views
26
-
27
- def initialize(connection, data)
28
- @data = data
29
- @connection = connection
30
- @views = []
31
- begin
32
- if design_doc?
33
- data['views'].each do |name, funs|
34
- @views << name
35
- self.instance_eval <<-EOV, __FILE__, __LINE__ + 1
36
- def #{name}(params = {})
37
- endpoint = "\#{@connection.next_node.couch_api_base}/\#{@data['_id']}/_view/#{name}"
38
- View.new(@connection, endpoint, params)
39
- end
40
- EOV
41
- end
42
- end
43
- rescue NoMethodError
44
- end
45
- end
46
-
47
- def self.wrap(connection, data)
48
- Document.new(connection, data['doc'] || data)
49
- end
50
-
51
- def [](key)
52
- @data[key]
53
- end
54
-
55
- def []=(key, value)
56
- @data[key] = value
57
- end
58
-
59
- def design_doc?
60
- !!(@data['_id'] =~ %r(_design/))
61
- end
62
-
63
- def has_views?
64
- !!(design_doc? && !@views.empty?)
65
- end
66
-
67
- def inspect
68
- %(#<#{self.class.name}:#{self.object_id} #{@data.inspect}>)
69
- end
70
- end
71
- end
@@ -1,118 +0,0 @@
1
- # Author:: Couchbase <info@couchbase.com>
2
- # Copyright:: 2011 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
- module Couchbase
19
-
20
- # This module contains definitions for exceptions which wrap HTTP
21
- # errors. Also it collect them in useful structure
22
- # +HttpStatus::Errors+ which is map with status code as a key and
23
- # exception class as a value. See the usage example below.
24
- #
25
- # === Example
26
- #
27
- # data = Yajl::Parser.parse(curl.body_str)
28
- # if error_class = HttpStatus::Errors[curl.response_code]
29
- # raise error_class.new(data['error'], data['reason'])
30
- # end
31
- #
32
-
33
- module HttpStatus
34
-
35
- # Base class for all HTTP error codes. It povides handy methods for
36
- # investigating what happened. For example, it stores +status_code+
37
- # and human readable +status_message+ automatically and allows to
38
- # provide context specific code and message (+error+ and +reason+
39
- # correspondingly)
40
-
41
- class Status < Exception
42
- class << self
43
- attr_accessor :status_code, :status_message
44
- alias_method :to_i, :status_code
45
-
46
- def status_line
47
- "#{status_code} #{status_message}"
48
- end
49
- end
50
-
51
- attr_reader :error, :reason
52
- def initialize(error, reason)
53
- @error = error
54
- @reason = reason
55
- super("#{error}: #{reason}")
56
- end
57
-
58
- def status_code
59
- self.class.status_code
60
- end
61
-
62
- def status_message
63
- self.class.status_message
64
- end
65
-
66
- def status_line
67
- self.class.status_line
68
- end
69
-
70
- def to_i
71
- self.class.to_i
72
- end
73
- end
74
-
75
- StatusMessage = {
76
- 400 => 'Bad Request',
77
- 401 => 'Unauthorized',
78
- 402 => 'Payment Required',
79
- 403 => 'Forbidden',
80
- 404 => 'Not Found',
81
- 405 => 'Method Not Allowed',
82
- 406 => 'Not Acceptable',
83
- 407 => 'Proxy Authentication Required',
84
- 408 => 'Request Timeout',
85
- 409 => 'Conflict',
86
- 410 => 'Gone',
87
- 411 => 'Length Required',
88
- 412 => 'Precondition Failed',
89
- 413 => 'Request Entity Too Large',
90
- 414 => 'Request-URI Too Large',
91
- 415 => 'Unsupported Media Type',
92
- 416 => 'Request Range Not Satisfiable',
93
- 417 => 'Expectation Failed',
94
- 422 => 'Unprocessable Entity',
95
- 423 => 'Locked',
96
- 424 => 'Failed Dependency',
97
- 500 => 'Internal Server Error',
98
- 501 => 'Not Implemented',
99
- 502 => 'Bad Gateway',
100
- 503 => 'Service Unavailable',
101
- 504 => 'Gateway Timeout',
102
- 505 => 'HTTP Version Not Supported',
103
- 507 => 'Insufficient Storage'
104
- }
105
-
106
- # Hash with error code as a key and exceptin class as a value
107
- Errors = {}
108
-
109
- StatusMessage.each do |status_code, status_message|
110
- klass = Class.new(Status)
111
- klass.status_code = status_code
112
- klass.status_message = status_message
113
- klass_name = status_message.gsub(/[ \-]/,'')
114
- const_set(klass_name, klass)
115
- HttpStatus::Errors[status_code] = const_get(klass_name)
116
- end
117
- end
118
- end
@@ -1,71 +0,0 @@
1
- # Author:: Couchbase <info@couchbase.com>
2
- # Copyright:: 2011 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 'thread'
19
-
20
- module Couchbase
21
- class Latch
22
- attr_reader :state, :target
23
-
24
- # Takes initial pair of possible states and set latch in the first.
25
- #
26
- # @example Read an attribute.
27
- # Latch.new(false, true)
28
- # Latch.new(:closed, :opened)
29
- #
30
- # @param [ Object ] from Initial state
31
- #
32
- # @param [ Object ] to Target state
33
- def initialize(from, to)
34
- @state = from
35
- @target = to
36
- @lock = Mutex.new
37
- @condition = ConditionVariable.new
38
- end
39
-
40
-
41
- # Turn latch to target state.
42
- #
43
- # @example
44
- # l = Latch.new(:opened, :closed)
45
- # l.state #=> :opened
46
- # l.toggle #=> :closed
47
- #
48
- # @return [ Object ] Target state
49
- def toggle
50
- @lock.synchronize do
51
- @state = @target
52
- @condition.broadcast
53
- end
54
- @state
55
- end
56
-
57
- # Perform blocking wait operation until state will be toggled.
58
- #
59
- # @example
60
- # l = Latch.new(:opened, :closed)
61
- # l.wait #=> :closed
62
- #
63
- # @return [ Object ] Target state
64
- def wait
65
- @lock.synchronize do
66
- @condition.wait(@lock) while @state != @target
67
- end
68
- @state
69
- end
70
- end
71
- end
@@ -1,372 +0,0 @@
1
- # Author:: Couchbase <info@couchbase.com>
2
- # Copyright:: 2011 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 'memcached'
19
-
20
- module Couchbase
21
-
22
- # This module is included in the Couchbase::Connection and provides
23
- # routines for Memcached API
24
-
25
- module Memcached
26
-
27
- attr_reader :memcached, :default_format, :default_flags, :default_ttl
28
-
29
- # Initializes Memcached API. It builds a server list using moxi ports.
30
- #
31
- # @param [Hash] options The options for module
32
- # @option options [Symbol] :format format of the values. It can be on of
33
- # the <tt>[:plain, :document, :marshal]</tt>. You can choose
34
- # <tt>:plain</tt> if you no need any conversions to be applied to your
35
- # data, but your data should be passed as String. Choose
36
- # <tt>:document</tt> (default) format when you'll store hashes and plan
37
- # to execute CouchDB views with map/reduce operations on them. And
38
- # finally use <tt>:marshal</tt> format if you'd like to transparently
39
- # serialize almost any ruby object with standard <tt>Marshal.dump</tt>
40
- # and <tt>Marhal.load</tt> methods.
41
- def initialize(pool_uri, options = {})
42
- @default_format = options[:format] || :document
43
- @default_flags = ::Memcached::FLAGS
44
- @options = {
45
- :binary_protocol => true,
46
- :support_cas => true,
47
- :default_ttl => 0
48
- }.merge(options || {})
49
- @options[:experimental_features] = true
50
- if @credentials
51
- @options[:credentials] = [@credentials[:username], @credentials[:password]]
52
- end
53
- super
54
- end
55
-
56
- # Returns effective options from Memcached instance
57
- #
58
- # @return [Hash]
59
- def options
60
- @memcached.options
61
- end
62
-
63
- # Return the array of server strings used to configure this instance.
64
- #
65
- # @return [Array]
66
- def servers
67
- @memcached.servers
68
- end
69
-
70
- # Set the prefix key.
71
- #
72
- # @param [String] prefix the string to prepend before each key.
73
- def prefix_key=(prefix)
74
- @memcached.prefix_key(prefix)
75
- end
76
- alias :namespace= :prefix_key=
77
-
78
- # Return the current prefix key.
79
- #
80
- # @return [String]
81
- def prefix_key
82
- @memcached.prefix_key
83
- end
84
- alias :namespace :prefix_key
85
-
86
- # Return a hash of statistics responses from the set of servers. Each
87
- # value is an array with one entry for each server, in the same order the
88
- # servers were defined.
89
- #
90
- # @param [String] key The name of the statistical item. When key is nil,
91
- # the server will return all set of statistics information.
92
- #
93
- # @return [Hash]
94
- def stats(key = nil)
95
- @memcached.stats(key)
96
- end
97
-
98
- # Flushes all key/value pairs from all the servers.
99
- def flush
100
- @memcached.flush
101
- end
102
-
103
- # Gets a key's value from the server. It will use <tt>multiget</tt>
104
- # behaviour if you pass Array of keys, which is much faster than normal
105
- # mode.
106
- #
107
- # @overload get(key, options = {})
108
- # Get single key.
109
- #
110
- # @param [String] key
111
- # @param [Hash] options the options for operation
112
- # @option options [Symbol] :format (self.default_format) format of the value
113
- # @return [Object] the value is associated with the key
114
- # @raise [Memcached::NotFound] if the key does not exist on the server.
115
- #
116
- # @overload get(*keys, options = {})
117
- # Get multiple keys aka multiget (mget).
118
- #
119
- # @param [Array] keys the list of keys
120
- # @param [Hash] options the options for operation
121
- # @option options [Symbol] :format (self.default_format) format of the value
122
- # @return [Hash] result map, where keys are keys which were requested
123
- # and values are the values from the storage. Result will contain only
124
- # existing keys and in this case no exception will be raised.
125
- def get(*args)
126
- options = args.last.is_a?(Hash) ? args.pop : {}
127
- raise ArgumentError, "You must provide at least one key" if args.empty?
128
- keys = args.length == 1 ? args.pop : args
129
- format = options[:format] || @default_format
130
- rv = @memcached.get(keys, format == :marshal)
131
- if keys.is_a?(Array)
132
- rv.keys.each do |key|
133
- rv[key] = decode(rv[key], format)
134
- end
135
- rv
136
- else
137
- decode(rv, format)
138
- end
139
- end
140
-
141
- # Shortcut to <tt>#get</tt> operation. Gets a key's value from the server
142
- # with default options. (@see #get method for additional info)
143
- #
144
- # @param [Array, String] keys list of String keys or single key
145
- #
146
- # @raise [Memcached::NotFound] if the key does not exist on the server.
147
- def [](keys)
148
- decode(@memcached.get(keys, @default_format == :marshal), @default_format)
149
- end
150
-
151
- # Set new expiration time for existing item. The <tt>ttl</tt> parameter
152
- # will use <tt>#default_ttl</tt> value if it is nil.
153
- #
154
- # @param [String] key
155
- #
156
- # @param [Fixnum] ttl
157
- def touch(key, ttl = @default_ttl)
158
- @memcached.touch(key, ttl)
159
- end
160
-
161
- # Set a key/value pair. Overwrites any existing value on the server.
162
- #
163
- # @param [String] key
164
- #
165
- # @param [Object] value
166
- #
167
- # @param [Hash] options the options for operation
168
- # @option options [String] :ttl (self.default_ttl) the time to live of this key
169
- # @option options [Symbol] :format (self.default_format) format of the value
170
- # @option options [Fixnum] :flags (self.default_flags) flags for this key
171
- def set(key, value, options = {})
172
- ttl = options[:ttl] || @default_ttl
173
- format = options[:format] || @default_format
174
- flags = options[:flags] || @default_flags
175
- @memcached.set(key, encode(value, format), ttl, format == :marshal, flags)
176
- end
177
-
178
- # Shortcut to <tt>#set</tt> operation. Sets key to given value using
179
- # default options.
180
- #
181
- # @param [String] key
182
- #
183
- # @param [Object] value
184
- def []=(key, value)
185
- @memcached.set(key, encode(value, @default_format),
186
- @default_ttl, @default_format == :marshal, @default_flags)
187
- end
188
-
189
- # Reads a key's value from the server and yields it to a block. Replaces
190
- # the key's value with the result of the block as long as the key hasn't
191
- # been updated in the meantime, otherwise raises
192
- # <b>Memcached::NotStored</b>. CAS stands for "compare and swap", and
193
- # avoids the need for manual key mutexing. Read more info here:
194
- #
195
- # http://docs.couchbase.org/memcached-api/memcached-api-protocol-text.html#memcached-api-protocol-text_cas
196
- #
197
- # @param [String] key
198
- #
199
- # @param [Hash] options the options for operation
200
- # @option options [String] :ttl (self.default_ttl) the time to live of this key
201
- # @option options [Symbol] :format (self.default_format) format of the value
202
- # @option options [Fixnum] :flags (self.default_flags) flags for this key
203
- #
204
- # @yieldparam [Object] value old value.
205
- # @yieldreturn [Object] new value.
206
- #
207
- # @raise [Memcached::ClientError] if CAS doesn't enabled for current
208
- # connection. (:support_cas is true by default)
209
- # @raise [Memcached::NotStored] if the key was updated before the the
210
- # code in block has been completed (the CAS value has been changed).
211
- #
212
- # @example Implement append to JSON encoded value
213
- #
214
- # c.default_format #=> :json
215
- # c.set("foo", {"bar" => 1})
216
- # c.cas("foo") do |val|
217
- # val["baz"] = 2
218
- # val
219
- # end
220
- # c.get("foo") #=> {"bar" => 1, "baz" => 2}
221
- #
222
- def cas(key, options = {}, &block)
223
- ttl = options[:ttl] || @default_ttl
224
- format = options[:format] || @default_format
225
- flags = options[:flags] || @default_flags
226
- @memcached.cas(key, ttl, format == :marshal, flags) do |value|
227
- value = decode(value, format)
228
- encode(block.call(value), format)
229
- end
230
- end
231
- alias :compare_and_swap :cas
232
-
233
- # Add a key/value pair.
234
- #
235
- # @param [String] key
236
- #
237
- # @param [Object] value
238
- #
239
- # @param [Hash] options the options for operation
240
- # @option options [String] :ttl (self.default_ttl) the time to live of this key
241
- # @option options [Symbol] :format (self.default_format) format of the value
242
- # @option options [Fixnum] :flags (self.default_flags) flags for this key
243
- #
244
- # @raise [Memcached::NotStored] if the key already exists on the server.
245
- def add(key, value, options = {})
246
- ttl = options[:ttl] || @default_ttl
247
- format = options[:format] || @default_format
248
- flags = options[:flags] || @default_flags
249
- @memcached.add(key, encode(value, format), ttl, format == :marshal, flags)
250
- end
251
-
252
-
253
- # Replace a key/value pair.
254
- #
255
- # @param [String] key
256
- #
257
- # @param [Object] value
258
- #
259
- # @param [Hash] options the options for operation
260
- # @option options [String] :ttl (self.default_ttl) the time to live of this key
261
- # @option options [Symbol] :format (self.default_format) format of the value
262
- # @option options [Fixnum] :flags (self.default_flags) flags for this key
263
- #
264
- # @raise [Memcached::NotFound] if the key doesn't exists on the server.
265
- def replace(key, value, options = {})
266
- ttl = options[:ttl] || @default_ttl
267
- format = options[:format] || @default_format
268
- flags = options[:flags] || @default_flags
269
- @memcached.replace(key, encode(value, format), ttl, format == :marshal, flags)
270
- end
271
-
272
- # Appends a string to a key's value. Make sense for <tt>:plain</tt>
273
- # format, because server doesn't make assumptions about value structure
274
- # here.
275
- #
276
- # @param [String] key
277
- #
278
- # @param [Object] value
279
- #
280
- # @raise [Memcached::NotFound] if the key doesn't exists on the server.
281
- def append(key, value)
282
- @memcached.append(key, value)
283
- end
284
-
285
-
286
- # Prepends a string to a key's value. Make sense for <tt>:plain</tt>
287
- # format, because server doesn't make assumptions about value structure
288
- # here.
289
- #
290
- # @param [String] key
291
- #
292
- # @param [Object] value
293
- #
294
- # @raise [Memcached::NotFound] if the key doesn't exists on the server.
295
- def prepend(key, value)
296
- @memcached.prepend(key, value)
297
- end
298
-
299
- # Deletes a key/value pair from the server.
300
- #
301
- # @param [String] key
302
- #
303
- # @raise [Memcached::NotFound] if the key doesn't exists on the server.
304
- def delete(key)
305
- @memcached.delete(key)
306
- end
307
-
308
- # Increment a key's value. The key must be initialized to a plain integer
309
- # first via <tt>#set</tt>, <tt>#add</tt>, or <tt>#replace</tt> with
310
- # <tt>:format</tt> set to <tt>:plain</tt>.
311
- #
312
- # @param [String] key
313
- #
314
- # @param [Fixnum] offset the value to add
315
- def increment(key, offset = 1)
316
- @memcached.increment(key, offset)
317
- end
318
- alias :incr :increment
319
-
320
- # Decrement a key's value. The key must be initialized to a plain integer
321
- # first via <tt>#set</tt>, <tt>#add</tt>, or <tt>#replace</tt> with
322
- # <tt>:format</tt> set to <tt>:plain</tt>.
323
- #
324
- # @param [String] key
325
- #
326
- # @param [Fixnum] offset the value to substract
327
- def decrement(key, offset = 1)
328
- @memcached.decrement(key, offset)
329
- end
330
- alias :decr :decrement
331
-
332
- # Safely copy this instance.
333
- #
334
- # <tt>clone</tt> is useful for threading, since each thread must have its own unshared object.
335
- def clone
336
- double = super
337
- double.instance_variable_set("@memcached", @memcached.clone)
338
- double
339
- end
340
- alias :dup :clone #:nodoc:
341
-
342
- private
343
-
344
- # Setups memcached instance. Used for dynamic client reconfiguration
345
- # when server pushes new config.
346
- def setup(not_used)
347
- servers = nodes.map do |n|
348
- "#{n.hostname}:#{n.ports['proxy']}" if n.healthy?
349
- end.compact
350
- @memcached = ::Memcached.new(servers, @options)
351
- @default_ttl = @memcached.options[:default_ttl]
352
- end
353
-
354
- def encode(value, mode)
355
- case mode
356
- when :document
357
- Yajl::Encoder.encode(value)
358
- when :marshal, :plain
359
- value # encoding handled by memcached library internals
360
- end
361
- end
362
-
363
- def decode(value, mode)
364
- case mode
365
- when :document
366
- Yajl::Parser.parse(value)
367
- when :marshal, :plain
368
- value # encoding handled by memcached library internals
369
- end
370
- end
371
- end
372
- end