couchbase 1.3.4-x64-mingw32

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +22 -0
  4. data/.yardopts +5 -0
  5. data/CONTRIBUTING.markdown +75 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +201 -0
  8. data/Makefile +3 -0
  9. data/README.markdown +649 -0
  10. data/RELEASE_NOTES.markdown +796 -0
  11. data/Rakefile +20 -0
  12. data/couchbase.gemspec +49 -0
  13. data/examples/chat-em/Gemfile +7 -0
  14. data/examples/chat-em/README.markdown +45 -0
  15. data/examples/chat-em/server.rb +82 -0
  16. data/examples/chat-goliath-grape/Gemfile +5 -0
  17. data/examples/chat-goliath-grape/README.markdown +50 -0
  18. data/examples/chat-goliath-grape/app.rb +67 -0
  19. data/examples/chat-goliath-grape/config/app.rb +20 -0
  20. data/examples/transcoders/Gemfile +3 -0
  21. data/examples/transcoders/README.markdown +59 -0
  22. data/examples/transcoders/cb-zcat +40 -0
  23. data/examples/transcoders/cb-zcp +45 -0
  24. data/examples/transcoders/gzip_transcoder.rb +49 -0
  25. data/examples/transcoders/options.rb +54 -0
  26. data/ext/couchbase_ext/.gitignore +4 -0
  27. data/ext/couchbase_ext/arguments.c +956 -0
  28. data/ext/couchbase_ext/arithmetic.c +307 -0
  29. data/ext/couchbase_ext/bucket.c +1370 -0
  30. data/ext/couchbase_ext/context.c +65 -0
  31. data/ext/couchbase_ext/couchbase_ext.c +1364 -0
  32. data/ext/couchbase_ext/couchbase_ext.h +644 -0
  33. data/ext/couchbase_ext/delete.c +163 -0
  34. data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
  35. data/ext/couchbase_ext/extconf.rb +168 -0
  36. data/ext/couchbase_ext/get.c +316 -0
  37. data/ext/couchbase_ext/gethrtime.c +129 -0
  38. data/ext/couchbase_ext/http.c +432 -0
  39. data/ext/couchbase_ext/multithread_plugin.c +1090 -0
  40. data/ext/couchbase_ext/observe.c +171 -0
  41. data/ext/couchbase_ext/plugin_common.c +171 -0
  42. data/ext/couchbase_ext/result.c +129 -0
  43. data/ext/couchbase_ext/stats.c +163 -0
  44. data/ext/couchbase_ext/store.c +542 -0
  45. data/ext/couchbase_ext/timer.c +192 -0
  46. data/ext/couchbase_ext/touch.c +186 -0
  47. data/ext/couchbase_ext/unlock.c +176 -0
  48. data/ext/couchbase_ext/utils.c +551 -0
  49. data/ext/couchbase_ext/version.c +142 -0
  50. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  51. data/lib/active_support/cache/couchbase_store.rb +430 -0
  52. data/lib/couchbase.rb +155 -0
  53. data/lib/couchbase/bucket.rb +457 -0
  54. data/lib/couchbase/cluster.rb +119 -0
  55. data/lib/couchbase/connection_pool.rb +58 -0
  56. data/lib/couchbase/constants.rb +12 -0
  57. data/lib/couchbase/result.rb +26 -0
  58. data/lib/couchbase/transcoder.rb +120 -0
  59. data/lib/couchbase/utils.rb +62 -0
  60. data/lib/couchbase/version.rb +21 -0
  61. data/lib/couchbase/view.rb +506 -0
  62. data/lib/couchbase/view_row.rb +272 -0
  63. data/lib/ext/multi_json_fix.rb +56 -0
  64. data/lib/rack/session/couchbase.rb +108 -0
  65. data/tasks/benchmark.rake +6 -0
  66. data/tasks/compile.rake +158 -0
  67. data/tasks/test.rake +100 -0
  68. data/tasks/util.rake +21 -0
  69. data/test/profile/.gitignore +1 -0
  70. data/test/profile/Gemfile +6 -0
  71. data/test/profile/benchmark.rb +195 -0
  72. data/test/setup.rb +178 -0
  73. data/test/test_arithmetic.rb +185 -0
  74. data/test/test_async.rb +316 -0
  75. data/test/test_bucket.rb +250 -0
  76. data/test/test_cas.rb +235 -0
  77. data/test/test_couchbase.rb +77 -0
  78. data/test/test_couchbase_connection_pool.rb +77 -0
  79. data/test/test_couchbase_rails_cache_store.rb +361 -0
  80. data/test/test_delete.rb +120 -0
  81. data/test/test_errors.rb +82 -0
  82. data/test/test_eventmachine.rb +70 -0
  83. data/test/test_format.rb +164 -0
  84. data/test/test_get.rb +407 -0
  85. data/test/test_stats.rb +57 -0
  86. data/test/test_store.rb +216 -0
  87. data/test/test_timer.rb +42 -0
  88. data/test/test_touch.rb +97 -0
  89. data/test/test_unlock.rb +119 -0
  90. data/test/test_utils.rb +58 -0
  91. data/test/test_version.rb +52 -0
  92. metadata +336 -0
