libcouchbase 0.0.9 → 0.1.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -4
  3. data/README.md +4 -0
  4. data/ext/libcouchbase/CMakeLists.txt +1 -1
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +42 -0
  6. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  7. data/ext/libcouchbase/cmake/source_files.cmake +1 -0
  8. data/ext/libcouchbase/include/libcouchbase/cntl.h +27 -1
  9. data/ext/libcouchbase/include/libcouchbase/couchbase.h +0 -10
  10. data/ext/libcouchbase/include/libcouchbase/error.h +8 -1
  11. data/ext/libcouchbase/include/memcached/protocol_binary.h +12 -3
  12. data/ext/libcouchbase/src/auth.cc +0 -4
  13. data/ext/libcouchbase/src/cntl.cc +11 -1
  14. data/ext/libcouchbase/src/connspec.cc +18 -0
  15. data/ext/libcouchbase/src/connspec.h +10 -0
  16. data/ext/libcouchbase/src/dns-srv.cc +13 -14
  17. data/ext/libcouchbase/src/errmap.cc +107 -0
  18. data/ext/libcouchbase/src/errmap.h +113 -0
  19. data/ext/libcouchbase/src/hostlist.cc +0 -35
  20. data/ext/libcouchbase/src/hostlist.h +38 -64
  21. data/ext/libcouchbase/src/http/http.cc +6 -1
  22. data/ext/libcouchbase/src/instance.cc +1 -1
  23. data/ext/libcouchbase/src/internal.h +10 -0
  24. data/ext/libcouchbase/src/mcserver/mcserver.cc +119 -3
  25. data/ext/libcouchbase/src/mcserver/mcserver.h +3 -1
  26. data/ext/libcouchbase/src/mcserver/negotiate.cc +130 -37
  27. data/ext/libcouchbase/src/nodeinfo.cc +1 -1
  28. data/ext/libcouchbase/src/settings.c +3 -0
  29. data/ext/libcouchbase/src/settings.h +5 -0
  30. data/ext/libcouchbase/src/ssl/ssl_common.c +2 -0
  31. data/ext/libcouchbase/tests/basic/t_host.cc +67 -75
  32. data/ext/libcouchbase/tests/iotests/mock-environment.h +2 -1
  33. data/ext/libcouchbase/tests/iotests/t_confmon.cc +3 -4
  34. data/ext/libcouchbase/tests/iotests/t_errmap.cc +97 -0
  35. data/lib/libcouchbase/bucket.rb +27 -12
  36. data/lib/libcouchbase/callbacks.rb +1 -1
  37. data/lib/libcouchbase/connection.rb +18 -5
  38. data/lib/libcouchbase/version.rb +1 -1
  39. data/spec/connection_spec.rb +1 -1
  40. metadata +5 -2
@@ -71,7 +71,8 @@ class MockCommand
71
71
  X(GET_MCPORTS) \
72
72
  X(SET_CCCP) \
73
73
  X(REGEN_VBCOORDS) \
74
- X(RESET_QUERYSTATE)
74
+ X(RESET_QUERYSTATE) \
75
+ X(OPFAIL)
75
76
 
76
77
  public:
