couchbase 1.1.5-x86-mingw32 → 1.2.0.beta-x86-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 (52) hide show
  1. data/.gitignore +2 -1
  2. data/.travis.yml +12 -1
  3. data/HISTORY.markdown +112 -1
  4. data/README.markdown +149 -6
  5. data/couchbase.gemspec +5 -1
  6. data/ext/couchbase_ext/.gitignore +4 -0
  7. data/ext/couchbase_ext/arguments.c +973 -0
  8. data/ext/couchbase_ext/arithmetic.c +322 -0
  9. data/ext/couchbase_ext/bucket.c +1092 -0
  10. data/ext/couchbase_ext/couchbase_ext.c +618 -3247
  11. data/ext/couchbase_ext/couchbase_ext.h +519 -0
  12. data/ext/couchbase_ext/delete.c +167 -0
  13. data/ext/couchbase_ext/extconf.rb +24 -5
  14. data/ext/couchbase_ext/get.c +301 -0
  15. data/ext/couchbase_ext/gethrtime.c +124 -0
  16. data/ext/couchbase_ext/http.c +402 -0
  17. data/ext/couchbase_ext/observe.c +174 -0
  18. data/ext/couchbase_ext/result.c +126 -0
  19. data/ext/couchbase_ext/stats.c +169 -0
  20. data/ext/couchbase_ext/store.c +522 -0
  21. data/ext/couchbase_ext/timer.c +192 -0
  22. data/ext/couchbase_ext/touch.c +190 -0
  23. data/ext/couchbase_ext/unlock.c +180 -0
  24. data/ext/couchbase_ext/utils.c +471 -0
  25. data/ext/couchbase_ext/version.c +147 -0
  26. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  27. data/lib/active_support/cache/couchbase_store.rb +356 -0
  28. data/lib/couchbase.rb +24 -3
  29. data/lib/couchbase/bucket.rb +372 -9
  30. data/lib/couchbase/result.rb +26 -0
  31. data/lib/couchbase/utils.rb +59 -0
  32. data/lib/couchbase/version.rb +1 -1
  33. data/lib/couchbase/view.rb +305 -0
  34. data/lib/couchbase/view_row.rb +230 -0
  35. data/lib/ext/multi_json_fix.rb +47 -0
  36. data/lib/rack/session/couchbase.rb +104 -0
  37. data/tasks/compile.rake +5 -14
  38. data/test/setup.rb +6 -2
  39. data/test/test_arithmetic.rb +32 -2
  40. data/test/test_async.rb +18 -4
  41. data/test/test_bucket.rb +11 -1
  42. data/test/test_cas.rb +13 -3
  43. data/test/test_couchbase_rails_cache_store.rb +294 -0
  44. data/test/test_delete.rb +60 -3
  45. data/test/test_format.rb +28 -17
  46. data/test/test_get.rb +91 -14
  47. data/test/test_store.rb +31 -1
  48. data/test/{test_flush.rb → test_timer.rb} +11 -18
  49. data/test/test_touch.rb +33 -5
  50. data/test/test_unlock.rb +120 -0
  51. data/test/test_utils.rb +26 -0
  52. metadata +102 -12