@@ -0,0 +1,142 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2011, 2012 Couchbase, Inc.
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
+ #include "couchbase_ext.h"
19
+
20
+ void
21
+ cb_version_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_server_version_resp_t *resp)
22
+ {
23
+ struct cb_context_st *ctx = (struct cb_context_st *)cookie;
24
+ struct cb_bucket_st *bucket = ctx->bucket;
25
+ VALUE node, val, exc, res;
26
+
27
+ node = resp->v.v0.server_endpoint ? STR_NEW_CSTR(resp->v.v0.server_endpoint) : Qnil;
28
+ exc = cb_check_error(error, "failed to get version", node);
29
+ if (exc != Qnil) {
30
+ rb_ivar_set(exc, cb_id_iv_operation, cb_sym_version);
31
+ ctx->exception = exc;
32
+ }
33
+
34
+ if (node != Qnil) {
35
+ val = STR_NEW((const char*)resp->v.v0.vstring, resp->v.v0.nvstring);
36
+ if (bucket->async) { /* asynchronous */
37
+ if (ctx->proc != Qnil) {
38
+ res = rb_class_new_instance(0, NULL, cb_cResult);
39
+ rb_ivar_set(res, cb_id_iv_error, exc);
40
+ rb_ivar_set(res, cb_id_iv_operation, cb_sym_version);
41
+ rb_ivar_set(res, cb_id_iv_node, node);
42
+ rb_ivar_set(res, cb_id_iv_value, val);
43
+ cb_proc_call(bucket, ctx->proc, 1, res);
44
+ }
45
+ } else { /* synchronous */
46
+ if (NIL_P(exc)) {
47
+ rb_hash_aset(ctx->rv, node, val);
48
+ }
49
+ }
50
+ } else {
51
+ ctx->nqueries--;
52
+ ctx->proc = Qnil;
53
+ if (bucket->async) {
54
+ cb_context_free(ctx);
55
+ }
56
+ }
57
+
58
+ (void)handle;
59
+ }
60
+
61
+ /*
62
+ * Returns versions of the server for each node in the cluster
63
+ *
64
+ * @since 1.1.0
65
+ *
66
+ * @overload version
67
+ * @yieldparam [Result] ret the object with +error+, +node+, +operation+
68
+ * and +value+ attributes.
69
+ *
70
+ * @return [Hash] node-version pairs
71
+ *
72
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
73
+ * @raise [ArgumentError] when passing the block in synchronous mode
74
+ *
75
+ * @example Synchronous version request
76
+ * c.version #=> will render version
77
+ *
78
+ * @example Asynchronous version request
79
+ * c.run do
80
+ * c.version do |ret|
81
+ * ret.operation #=> :version
82
+ * ret.success? #=> true
83
+ * ret.node #=> "localhost:11211"
84
+ * ret.value #=> will render version
85
+ * end
86
+ * end
87
+ */
88
+ VALUE
89
+ cb_bucket_version(int argc, VALUE *argv, VALUE self)
90
+ {
91
+ struct cb_bucket_st *bucket = DATA_PTR(self);
92
+ struct cb_context_st *ctx;
93
+ VALUE rv, exc, proc;
94
+ lcb_error_t err;
95
+ struct cb_params_st params;
96
+
97
+ if (!cb_bucket_connected_bang(bucket, cb_sym_version)) {
98
+ return Qnil;
99
+ }
100
+
101
+ memset(&params, 0, sizeof(struct cb_params_st));
102
+ rb_scan_args(argc, argv, "0*&", &params.args, &proc);
103
+ if (!bucket->async && proc != Qnil) {
104
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
105
+ }
106
+ params.type = cb_cmd_version;
107
+ params.bucket = bucket;
108
+ cb_params_build(&params);
109
+ ctx = cb_context_alloc_common(bucket, proc, params.cmd.version.num);
110
+ err = lcb_server_versions(bucket->handle, (const void *)ctx,
111
+ params.cmd.version.num, params.cmd.version.ptr);
112
+ exc = cb_check_error(err, "failed to schedule version request", Qnil);
113
+ cb_params_destroy(&params);
114
+ if (exc != Qnil) {
115
+ cb_context_free(ctx);
116
+ rb_exc_raise(exc);
117
+ }
118
+ bucket->nbytes += params.npayload;
119
+ if (bucket->async) {
120
+ cb_maybe_do_loop(bucket);
121
+ return Qnil;
122
+ } else {
123
+ if (ctx->nqueries > 0) {
124
+ /* we have some operations pending */
125
+ lcb_wait(bucket->handle);
126
+ }
127
+ exc = ctx->exception;
128
+ rv = ctx->rv;
129
+ cb_context_free(ctx);
130
+ if (exc != Qnil) {
131
+ rb_exc_raise(exc);
132
+ }
133
+ exc = bucket->exception;
134
+ if (exc != Qnil) {
135
+ bucket->exception = Qnil;
136
+ rb_exc_raise(exc);
137
+ }
138
+ return rv;
139
+ }
140
+ }
141
+
142
+
@@ -0,0 +1,38 @@
1
+ require 'active_support/cache'
2
+ require 'action_dispatch/middleware/session/abstract_store'
3
+ require 'rack/session/couchbase'
4
+ require 'couchbase'
5
+
6
+ module ActionDispatch
7
+ module Session
8
+
9
+ # This is Couchbase-powered session store for Rails applications
10
+ #
11
+ # To use it just update your `config/initializers/session_store.rb` file
12
+ #
13
+ # require 'action_dispatch/middleware/session/couchbase_store'
14
+ # AppName::Application.config.session_store :couchbase_store
15
+ #
16
+ # Or remove this file and add following line to your `config/application.rb`:
17
+ #
18
+ # require 'action_dispatch/middleware/session/couchbase_store'
19
+ # config.session_store :couchbase_store
20
+ #
21
+ # You can also pass additional options:
22
+ #
23
+ # require 'action_dispatch/middleware/session/couchbase_store'
24
+ # session_options = {
25
+ # :expire_after => 5.minutes,
26
+ # :couchbase => {:bucket => "sessions", :default_format => :marshal}
27
+ # }
28
+ # config.session_store :couchbase_store, session_options
29
+ #
30
+ # By default sessions will be serialized to JSON, to allow analyse them
31
+ # using Map/Reduce.
32
+ #
33
+ class CouchbaseStore < Rack::Session::Couchbase
34
+ include Compatibility
35
+ include StaleSessionCheck
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,430 @@
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 'couchbase'
19
+ require 'securerandom'
20
+ require 'active_support/core_ext/array/extract_options'
21
+ require 'active_support/cache'
22
+ require 'monitor'
23
+
24
+ module ActiveSupport
25
+ module Cache
26
+ # This class implements Cache interface for Rails. To use it just
27
+ # put following line in your config/application.rb file:
28
+ #
29
+ # config.cache_store = :couchbase_store
30
+ #
31
+ # You can also pass additional connection options there
32
+ #
33
+ # cache_options = {
34
+ # :bucket => 'protected',
35
+ # :username => 'protected',
36
+ # :password => 'secret',
37
+ # :expires_in => 30.seconds
38
+ # }
39
+ # config.cache_store = :couchbase_store, cache_options
40
+ class CouchbaseStore < Store
41
+
42
+ # Creates a new CouchbaseStore object, with the given options. For
43
+ # more info see {{Couchbase::Bucket#initialize}}
44
+ #
45
+ # ActiveSupport::Cache::CouchbaseStore.new(:bucket => "cache")
46
+ #
47
+ # If no options are specified, then CouchbaseStore will connect to
48
+ # localhost port 8091 (default Couchbase Server port) and will use
49
+ # bucket named "default" which is always open for unauthorized access
50
+ # (if exists).
51
+ def initialize(*args)
52
+ args = [*(args.flatten)]
53
+ options = args.extract_options! || {}
54
+ @raise_errors = !options[:quiet] = !options.delete(:raise_errors)
55
+ options[:default_ttl] ||= options.delete(:expires_in)
56
+ options[:default_format] ||= :marshal
57
+ options[:key_prefix] ||= options.delete(:namespace)
58
+ @key_prefix = options[:key_prefix]
59
+ options[:connection_pool] ||= options.delete(:connection_pool)
60
+ args.push(options)
61
+
62
+ if options[:connection_pool]
63
+ if RUBY_VERSION.to_f < 1.9
64
+ warn "connection_pool gem doesn't support ruby < 1.9"
65
+ else
66
+ @data = ::Couchbase::ConnectionPool.new(options[:connection_pool], *args)
67
+ end
68
+ end
69
+ unless @data
70
+ @data = ::Couchbase::Bucket.new(*args)
71
+ @data.extend(Threadsafe)
72
+ end
73
+ end
74
+
75
+ # Fetches data from the cache, using the given key.
76
+ #
77
+ # @since 1.2.0.dp5
78
+ #
79
+ # If there is data in the cache with the given key, then that data is
80
+ # returned. If there is no such data in the cache (a cache miss),
81
+ # then nil will be returned. However, if a block has been passed, that
82
+ # block will be run in the event of a cache miss. The return value of
83
+ # the block will be written to the cache under the given cache key,
84
+ # and that return value will be returned.
85
+ #
86
+ # @param [String] name name for the key
87
+ # @param [Hash] options
88
+ # @option options [true, false] :force if this option is +true+ it
89
+ # will force cache miss.
90
+ # @option options [Fixnum] :expires_in the expiration time on the
91
+ # cache in seconds. Values larger than 30*24*60*60 seconds (30 days)
92
+ # are interpreted as absolute times (from the epoch).
93
+ # @option options [true, false] :unless_exists if this option is +true+
94
+ # it will write value only if the key doesn't exist in the database
95
+ # (it accepts +:unless_exist+ too).
96
+ #
97
+ # @return [Object]
98
+ def fetch(name, options = nil)
99
+ options ||= {}
100
+ name = expanded_key(name)
101
+
102
+ if block_given?
103
+ unless options[:force]
104
+ entry = instrument(:read, name, options) do |payload|
105
+ payload[:super_operation] = :fetch if payload
106
+ read_entry(name, options)
107
+ end
108
+ end
109
+
110
+ if !entry.nil?
111
+ instrument(:fetch_hit, name, options) { |payload| }
112
+ entry
113
+ else
114
+ result = instrument(:generate, name, options) do |payload|
115
+ yield
116
+ end
117
+ write(name, result, options)
118
+ result
119
+ end
120
+ else
121
+ read(name, options)
122
+ end
123
+ end
124
+
125
+ # Writes the value to the cache, with the key
126
+ #
127
+ # @since 1.2.0.dp5
128
+ #
129
+ # @param [String] name name for the key
130
+ # @param [Object] value value of the key
131
+ # @param [Hash] options
132
+ # @option options [Fixnum] :expires_in the expiration time on the
133
+ # cache in seconds. Values larger than 30*24*60*60 seconds (30 days)
134
+ # are interpreted as absolute times (from the epoch).
135
+ #
136
+ # @return [Fixnum, false] false in case of failure and CAS value
137
+ # otherwise (it could be used as true value)
138
+ def write(name, value, options = nil)
139
+ options ||= {}
140
+ name = expanded_key name
141
+ if options.delete(:raw)
142
+ options[:format] = :plain
143
+ value = value.to_s
144
+ value.force_encoding(Encoding::BINARY) if defined?(Encoding)
145
+ end
146
+
147
+ instrument(:write, name, options) do |payload|
148
+ write_entry(name, value, options)
149
+ end
150
+ end
151
+
152
+ # Fetches data from the cache, using the given key.
153
+ #
154
+ # @since 1.2.0.dp5
155
+ #
156
+ # If there is data in the cache with the given key, then that data is
157
+ # returned. Otherwise, nil is returned.
158
+ #
159
+ # @param [String] name name for the key
160
+ # @param [Hash] options
161
+ # @option options [Fixnum] :expires_in the expiration time on the
162
+ # cache in seconds. Values larger than 30*24*60*60 seconds (30 days)
163
+ # are interpreted as absolute times (from the epoch).
164
+ # @option options [true, false] :raw do not marshal the value if this
165
+ # option is +true+
166
+ #
167
+ # @return [Object]
168
+ def read(name, options = nil)
169
+ options ||= {}
170
+ name = expanded_key name
171
+ if options.delete(:raw)
172
+ options[:format] = :plain
173
+ end
174
+
175
+ instrument(:read, name, options) do |payload|
176
+ entry = read_entry(name, options)
177
+ payload[:hit] = !!entry if payload
178
+ entry
179
+ end
180
+ end
181
+
182
+ # Read multiple values at once from the cache.
183
+ #
184
+ # @since 1.2.0.dp5
185
+ #
186
+ # Options can be passed in the last argument.
187
+ #
188
+ # Returns a hash mapping the names provided to the values found.
189
+ #
190
+ # @return [Hash] key-value pairs
191
+ def read_multi(*names)
192
+ options = names.extract_options!
193
+ names = names.flatten.map{|name| expanded_key(name)}
194
+ options[:assemble_hash] = true
195
+ if options.delete(:raw)
196
+ options[:format] = :plain
197
+ end
198
+ instrument(:read_multi, names, options) do
199
+ @data.get(names, options)
200
+ end
201
+ rescue ::Couchbase::Error::Base => e
202
+ logger.error("#{e.class}: #{e.message}") if logger
203
+ raise if @raise_errors
204
+ false
205
+ end
206
+
207
+ # Return true if the cache contains an entry for the given key.
208
+ #
209
+ # @since 1.2.0.dp5
210
+ #
211
+ # @return [true, false]
212
+ def exists?(name, options = nil)
213
+ options ||= {}
214
+ name = expanded_key name
215
+
216
+ instrument(:exists?, name) do
217
+ !read_entry(name, options).nil?
218
+ end
219
+ end
220
+ alias :exist? :exists?
221
+
222
+ # Deletes an entry in the cache.
223
+ #
224
+ # @since 1.2.0.dp5
225
+ #
226
+ # @return [true, false] true if an entry is deleted
227
+ def delete(name, options = nil)
228
+ options ||= {}
229
+ name = expanded_key name
230
+
231
+ instrument(:delete, name) do
232
+ delete_entry(name, options)
233
+ end
234
+ end
235
+
236
+ # Increment an integer value in the cache.
237
+ #
238
+ # @since 1.2.0.dp5
239
+ #
240
+ # @param [String] name name for the key
241
+ # @param [Fixnum] amount (1) the delta value
242
+ # @param [Hash] options
243
+ # @option options [Fixnum] :expires_in the expiration time on the
244
+ # cache in seconds. Values larger than 30*24*60*60 seconds (30 days)
245
+ # are interpreted as absolute times (from the epoch).
246
+ # @option options [Fixnum] :initial (1) this option allows to initialize
247
+ # the value if the key is missing in the cache
248
+ #
249
+ # @return [Fixnum] new value
250
+ def increment(name, amount = 1, options = nil)
251
+ options ||= {}
252
+ name = expanded_key name
253
+
254
+ if ttl = options.delete(:expires_in)
255
+ options[:ttl] ||= ttl
256
+ end
257
+ options[:create] = true
258
+ instrument(:increment, name, options) do |payload|
259
+ payload[:amount] = amount if payload
260
+ @data.incr(name, amount, options)
261
+ end
262
+ rescue ::Couchbase::Error::Base => e
263
+ logger.error("#{e.class}: #{e.message}") if logger
264
+ raise if @raise_errors
265
+ false
266
+ end
267
+
268
+ # Decrement an integer value in the cache.
269
+ #
270
+ # @since 1.2.0.dp5
271
+ #
272
+ # @param [String] name name for the key
273
+ # @param [Fixnum] amount (1) the delta value
274
+ # @param [Hash] options
275
+ # @option options [Fixnum] :expires_in the expiration time on the
276
+ # cache in seconds. Values larger than 30*24*60*60 seconds (30 days)
277
+ # are interpreted as absolute times (from the epoch).
278
+ # @option options [Fixnum] :initial this option allows to initialize
279
+ # the value if the key is missing in the cache
280
+ #
281
+ # @return [Fixnum] new value
282
+ def decrement(name, amount = 1, options = nil)
283
+ options ||= {}
284
+ name = expanded_key name
285
+
286
+ if ttl = options.delete(:expires_in)
287
+ options[:ttl] ||= ttl
288
+ end
289
+ options[:create] = true
290
+ instrument(:decrement, name, options) do |payload|
291
+ payload[:amount] = amount if payload
292
+ @data.decr(name, amount, options)
293
+ end
294
+ rescue ::Couchbase::Error::Base => e
295
+ logger.error("#{e.class}: #{e.message}") if logger
296
+ raise if @raise_errors
297
+ false
298
+ end
299
+
300
+ # Get the statistics from the memcached servers.
301
+ #
302
+ # @since 1.2.0.dp5
303
+ #
304
+ # @return [Hash]
305
+ def stats(*arg)
306
+ @data.stats(*arg)
307
+ end
308
+
309
+ protected
310
+
311
+ # Read an entry from the cache.
312
+ def read_entry(key, options) # :nodoc:
313
+ @data.get(key, options)
314
+ rescue ::Couchbase::Error::Base => e
315
+ logger.error("#{e.class}: #{e.message}") if logger
316
+ raise if @raise_errors
317
+ nil
318
+ end
319
+
320
+ # Write an entry to the cache.
321
+ def write_entry(key, value, options) # :nodoc:
322
+ method = if options[:unless_exists] || options[:unless_exist]
323
+ :add
324
+ else
325
+ :set
326
+ end
327
+ if ttl = options.delete(:expires_in)
328
+ options[:ttl] ||= ttl
329
+ end
330
+ @data.send(method, key, value, options)
331
+ rescue ::Couchbase::Error::Base => e
332
+ logger.error("#{e.class}: #{e.message}") if logger
333
+ raise if @raise_errors
334
+ false
335
+ end
336
+
337
+ # Delete an entry from the cache.
338
+ def delete_entry(key, options) # :nodoc:
339
+ @data.delete(key, options)
340
+ rescue ::Couchbase::Error::Base => e
341
+ logger.error("#{e.class}: #{e.message}") if logger
342
+ raise if @raise_errors
343
+ false
344
+ end
345
+
346
+ private
347
+
348
+ # Expand key to be a consistent string value. Invoke +cache_key+ if
349
+ # object responds to +cache_key+. Otherwise, to_param method will be
350
+ # called. If the key is a Hash, then keys will be sorted alphabetically.
351
+ def expanded_key(key) # :nodoc:
352
+ return validate_key(key.cache_key.to_s) if key.respond_to?(:cache_key)
353
+
354
+ case key
355
+ when Array
356
+ if key.size > 1
357
+ key = key.collect{|element| expanded_key(element)}
358
+ else
359
+ key = key.first
360
+ end
361
+ when Hash
362
+ key = key.sort_by { |k,_| k.to_s }.collect{|k,v| "#{k}=#{v}"}
363
+ end
364
+
365
+ validate_key(key.respond_to?(:to_param) ? key.to_param : key)
366
+ end
367
+
368
+ def validate_key(key)
369
+ if key_with_prefix(key).length > 250
370
+ key = "#{key[0, max_length_before_prefix]}:md5:#{Digest::MD5.hexdigest(key)}"
371
+ end
372
+ return key
373
+ end
374
+
375
+ def key_with_prefix(key)
376
+ (ns = @key_prefix) ? "#{ns}#{key}" : key
377
+ end
378
+
379
+ def max_length_before_prefix
380
+ @max_length_before_prefix ||= 212 - (@key_prefix || '').size
381
+ end
382
+
383
+ module Threadsafe
384
+ def self.extended(obj)
385
+ obj.init_threadsafe
386
+ end
387
+
388
+ def get(*)
389
+ @lock.synchronize do
390
+ super
391
+ end
392
+ end
393
+
394
+ def send(*)
395
+ @lock.synchronize do
396
+ super
397
+ end
398
+ end
399
+
400
+ def delete(*)
401
+ @lock.synchronize do
402
+ super
403
+ end
404
+ end
405
+
406
+ def incr(*)
407
+ @lock.synchronize do
408
+ super
409
+ end
410
+ end
411
+
412
+ def decr(*)
413
+ @lock.synchronize do
414
+ super
415
+ end
416
+ end
417
+
418
+ def stats(*)
419
+ @lock.synchronize do
420
+ super
421
+ end
422
+ end
423
+
424
+ def init_threadsafe
425
+ @lock = Monitor.new
426
+ end
427
+ end
428
+ end
429
+ end
430
+ end