77
78
  enum Code {
@@ -141,14 +141,13 @@ TEST_F(ConfmonTest, testCycle)
141
141
  Provider *cccp = mon->get_provider(CLCONFIG_CCCP);
142
142
  Provider *http = mon->get_provider(CLCONFIG_HTTP);
143
143
 
144
- hostlist_t hl = hostlist_create();
145
- hostlist_add_stringz(hl, cropts.v.v2.mchosts, 11210);
144
+ lcb::Hostlist hl;
145
+ hl.add(cropts.v.v2.mchosts, 11210);
146
146
  cccp->enable(instance);
147
- cccp->configure_nodes(*hl);
147
+ cccp->configure_nodes(hl);
148
148
 
149
149
  http->enable();
150
150
  http->configure_nodes(*instance->ht_nodes);
151
- hostlist_destroy(hl);
152
151
 
153
152
  mon->prepare();
154
153
  mon->start();
@@ -0,0 +1,97 @@
1
+ #include "config.h"
2
+ #include "iotests.h"
3
+ #include "internal.h"
4
+ #include <map>
5
+
6
+ class ErrmapUnitTest : public MockUnitTest {
7
+ protected:
8
+ virtual void createErrmapConnection(HandleWrap& hw, lcb_t& instance) {
9
+ MockEnvironment::getInstance()->createConnection(hw, instance);
10
+ ASSERT_EQ(LCB_SUCCESS, lcb_cntl_string(instance, "enable_errmap", "true"));
11
+ ASSERT_EQ(LCB_SUCCESS, lcb_connect(instance));
12
+ lcb_wait(instance);
13
+ ASSERT_EQ(LCB_SUCCESS, lcb_get_bootstrap_status(instance));
14
+ }
15
+ };
16
+
17
+ struct ResultCookie {
18
+ lcb_error_t rc;
19
+ bool called;
20
+
21
+ void reset() {
22
+ rc = LCB_SUCCESS;
23
+ called = false;
24
+ }
25
+ ResultCookie() : rc(LCB_SUCCESS), called(false) {
26
+ }
27
+ };
28
+
29
+ extern "C" {
30
+ static void opcb(lcb_t,int,const lcb_RESPBASE* rb) {
31
+ ResultCookie *cookie = reinterpret_cast<ResultCookie*>(rb->cookie);
32
+ cookie->called = true;
33
+ cookie->rc = rb->rc;
34
+ }
35
+ }
36
+
37
+ TEST_F(ErrmapUnitTest, hasRecognizedErrors) {
38
+ SKIP_UNLESS_MOCK();
39
+ HandleWrap hw;
40
+ lcb_t instance;
41
+
42
+ createErrmapConnection(hw, instance);
43
+
44
+ // Test the actual error map..
45
+ using namespace lcb;
46
+ const errmap::ErrorMap& em = *instance->settings->errmap;
47
+ const errmap::Error& err = em.getError(PROTOCOL_BINARY_RESPONSE_KEY_ENOENT);
48
+ ASSERT_TRUE(err.isValid());
49
+ ASSERT_TRUE(err.hasAttribute(errmap::CONSTRAINT_FAILURE));
50
+ }
51
+
52
+ TEST_F(ErrmapUnitTest, closesOnUnrecognizedError) {
53
+ // For now, EINTERNAL is an error code we don't know!
54
+ SKIP_UNLESS_MOCK();
55
+ HandleWrap hw;
56
+ lcb_t instance;
57
+ createErrmapConnection(hw, instance);
58
+
59
+ const char *key = "key";
60
+ lcb_CMDSTORE scmd = { 0 };
61
+ LCB_CMD_SET_KEY(&scmd, key, strlen(key));
62
+ LCB_CMD_SET_VALUE(&scmd, "val", 3);
63
+
64
+ ResultCookie cookie;
65
+ lcb_install_callback3(instance, LCB_CALLBACK_STORE, opcb);
66
+ ASSERT_EQ(LCB_SUCCESS, lcb_store3(instance, &cookie, &scmd));
67
+ lcb_wait(instance);
68
+ ASSERT_EQ(LCB_SUCCESS, cookie.rc);
69
+
70
+ MockCommand cmd(MockCommand::OPFAIL);
71
+
72
+ // Determine the server
73
+ int srvix = instance->map_key(key);
74
+
75
+ cmd.set("server", srvix);
76
+ cmd.set("code", PROTOCOL_BINARY_RESPONSE_EINTERNAL); // Invalidate the connection!
77
+ cmd.set("count", 1);
78
+ doMockTxn(cmd);
79
+
80
+ cookie.reset();
81
+ ASSERT_EQ(LCB_SUCCESS, lcb_store3(instance, &cookie, &scmd));
82
+ lcb_wait(instance);
83
+
84
+ ASSERT_TRUE(cookie.called);
85
+ ASSERT_NE(LCB_SUCCESS, cookie.rc);
86
+
87
+ cookie.reset();
88
+ ASSERT_EQ(LCB_SUCCESS, lcb_store3(instance, &cookie, &scmd));
89
+ lcb_wait(instance);
90
+ ASSERT_TRUE(cookie.called);
91
+
92
+ // Note, we can't determine what the actual error here is. It would be nice
93
+ // if we were able to reconnect and retry the other commands, but right now
94
+ // detecting a failed connection is better than having no detection at all:
95
+ //
96
+ // ASSERT_EQ(LCB_SUCCESS, cookie.rc);
97
+ }
@@ -24,7 +24,7 @@ module Libcouchbase
24
24
 
25
25
  # This obtains the connections reactor
26
26
  @reactor = reactor
27
- @quiet = true
27
+ @quiet = false
28
28
 
29
29
  # clean up the connection once this object is garbage collected
30
30
  ObjectSpace.define_finalizer( self, self.class.finalize(@connection) )
@@ -157,7 +157,11 @@ module Libcouchbase
157
157
  }), async)