@@ -0,0 +1,174 @@
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
+ observe_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_observe_resp_t *resp)
22
+ {
23
+ struct context_st *ctx = (struct context_st *)cookie;
24
+ struct bucket_st *bucket = ctx->bucket;
25
+ VALUE key, res, *rv = ctx->rv;
26
+
27
+ if (resp->v.v0.key) {
28
+ key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
29
+ ctx->exception = cb_check_error(error, "failed to execute observe request", key);
30
+ if (ctx->exception) {
31
+ cb_gc_protect(bucket, ctx->exception);
32
+ }
33
+ res = rb_class_new_instance(0, NULL, cResult);
34
+ rb_ivar_set(res, id_iv_completed, Qfalse);
35
+ rb_ivar_set(res, id_iv_error, ctx->exception);
36
+ rb_ivar_set(res, id_iv_operation, sym_observe);
37
+ rb_ivar_set(res, id_iv_key, key);
38
+ rb_ivar_set(res, id_iv_cas, ULL2NUM(resp->v.v0.cas));
39
+ rb_ivar_set(res, id_iv_from_master, resp->v.v0.from_master ? Qtrue : Qfalse);
40
+ rb_ivar_set(res, id_iv_time_to_persist, ULONG2NUM(resp->v.v0.ttp));
41
+ rb_ivar_set(res, id_iv_time_to_replicate, ULONG2NUM(resp->v.v0.ttr));
42
+ switch (resp->v.v0.status) {
43
+ case LCB_OBSERVE_FOUND:
44
+ rb_ivar_set(res, id_iv_status, sym_found);
45
+ break;
46
+ case LCB_OBSERVE_PERSISTED:
47
+ rb_ivar_set(res, id_iv_status, sym_persisted);
48
+ break;
49
+ case LCB_OBSERVE_NOT_FOUND:
50
+ rb_ivar_set(res, id_iv_status, sym_not_found);
51
+ break;
52
+ default:
53
+ rb_ivar_set(res, id_iv_status, Qnil);
54
+ }
55
+ if (bucket->async) { /* asynchronous */
56
+ if (ctx->proc != Qnil) {
57
+ cb_proc_call(ctx->proc, 1, res);
58
+ }
59
+ } else { /* synchronous */
60
+ if (NIL_P(ctx->exception)) {
61
+ VALUE stats = rb_hash_aref(*rv, key);
62
+ if (NIL_P(stats)) {
63
+ stats = rb_ary_new();
64
+ rb_hash_aset(*rv, key, stats);
65
+ }
66
+ rb_ary_push(stats, res);
67
+ }
68
+ }
69
+ } else {
70
+ if (bucket->async && ctx->proc != Qnil) {
71
+ res = rb_class_new_instance(0, NULL, cResult);
72
+ rb_ivar_set(res, id_iv_completed, Qtrue);
73
+ cb_proc_call(ctx->proc, 1, res);
74
+ }
75
+ ctx->nqueries--;
76
+ cb_gc_unprotect(bucket, ctx->proc);
77
+ }
78
+ (void)handle;
79
+ }
80
+
81
+ /*
82
+ * Observe key state
83
+ *
84
+ * @since 1.2.0.dp6
85
+ *
86
+ * @overload observe(*keys, options = {})
87
+ * @param keys [String, Symbol, Array] One or several keys to fetch
88
+ * @param options [Hash] Options for operation.
89
+ *
90
+ * @yieldparam ret [Result] the result of operation in asynchronous mode
91
+ * (valid attributes: +error+, +status+, +operation+, +key+, +cas+,
92
+ * +from_master+, +time_to_persist+, +time_to_replicate+).
93
+ *
94
+ * @return [Hash<String, Array<Result>>, Array<Result>] the state of the
95
+ * keys on all nodes. If the +keys+ argument was String or Symbol, this
96
+ * method will return just array of results (result per each node),
97
+ * otherwise it will return hash map.
98
+ *
99
+ * @example Observe single key
100
+ * c.observe("foo")
101
+ * #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
102
+ *
103
+ * @example Observe multiple keys
104
+ * keys = ["foo", "bar"]
105
+ * stats = c.observe(keys)
106
+ * stats.size #=> 2
107
+ * stats["foo"] #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
108
+ */
109
+
110
+ VALUE
111
+ cb_bucket_observe(int argc, VALUE *argv, VALUE self)
112
+ {
113
+ struct bucket_st *bucket = DATA_PTR(self);
114
+ struct context_st *ctx;
115
+ VALUE args, rv, proc, exc;
116
+ lcb_error_t err;
117
+ struct params_st params;
118
+
119
+ if (bucket->handle == NULL) {
120
+ rb_raise(eConnectError, "closed connection");
121
+ }
122
+ rb_scan_args(argc, argv, "0*&", &args, &proc);
123
+ if (!bucket->async && proc != Qnil) {
124
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
125
+ }
126
+ memset(&params, 0, sizeof(struct params_st));
127
+ params.type = cmd_observe;
128
+ params.bucket = bucket;
129
+ cb_params_build(&params, RARRAY_LEN(args), args);
130
+ ctx = xcalloc(1, sizeof(struct context_st));
131
+ if (ctx == NULL) {
132
+ rb_raise(eClientNoMemoryError, "failed to allocate memory for context");
133
+ }
134
+ ctx->proc = cb_gc_protect(bucket, proc);
135
+ ctx->bucket = bucket;
136
+ rv = rb_hash_new();
137
+ ctx->rv = &rv;
138
+ ctx->exception = Qnil;
139
+ ctx->nqueries = params.cmd.observe.num;
140
+ err = lcb_observe(bucket->handle, (const void *)ctx,
141
+ params.cmd.observe.num, params.cmd.observe.ptr);
142
+ cb_params_destroy(&params);
143
+ exc = cb_check_error(err, "failed to schedule observe request", Qnil);
144
+ if (exc != Qnil) {
145
+ xfree(ctx);
146
+ rb_exc_raise(exc);
147
+ }
148
+ bucket->nbytes += params.npayload;
149
+ if (bucket->async) {
150
+ maybe_do_loop(bucket);
151
+ return Qnil;
152
+ } else {
153
+ if (ctx->nqueries > 0) {
154
+ /* we have some operations pending */
155
+ lcb_wait(bucket->handle);
156
+ }
157
+ exc = ctx->exception;
158
+ xfree(ctx);
159
+ if (exc != Qnil) {
160
+ cb_gc_unprotect(bucket, exc);
161
+ rb_exc_raise(exc);
162
+ }
163
+ if (bucket->exception != Qnil) {
164
+ rb_exc_raise(bucket->exception);
165
+ }
166
+ if (params.cmd.observe.num > 1 || params.cmd.observe.array) {
167
+ return rv; /* return as a hash {key => {}, ...} */
168
+ } else {
169
+ VALUE vv = Qnil;
170
+ rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
171
+ return vv; /* return first value */
172
+ }
173
+ }
174
+ }
@@ -0,0 +1,126 @@
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
+ /*
21
+ * Check if result of operation was successful.
22
+ *
23
+ * @since 1.0.0
24
+ *
25
+ * @return [true, false] +false+ if there is an +error+ object attached,
26
+ * +false+ otherwise.
27
+ */
28
+ VALUE
29
+ cb_result_success_p(VALUE self)
30
+ {
31
+ return RTEST(rb_ivar_get(self, id_iv_error)) ? Qfalse : Qtrue;
32
+ }
33
+
34
+ /*
35
+ * Returns a string containing a human-readable representation of the Result.
36
+ *
37
+ * @since 1.0.0
38
+ *
39
+ * @return [String]
40
+ */
41
+ VALUE
42
+ cb_result_inspect(VALUE self)
43
+ {
44
+ VALUE str, attr, error;
45
+ char buf[100];
46
+
47
+ str = rb_str_buf_new2("#<");
48
+ rb_str_buf_cat2(str, rb_obj_classname(self));
49
+ snprintf(buf, 100, ":%p", (void *)self);
50
+ rb_str_buf_cat2(str, buf);
51
+
52
+ attr = rb_ivar_get(self, id_iv_error);
53
+ if (RTEST(attr)) {
54
+ error = rb_ivar_get(attr, id_iv_error);
55
+ } else {
56
+ error = INT2FIX(0);
57
+ }
58
+ rb_str_buf_cat2(str, " error=0x");
59
+ rb_str_append(str, rb_funcall(error, id_to_s, 1, INT2FIX(16)));
60
+
61
+ attr = rb_ivar_get(self, id_iv_operation);
62
+ if (RTEST(attr)) {
63
+ rb_str_buf_cat2(str, " operation=");
64
+ rb_str_append(str, rb_inspect(attr));
65
+ }
66
+
67
+ attr = rb_ivar_get(self, id_iv_key);
68
+ if (RTEST(attr)) {
69
+ rb_str_buf_cat2(str, " key=");
70
+ rb_str_append(str, rb_inspect(attr));
71
+ }
72
+
73
+ attr = rb_ivar_get(self, id_iv_status);
74
+ if (RTEST(attr)) {
75
+ rb_str_buf_cat2(str, " status=");
76
+ rb_str_append(str, rb_inspect(attr));
77
+ }
78
+
79
+ attr = rb_ivar_get(self, id_iv_cas);
80
+ if (RTEST(attr)) {
81
+ rb_str_buf_cat2(str, " cas=");
82
+ rb_str_append(str, rb_inspect(attr));
83
+ }
84
+
85
+ attr = rb_ivar_get(self, id_iv_flags);
86
+ if (RTEST(attr)) {
87
+ rb_str_buf_cat2(str, " flags=0x");
88
+ rb_str_append(str, rb_funcall(attr, id_to_s, 1, INT2FIX(16)));
89
+ }
90
+
91
+ attr = rb_ivar_get(self, id_iv_node);
92
+ if (RTEST(attr)) {
93
+ rb_str_buf_cat2(str, " node=");
94
+ rb_str_append(str, rb_inspect(attr));
95
+ }
96
+
97
+ attr = rb_ivar_get(self, id_iv_from_master);
98
+ if (attr != Qnil) {
99
+ rb_str_buf_cat2(str, " from_master=");
100
+ rb_str_append(str, rb_inspect(attr));
101
+ }
102
+
103
+ attr = rb_ivar_get(self, id_iv_time_to_persist);
104
+ if (RTEST(attr)) {
105
+ rb_str_buf_cat2(str, " time_to_persist=");
106
+ rb_str_append(str, rb_inspect(attr));
107
+ }
108
+
109
+ attr = rb_ivar_get(self, id_iv_time_to_replicate);
110
+ if (RTEST(attr)) {
111
+ rb_str_buf_cat2(str, " time_to_replicate=");
112
+ rb_str_append(str, rb_inspect(attr));
113
+ }
114
+
115
+ attr = rb_ivar_get(self, id_iv_headers);
116
+ if (RTEST(attr)) {
117
+ rb_str_buf_cat2(str, " headers=");
118
+ rb_str_append(str, rb_inspect(attr));
119
+ }
120
+
121
+ rb_str_buf_cat2(str, ">");
122
+
123
+ return str;
124
+ }
125
+
126
+
@@ -0,0 +1,169 @@
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
+ stat_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_server_stat_resp_t *resp)
22
+ {
23
+ struct context_st *ctx = (struct context_st *)cookie;
24
+ struct bucket_st *bucket = ctx->bucket;
25
+ VALUE stats, node, key, val, *rv = ctx->rv, exc = Qnil, 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 fetch stats", node);
29
+ if (exc != Qnil) {
30
+ rb_ivar_set(exc, id_iv_operation, sym_stats);
31
+ if (NIL_P(ctx->exception)) {
32
+ ctx->exception = cb_gc_protect(bucket, exc);
33
+ }
34
+ }
35
+ if (node != Qnil) {
36
+ key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
37
+ val = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
38
+ if (bucket->async) { /* asynchronous */
39
+ if (ctx->proc != Qnil) {
40
+ res = rb_class_new_instance(0, NULL, cResult);
41
+ rb_ivar_set(res, id_iv_error, exc);
42
+ rb_ivar_set(res, id_iv_operation, sym_stats);
43
+ rb_ivar_set(res, id_iv_node, node);
44
+ rb_ivar_set(res, id_iv_key, key);
45
+ rb_ivar_set(res, id_iv_value, val);
46
+ cb_proc_call(ctx->proc, 1, res);
47
+ }
48
+ } else { /* synchronous */
49
+ if (NIL_P(exc)) {
50
+ stats = rb_hash_aref(*rv, key);
51
+ if (NIL_P(stats)) {
52
+ stats = rb_hash_new();
53
+ rb_hash_aset(*rv, key, stats);
54
+ }
55
+ rb_hash_aset(stats, node, val);
56
+ }
57
+ }
58
+ } else {
59
+ ctx->nqueries--;
60
+ cb_gc_unprotect(bucket, ctx->proc);
61
+ }
62
+ (void)handle;
63
+ }
64
+
65
+ /*
66
+ * Request server statistics.
67
+ *
68
+ * @since 1.0.0
69
+ *
70
+ * Fetches stats from each node in cluster. Without a key specified the
71
+ * server will respond with a "default" set of statistical information. In
72
+ * asynchronous mode each statistic is returned in separate call where the
73
+ * Result object yielded (+#key+ contains the name of the statistical item
74
+ * and the +#value+ contains the value, the +#node+ will indicate the server
75
+ * address). In synchronous mode it returns the hash of stats keys and
76
+ * node-value pairs as a value.
77
+ *
78
+ * @overload stats(arg = nil)
79
+ * @param [String] arg argument to STATS query
80
+ * @yieldparam [Result] ret the object with +node+, +key+ and +value+
81
+ * attributes.
82
+ *
83
+ * @example Found how many items in the bucket
84
+ * total = 0
85
+ * c.stats["total_items"].each do |key, value|
86
+ * total += value.to_i
87
+ * end
88
+ *
89
+ * @example Found total items number asynchronously
90
+ * total = 0
91
+ * c.run do
92
+ * c.stats do |ret|
93
+ * if ret.key == "total_items"
94
+ * total += ret.value.to_i
95
+ * end
96
+ * end
97
+ * end
98
+ *
99
+ * @example Get memory stats (works on couchbase buckets)
100
+ * c.stats(:memory) #=> {"mem_used"=>{...}, ...}
101
+ *
102
+ * @return [Hash] where keys are stat keys, values are host-value pairs
103
+ *
104
+ * @raise [Couchbase::Error::Connect] if connection closed (see {Bucket#reconnect})
105
+ * @raise [ArgumentError] when passing the block in synchronous mode
106
+ */
107
+ VALUE
108
+ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
109
+ {
110
+ struct bucket_st *bucket = DATA_PTR(self);
111
+ struct context_st *ctx;
112
+ VALUE rv, exc, args, proc;
113
+ lcb_error_t err;
114
+ struct params_st params;
115
+
116
+ if (bucket->handle == NULL) {
117
+ rb_raise(eConnectError, "closed connection");
118
+ }
119
+ rb_scan_args(argc, argv, "0*&", &args, &proc);
120
+ if (!bucket->async && proc != Qnil) {
121
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
122
+ }
123
+ memset(&params, 0, sizeof(struct params_st));
124
+ params.type = cmd_stats;
125
+ params.bucket = bucket;
126
+ cb_params_build(&params, RARRAY_LEN(args), args);
127
+ ctx = xcalloc(1, sizeof(struct context_st));
128
+ if (ctx == NULL) {
129
+ rb_raise(eClientNoMemoryError, "failed to allocate memory for context");
130
+ }
131
+ rv = rb_hash_new();
132
+ ctx->rv = &rv;
133
+ ctx->bucket = bucket;
134
+ ctx->proc = cb_gc_protect(bucket, proc);
135
+ ctx->exception = Qnil;
136
+ ctx->nqueries = params.cmd.stats.num;
137
+ err = lcb_server_stats(bucket->handle, (const void *)ctx,
138
+ params.cmd.stats.num, params.cmd.stats.ptr);
139
+ exc = cb_check_error(err, "failed to schedule stat request", Qnil);
140
+ cb_params_destroy(&params);
141
+ if (exc != Qnil) {
142
+ xfree(ctx);
143
+ rb_exc_raise(exc);
144
+ }
145
+ bucket->nbytes += params.npayload;
146
+ if (bucket->async) {
147
+ maybe_do_loop(bucket);
148
+ return Qnil;
149
+ } else {
150
+ if (ctx->nqueries > 0) {
151
+ /* we have some operations pending */
152
+ lcb_wait(bucket->handle);
153
+ }
154
+ exc = ctx->exception;
155
+ xfree(ctx);
156
+ if (exc != Qnil) {
157
+ cb_gc_unprotect(bucket, exc);
158
+ rb_exc_raise(exc);
159
+ }
160
+ if (bucket->exception != Qnil) {
161
+ rb_exc_raise(bucket->exception);
162
+ }
163
+ return rv;
164
+ }
165
+
166
+ return Qnil;
167
+ }
168
+
169
+