158
158
  end
159
159
  end
160
- alias_method :[], :get
160
+
161
+ # Quietly obtain an object stored in Couchbase by given key.
162
+ def [](key)
163
+ get(key, quiet: true)
164
+ end
161
165
 
162
166
  # Add the item to the database, but fail if the object exists already
163
167
  #
@@ -495,7 +499,7 @@ module Libcouchbase
495
499
  # res = c.set("foo", "bar") #=> #<struct Libcouchbase::Response callback=:callback_set, key="foo", cas=1975457268957184, value="bar", metadata={:format=>:document, :flags=>0}>
496
500
  # c.delete("foo", cas: 123456) #=> will raise Libcouchbase::Error::KeyExists
497
501
  # c.delete("foo", cas: res.cas) #=> true
498
- def delete(key, async: false, quiet: @quiet, **opts)
502
+ def delete(key, async: false, quiet: true, **opts)
499
503
  promise = @connection.remove(key, **opts).then { true }
500
504
  if quiet
501
505
  promise = promise.catch { |error|
@@ -654,7 +658,7 @@ module Libcouchbase
654
658
  # @param [String, Symbol] key
655
659
  #
656
660
  # @param [Hash] options the options for "swap" part
657
- # @option options [Fixnum] :retry (0) maximum number of times to autmatically retry upon update collision
661
+ # @option options [Integer] :retry (0) maximum number of times to autmatically retry upon update collision
658
662
  #
659
663
  # @yieldparam [Object] value existing value
660
664
  # @yieldreturn [Object] new value.
@@ -727,7 +731,7 @@ module Libcouchbase
727
731
  @connection.reactor.next_tick do
728
732
  begin
729
733
  response = co(promise)
730
- rescue => e
734
+ rescue Exception => e
731
735
  error = e
732
736
  end
733
737
 
@@ -738,7 +742,7 @@ module Libcouchbase
738
742
 
739
743
  Fiber.yield
740
744
 
741
- raise error if error
745
+ update_backtrace(error) if error
742
746
  response
743
747
  else
744
748
  request = Mutex.new
@@ -750,7 +754,7 @@ module Libcouchbase
750
754
  @connection.reactor.next_tick do
751
755
  begin
752
756
  response = co(promise)
753
- rescue => e
757
+ rescue Exception => e
754
758
  error = e
755
759
  end
756
760
 
@@ -762,7 +766,7 @@ module Libcouchbase
762
766
  result.wait(request)
763
767
  }
764
768
 
765
- raise error if error
769
+ update_backtrace(error) if error
766
770
  response
767
771
  end
768
772
  end
@@ -801,7 +805,7 @@ module Libcouchbase
801
805
  retry
802
806
  end
803
807
  error = e
804
- rescue => e
808
+ rescue Exception => e
805
809
  error = e
806
810
  end
807
811
 
@@ -814,7 +818,7 @@ module Libcouchbase
814
818
  result.wait(connecting)
815
819
  }
816
820
 
817
- raise error if error
821
+ update_backtrace(error) if error
818
822
  end
819
823
 
820
824
  # Assume this is being run in em-synchrony
@@ -838,7 +842,7 @@ module Libcouchbase
838
842
  retry
839
843
  end
840
844
  error = e
841
- rescue => e
845
+ rescue Exception => e
842
846
  error = e
843
847
  end
844
848
 
@@ -850,7 +854,18 @@ module Libcouchbase
850
854
 
851
855
  Fiber.yield
852
856
 
853
- raise error if error
857
+ update_backtrace(error) if error
858
+ end
859
+
860
+ def update_backtrace(error)
861
+ backtrace = caller
862
+ backtrace.shift(2)
863
+ if error.respond_to?(:backtrace) && error.backtrace
864
+ backtrace << '---- continuation ----'
865
+ backtrace.concat(error.backtrace)
866
+ end
867
+ error.set_backtrace(backtrace)
868
+ raise error
854
869
  end
855
870
  end
856
871
  end
@@ -47,7 +47,7 @@ module Libcouchbase
47
47
 
48
48
  def self.included(base)
49
49
  base.instance_variable_set(:@callback_funcs, {})
50
- base.instance_variable_set(:@callback_lookup, ::Concurrent::Map.new)
50
+ base.instance_variable_set(:@callback_lookup, ::Concurrent::Hash.new)
51
51
  base.instance_variable_set(:@callback_lock, ::Mutex.new)
52
52
  base.extend(ClassMethods)
53
53
  end
@@ -3,6 +3,15 @@
3
3
  require 'json'
4
4
 
5
5
 
6
+ at_exit do
7
+ ObjectSpace.each_object(::Libcouchbase::Connection).each do |connection|
8
+ connection.destroy.finally do
9
+ connection.reactor.stop
10
+ end
11
+ end
12
+ end
13
+
14
+
6
15
  module Libcouchbase
7
16
  Response = Struct.new(:callback, :key, :cas, :value, :metadata)
8
17
  HttpResponse = Struct.new(:callback, :status, :headers, :body, :request)
@@ -176,12 +185,16 @@ module Libcouchbase
176
185
  # Ensure it is thread safe
177
186
  @reactor.schedule {
178
187
  if @handle
179
- resp = Ext.get_server_list(@handle)
180
- if resp.null?
181
- defer.reject(RuntimeError.new('not connected'))
182
- else
183
- defer.resolve(resp.get_array_of_string(0))
188
+ nodes = Ext.get_num_nodes(@handle)
189
+ list = []
190
+ count = 0
191
+
192
+ while count <= nodes
193
+ list << Ext.get_node(@handle, :node_data, count)
194
+ count += 1
184
195
  end
196
+
197
+ defer.resolve(list.uniq)
185
198
  else
186
199
  defer.reject(RuntimeError.new('not connected'))
187
200
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true, encoding: ASCII-8BIT
2
2
 
3
3
  module Libcouchbase
4
- VERSION = '0.0.9'
4
+ VERSION = '0.1.0'
5
5
  end
@@ -157,7 +157,7 @@ describe Libcouchbase::Connection do
157
157
  end
158
158
  }
159
159
 
160
- expect(@log).to eq(['127.0.0.1:8091'])
160
+ expect(@log).to eq(['127.0.0.1:11210'])
161
161
  end
162
162
 
163
163
  it "should support counter operations" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: libcouchbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen von Takach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-03 00:00:00.000000000 Z
11
+ date: 2017-03-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -404,6 +404,8 @@ files:
404
404
  - ext/libcouchbase/src/ctx-log-inl.h
405
405
  - ext/libcouchbase/src/dns-srv.cc
406
406
  - ext/libcouchbase/src/dump.cc
407
+ - ext/libcouchbase/src/errmap.cc
408
+ - ext/libcouchbase/src/errmap.h
407
409
  - ext/libcouchbase/src/getconfig.cc
408
410
  - ext/libcouchbase/src/gethrtime.c
409
411
  - ext/libcouchbase/src/handler.cc
@@ -566,6 +568,7 @@ files:
566
568
  - ext/libcouchbase/tests/iotests/t_configcache.cc
567
569
  - ext/libcouchbase/tests/iotests/t_confmon.cc
568
570
  - ext/libcouchbase/tests/iotests/t_durability.cc
571
+ - ext/libcouchbase/tests/iotests/t_errmap.cc
569
572
  - ext/libcouchbase/tests/iotests/t_forward.cc
570
573
  - ext/libcouchbase/tests/iotests/t_get.cc
571
574
  - ext/libcouchbase/tests/iotests/t_http.cc