libcouchbase 0.3.3 → 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.
- checksums.yaml +4 -4
- data/ext/libcouchbase/CMakeLists.txt +6 -8
- data/ext/libcouchbase/README.markdown +2 -2
- data/ext/libcouchbase/RELEASE_NOTES.markdown +229 -2
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +11 -0
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +18 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +3 -2
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +4 -0
- data/ext/libcouchbase/cmake/defs.mk.in +0 -2
- data/ext/libcouchbase/cmake/source_files.cmake +21 -5
- data/ext/libcouchbase/contrib/cJSON/cJSON.c +1 -1
- data/ext/libcouchbase/contrib/cbsasl/src/client.c +2 -0
- data/ext/libcouchbase/example/users/README +48 -0
- data/ext/libcouchbase/example/users/users.c +147 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +175 -31
- data/ext/libcouchbase/include/libcouchbase/cntl.h +82 -1
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +45 -3
- data/ext/libcouchbase/include/libcouchbase/error.h +19 -1
- data/ext/libcouchbase/include/libcouchbase/iops.h +3 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +31 -1
- data/ext/libcouchbase/include/libcouchbase/plugins/io/bsdio-inl.c +4 -1
- data/ext/libcouchbase/include/libcouchbase/subdoc.h +36 -2
- data/ext/libcouchbase/include/libcouchbase/views.h +7 -1
- data/ext/libcouchbase/include/libcouchbase/visibility.h +1 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +24 -1146
- data/ext/libcouchbase/packaging/parse-git-describe.pl +1 -1
- data/ext/libcouchbase/plugins/io/libev/libev_io_opts.h +3 -2
- data/ext/libcouchbase/src/README.md +0 -2
- data/ext/libcouchbase/src/auth-priv.h +23 -4
- data/ext/libcouchbase/src/auth.cc +51 -43
- data/ext/libcouchbase/src/bootstrap.cc +244 -0
- data/ext/libcouchbase/src/bootstrap.h +58 -38
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +120 -158
- data/ext/libcouchbase/src/bucketconfig/bc_file.cc +281 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +526 -0
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +50 -25
- data/ext/libcouchbase/src/bucketconfig/bc_static.cc +150 -0
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +410 -386
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +393 -0
- data/ext/libcouchbase/src/cbft.cc +22 -27
- data/ext/libcouchbase/src/cntl.cc +56 -22
- data/ext/libcouchbase/src/connspec.cc +47 -6
- data/ext/libcouchbase/src/connspec.h +27 -0
- data/ext/libcouchbase/src/dns-srv.cc +147 -0
- data/ext/libcouchbase/src/dump.cc +3 -3
- data/ext/libcouchbase/src/errmap.cc +173 -0
- data/ext/libcouchbase/src/errmap.h +198 -0
- data/ext/libcouchbase/src/getconfig.cc +7 -33
- data/ext/libcouchbase/src/handler.cc +118 -7
- data/ext/libcouchbase/src/hostlist.cc +0 -36
- data/ext/libcouchbase/src/hostlist.h +44 -62
- data/ext/libcouchbase/src/http/http-priv.h +125 -112
- data/ext/libcouchbase/src/http/http.cc +27 -35
- data/ext/libcouchbase/src/http/http.h +1 -34
- data/ext/libcouchbase/src/http/http_io.cc +28 -36
- data/ext/libcouchbase/src/instance.cc +131 -34
- data/ext/libcouchbase/src/internal.h +58 -26
- data/ext/libcouchbase/src/jsparse/parser.cc +136 -210
- data/ext/libcouchbase/src/jsparse/parser.h +84 -98
- data/ext/libcouchbase/src/lcbht/lcbht.cc +177 -0
- data/ext/libcouchbase/src/lcbht/lcbht.h +174 -163
- data/ext/libcouchbase/src/lcbio/connect.cc +569 -0
- data/ext/libcouchbase/src/lcbio/connect.h +16 -7
- data/ext/libcouchbase/src/lcbio/ctx.c +1 -1
- data/ext/libcouchbase/src/lcbio/iotable.h +101 -16
- data/ext/libcouchbase/src/lcbio/{ioutils.c → ioutils.cc} +30 -51
- data/ext/libcouchbase/src/lcbio/ioutils.h +29 -90
- data/ext/libcouchbase/src/lcbio/manager.cc +543 -0
- data/ext/libcouchbase/src/lcbio/manager.h +133 -96
- data/ext/libcouchbase/src/lcbio/protoctx.c +2 -2
- data/ext/libcouchbase/src/lcbio/timer-cxx.h +87 -0
- data/ext/libcouchbase/src/mc/mcreq.c +11 -2
- data/ext/libcouchbase/src/mc/mcreq.h +9 -2
- data/ext/libcouchbase/src/mcserver/mcserver.cc +175 -43
- data/ext/libcouchbase/src/mcserver/mcserver.h +9 -13
- data/ext/libcouchbase/src/mcserver/negotiate.cc +181 -62
- data/ext/libcouchbase/src/mcserver/negotiate.h +1 -3
- data/ext/libcouchbase/src/mctx-helper.h +51 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +1 -2
- data/ext/libcouchbase/src/n1ql/n1ql.cc +74 -42
- data/ext/libcouchbase/src/netbuf/netbuf.c +4 -4
- data/ext/libcouchbase/src/newconfig.cc +6 -6
- data/ext/libcouchbase/src/nodeinfo.cc +2 -2
- data/ext/libcouchbase/src/operations/{cbflush.c → cbflush.cc} +7 -15
- data/ext/libcouchbase/src/operations/{counter.c → counter.cc} +0 -0
- data/ext/libcouchbase/src/operations/durability.cc +6 -26
- data/ext/libcouchbase/src/operations/durability_internal.h +6 -3
- data/ext/libcouchbase/src/operations/{get.c → get.cc} +24 -26
- data/ext/libcouchbase/src/operations/{observe.c → observe.cc} +68 -93
- data/ext/libcouchbase/src/operations/{pktfwd.c → pktfwd.cc} +0 -0
- data/ext/libcouchbase/src/operations/{remove.c → remove.cc} +0 -0
- data/ext/libcouchbase/src/operations/stats.cc +3 -8
- data/ext/libcouchbase/src/operations/{store.c → store.cc} +27 -32
- data/ext/libcouchbase/src/operations/subdoc.cc +129 -42
- data/ext/libcouchbase/src/operations/{touch.c → touch.cc} +0 -0
- data/ext/libcouchbase/src/packetutils.h +30 -2
- data/ext/libcouchbase/src/probes.d +1 -1
- data/ext/libcouchbase/src/rdb/rope.c +1 -1
- data/ext/libcouchbase/src/{retrychk.c → retrychk.cc} +2 -3
- data/ext/libcouchbase/src/retryq.cc +52 -14
- data/ext/libcouchbase/src/retryq.h +3 -3
- data/ext/libcouchbase/src/settings.c +5 -0
- data/ext/libcouchbase/src/settings.h +11 -0
- data/ext/libcouchbase/src/ssl/ssl_c.c +1 -0
- data/ext/libcouchbase/src/ssl/ssl_common.c +2 -0
- data/ext/libcouchbase/src/ssl/ssl_e.c +0 -1
- data/ext/libcouchbase/src/strcodecs/strcodecs.h +1 -1
- data/ext/libcouchbase/src/trace.h +4 -4
- data/ext/libcouchbase/src/vbucket/vbucket.c +6 -10
- data/ext/libcouchbase/src/views/{docreq.c → docreq.cc} +48 -54
- data/ext/libcouchbase/src/views/docreq.h +24 -30
- data/ext/libcouchbase/src/views/viewreq.cc +318 -0
- data/ext/libcouchbase/src/views/viewreq.h +43 -13
- data/ext/libcouchbase/tests/basic/t_connstr.cc +88 -50
- data/ext/libcouchbase/tests/basic/t_creds.cc +47 -5
- data/ext/libcouchbase/tests/basic/t_host.cc +67 -75
- data/ext/libcouchbase/tests/basic/t_jsparse.cc +27 -82
- data/ext/libcouchbase/tests/basic/t_misc.cc +1 -1
- data/ext/libcouchbase/tests/basic/t_n1qlstrings.cc +0 -1
- data/ext/libcouchbase/tests/htparse/t_basic.cc +58 -78
- data/ext/libcouchbase/tests/ioserver/connection.cc +1 -1
- data/ext/libcouchbase/tests/ioserver/ioserver.cc +19 -6
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +28 -2
- data/ext/libcouchbase/tests/iotests/mock-environment.h +51 -1
- data/ext/libcouchbase/tests/iotests/t_behavior.cc +1 -7
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +97 -115
- data/ext/libcouchbase/tests/iotests/t_durability.cc +0 -1
- data/ext/libcouchbase/tests/iotests/t_eerrs.cc +119 -0
- data/ext/libcouchbase/tests/iotests/t_errmap.cc +178 -0
- data/ext/libcouchbase/tests/iotests/t_misc.cc +3 -3
- data/ext/libcouchbase/tests/iotests/t_netfail.cc +1 -1
- data/ext/libcouchbase/tests/iotests/t_obseqno.cc +0 -1
- data/ext/libcouchbase/tests/iotests/t_subdoc.cc +18 -11
- data/ext/libcouchbase/tests/mc/t_alloc.cc +9 -9
- data/ext/libcouchbase/tests/socktests/socktest.cc +7 -10
- data/ext/libcouchbase/tests/socktests/socktest.h +2 -3
- data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
- data/ext/libcouchbase/tests/socktests/t_manager.cc +5 -6
- data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
- data/ext/libcouchbase/tests/vbucket/confdata/ketama_expected.json +2562 -0
- data/ext/libcouchbase/tests/vbucket/confdata/memd_ketama_config.json +31 -0
- data/ext/libcouchbase/tests/vbucket/t_config.cc +35 -5
- data/ext/libcouchbase/tools/CMakeLists.txt +2 -2
- data/ext/libcouchbase/tools/cbc-handlers.h +128 -0
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +64 -10
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +2 -2
- data/ext/libcouchbase/tools/cbc.cc +143 -10
- data/ext/libcouchbase/tools/docgen/loc.h +1 -1
- data/lib/libcouchbase/connection.rb +4 -3
- data/lib/libcouchbase/version.rb +1 -1
- metadata +37 -28
- data/ext/libcouchbase/include/memcached/vbucket.h +0 -42
- data/ext/libcouchbase/src/bootstrap.c +0 -269
- data/ext/libcouchbase/src/bucketconfig/bc_file.c +0 -347
- data/ext/libcouchbase/src/bucketconfig/bc_http.c +0 -630
- data/ext/libcouchbase/src/bucketconfig/bc_mcraw.c +0 -150
- data/ext/libcouchbase/src/bucketconfig/confmon.c +0 -474
- data/ext/libcouchbase/src/lcbht/lcbht.c +0 -282
- data/ext/libcouchbase/src/lcbio/connect.c +0 -557
- data/ext/libcouchbase/src/lcbio/manager.c +0 -584
- data/ext/libcouchbase/src/packetutils.c +0 -37
- data/ext/libcouchbase/src/simplestring.c +0 -211
- data/ext/libcouchbase/src/simplestring.h +0 -228
- data/ext/libcouchbase/src/ssobuf.h +0 -82
- data/ext/libcouchbase/src/views/viewreq.c +0 -358
- data/ext/libcouchbase/tests/basic/t_string.cc +0 -112
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
#define LCBIO_MANAGER_H
|
|
20
20
|
#include "connect.h"
|
|
21
21
|
#include "settings.h"
|
|
22
|
-
#include "contrib/genhash/genhash.h"
|
|
23
22
|
#include "list.h"
|
|
23
|
+
#include "ioutils.h"
|
|
24
24
|
#include <stdio.h>
|
|
25
25
|
|
|
26
26
|
|
|
@@ -42,114 +42,151 @@
|
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
44
|
#ifdef __cplusplus
|
|
45
|
-
|
|
46
|
-
#endif
|
|
45
|
+
#include <map>
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
namespace lcb {
|
|
48
|
+
namespace io {
|
|
50
49
|
|
|
51
50
|
/** @brief Socket Pool */
|
|
52
|
-
|
|
53
|
-
genhash_t* ht;
|
|
54
|
-
lcb_settings *settings;
|
|
55
|
-
lcbio_pTABLE io;
|
|
51
|
+
class Pool;
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* before being closed
|
|
60
|
-
*/
|
|
61
|
-
uint32_t tmoidle;
|
|
62
|
-
unsigned maxtotal;
|
|
63
|
-
unsigned maxidle; /**< Maximum number of idle connections, per host */
|
|
64
|
-
unsigned refcount;
|
|
65
|
-
} lcbio_MGR;
|
|
53
|
+
/** @brief Pooled connection */
|
|
54
|
+
struct PoolConnInfo;
|
|
66
55
|
|
|
67
|
-
/**
|
|
68
|
-
|
|
69
|
-
* This function will increment the refcount on both the settings and table
|
|
70
|
-
* objects.
|
|
71
|
-
*/
|
|
72
|
-
LCB_INTERNAL_API
|
|
73
|
-
lcbio_MGR*
|
|
74
|
-
lcbio_mgr_create(lcb_settings *settings, lcbio_pTABLE io);
|
|
56
|
+
/** @brief Cancellable pool request */
|
|
57
|
+
struct PoolRequest;
|
|
75
58
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*/
|
|
80
|
-
LCB_INTERNAL_API
|
|
81
|
-
void
|
|
82
|
-
lcbio_mgr_destroy(lcbio_MGR *);
|
|
59
|
+
struct PoolHost;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
83
62
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
* of this function are by design similar to lcbio_connect() as they do the
|
|
87
|
-
* same things.
|
|
88
|
-
*
|
|
89
|
-
* @param mgr
|
|
90
|
-
* @param dest the host to connect to
|
|
91
|
-
* @param timeout amount of time to wait for a connection to be estblished
|
|
92
|
-
* @param handler a callback to invoke when the result is ready
|
|
93
|
-
* @param arg an argument passed to the callback
|
|
94
|
-
* @return a request handle which may be cancelled
|
|
95
|
-
* @see lcbio_connect()
|
|
96
|
-
*/
|
|
97
|
-
LCB_INTERNAL_API
|
|
98
|
-
struct lcbio_MGRREQ *
|
|
99
|
-
lcbio_mgr_get(lcbio_MGR *mgr, lcb_host_t *dest, uint32_t timeout,
|
|
100
|
-
lcbio_CONNDONE_cb handler, void *arg);
|
|
63
|
+
typedef lcb::io::Pool lcbio_MGR;
|
|
64
|
+
extern "C" {
|
|
101
65
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
*/
|
|
107
|
-
LCB_INTERNAL_API
|
|
108
|
-
void
|
|
109
|
-
lcbio_mgr_cancel(struct lcbio_MGRREQ *req);
|
|
66
|
+
#else
|
|
67
|
+
/* C only */
|
|
68
|
+
typedef struct lcbio_MGR_CDUMMY lcbio_MGR;
|
|
69
|
+
#endif
|
|
110
70
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* used and shall be available for reuse for another request. To verify these
|
|
114
|
-
* constraints, the socket's reference count must be one. Once the socket
|
|
115
|
-
* has been released its reference count should not be modified.
|
|
116
|
-
*/
|
|
117
|
-
LCB_INTERNAL_API
|
|
118
|
-
void lcbio_mgr_put(lcbio_SOCKET *sock);
|
|
71
|
+
#ifdef __cplusplus
|
|
72
|
+
}
|
|
119
73
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
74
|
+
namespace lcb {
|
|
75
|
+
namespace io {
|
|
76
|
+
class Pool {
|
|
77
|
+
public:
|
|
78
|
+
/**
|
|
79
|
+
* Create a socket pool controlled by the given settings and IO structure.
|
|
80
|
+
* This function will increment the refcount on both the settings and table
|
|
81
|
+
* objects.
|
|
82
|
+
*/
|
|
83
|
+
Pool(lcb_settings*, lcbio_pTABLE);
|
|
127
84
|
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
* many leased and/or open connections it can contain, when a connection receives
|
|
134
|
-
* an error it must either be discarded back to the pool (in which case the
|
|
135
|
-
* connection is cleaned up and is freed) or it must be detached (in which case
|
|
136
|
-
* the connection object itself still remains valid, but the pool does not know
|
|
137
|
-
* about it, and all its counters are restored, as with lcbio_mgr_discard()).
|
|
138
|
-
*
|
|
139
|
-
* lcbio_mgr_discard() itself is now implemented as the equivalent to:
|
|
140
|
-
* `lcbio_mgr_detach(mgr, conn)`;
|
|
141
|
-
*/
|
|
142
|
-
LCB_INTERNAL_API
|
|
143
|
-
void lcbio_mgr_detach(lcbio_SOCKET *sock);
|
|
85
|
+
/**
|
|
86
|
+
* Destroy the socket pool. Note that internally this just decrements the
|
|
87
|
+
* reference count. The object is only destroyed when its count hits zero.
|
|
88
|
+
*/
|
|
89
|
+
void shutdown();
|
|
144
90
|
|
|
145
|
-
/**
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Request a connection from the socket pool. The semantics and prototype
|
|
93
|
+
* of this function are by design similar to lcbio_connect() as they do the
|
|
94
|
+
* same things.
|
|
95
|
+
*
|
|
96
|
+
* @param dest the host to connect to
|
|
97
|
+
* @param timeout amount of time to wait for a connection to be estblished
|
|
98
|
+
* @param handler a callback to invoke when the result is ready
|
|
99
|
+
* @param arg an argument passed to the callback
|
|
100
|
+
* @return a request handle which may be cancelled
|
|
101
|
+
* @see lcbio_connect()
|
|
102
|
+
*/
|
|
103
|
+
ConnectionRequest* get(const lcb_host_t&, uint32_t, lcbio_CONNDONE_cb, void *);
|
|
150
104
|
|
|
151
|
-
|
|
152
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Release a socket back into the pool. This means the socket is no longer
|
|
107
|
+
* used and shall be available for reuse for another request. To verify these
|
|
108
|
+
* constraints, the socket's reference count must be one. Once the socket
|
|
109
|
+
* has been released its reference count should not be modified.
|
|
110
|
+
*/
|
|
111
|
+
static void put(lcbio_SOCKET *sock);
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Mark a slot as available but discard the current connection. This should be
|
|
115
|
+
* done if the connection itself is "dirty", i.e. has a protocol error on it
|
|
116
|
+
* or is otherwise not suitable for reuse
|
|
117
|
+
*/
|
|
118
|
+
static void discard(lcbio_SOCKET *sock);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Like lcbio_mgr_discard() except the source connection is left untouched. It
|
|
122
|
+
* is removed from the pool instead.
|
|
123
|
+
*
|
|
124
|
+
* Because the lcbio_MGR object itself has internal limits and thresholds on how
|
|
125
|
+
* many leased and/or open connections it can contain, when a connection receives
|
|
126
|
+
* an error it must either be discarded back to the pool (in which case the
|
|
127
|
+
* connection is cleaned up and is freed) or it must be detached (in which case
|
|
128
|
+
* the connection object itself still remains valid, but the pool does not know
|
|
129
|
+
* about it, and all its counters are restored, as with lcbio_mgr_discard()).
|
|
130
|
+
*
|
|
131
|
+
* lcbio_mgr_discard() itself is now implemented as the equivalent to:
|
|
132
|
+
* `lcbio_mgr_detach(mgr, conn)`;
|
|
133
|
+
*/
|
|
134
|
+
static void detach(lcbio_SOCKET *sock);
|
|
135
|
+
|
|
136
|
+
static bool is_from_pool(const lcbio_SOCKET *sock);
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Dumps the connection manager state to stderr
|
|
140
|
+
*/
|
|
141
|
+
void dump(FILE *) const;
|
|
142
|
+
|
|
143
|
+
inline void ref();
|
|
144
|
+
inline void unref();
|
|
145
|
+
|
|
146
|
+
struct Options {
|
|
147
|
+
Options() : maxtotal(0), maxidle(0), tmoidle(0) {
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Maximum *total* number of connections opened by the pool. If this
|
|
151
|
+
* number is exceeded, the pool will black hole future requests until
|
|
152
|
+
* a new slot becomes available.
|
|
153
|
+
*/
|
|
154
|
+
unsigned maxtotal;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Maximum number of idle connections to keep around
|
|
158
|
+
*/
|
|
159
|
+
unsigned maxidle;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The amount of time the pool should wait before closing idle
|
|
163
|
+
* connections. In microseconds
|
|
164
|
+
*/
|
|
165
|
+
uint32_t tmoidle;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
void set_options(const Options& opts) {
|
|
169
|
+
options = opts;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
Options& get_options() {
|
|
173
|
+
return options;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private:
|
|
177
|
+
friend struct PoolRequest;
|
|
178
|
+
friend struct PoolConnInfo;
|
|
179
|
+
friend struct PoolHost;
|
|
180
|
+
|
|
181
|
+
typedef std::map<std::string, PoolHost*> HostMap;
|
|
182
|
+
HostMap ht;
|
|
183
|
+
lcb_settings *settings;
|
|
184
|
+
lcbio_pTABLE io;
|
|
185
|
+
Options options;
|
|
186
|
+
unsigned refcount;
|
|
187
|
+
};
|
|
188
|
+
} // namespace io
|
|
189
|
+
} // namespace lcb
|
|
153
190
|
#endif
|
|
154
191
|
/**@}*/
|
|
155
192
|
|
|
@@ -24,9 +24,9 @@ lcbio_protoctx_add(lcbio_SOCKET *sock, lcbio_PROTOCTX *ctx)
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
lcbio_PROTOCTX *
|
|
27
|
-
lcbio_protoctx_get(lcbio_SOCKET *sock, lcbio_PROTOID id)
|
|
27
|
+
lcbio_protoctx_get(const lcbio_SOCKET *sock, lcbio_PROTOID id)
|
|
28
28
|
{
|
|
29
|
-
lcb_list_t *ll;
|
|
29
|
+
const lcb_list_t *ll;
|
|
30
30
|
LCB_LIST_FOR(ll, &sock->protos) {
|
|
31
31
|
lcbio_PROTOCTX *cur = LCB_LIST_ITEM(ll, lcbio_PROTOCTX, ll);
|
|
32
32
|
if (cur->id == id) {
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2016 Couchbase, Inc.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
#ifndef LCBIO_TIMER_CXX
|
|
18
|
+
#define LCBIO_TIMER_CXX
|
|
19
|
+
|
|
20
|
+
#include <lcbio/timer-ng.h>
|
|
21
|
+
#include <cstdlib>
|
|
22
|
+
|
|
23
|
+
namespace lcb {
|
|
24
|
+
namespace io {
|
|
25
|
+
|
|
26
|
+
class SimpleTimer {
|
|
27
|
+
public:
|
|
28
|
+
typedef void (Callback)(void*);
|
|
29
|
+
SimpleTimer(lcbio_pTABLE iot, void *data, Callback cb)
|
|
30
|
+
: inner(lcbio_timer_new(iot, data, cb)) {
|
|
31
|
+
}
|
|
32
|
+
~SimpleTimer() {
|
|
33
|
+
release();
|
|
34
|
+
}
|
|
35
|
+
void release() {
|
|
36
|
+
if (inner != NULL) {
|
|
37
|
+
lcbio_timer_destroy(inner);
|
|
38
|
+
inner = NULL;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
void signal() {
|
|
42
|
+
lcbio_async_signal(inner);
|
|
43
|
+
}
|
|
44
|
+
void cancel() {
|
|
45
|
+
lcbio_timer_disarm(inner);
|
|
46
|
+
}
|
|
47
|
+
bool is_armed() const {
|
|
48
|
+
return lcbio_timer_armed(inner);
|
|
49
|
+
}
|
|
50
|
+
void rearm(uint32_t usec) {
|
|
51
|
+
lcbio_timer_rearm(inner, usec);
|
|
52
|
+
}
|
|
53
|
+
void arm_if_disarmed(uint32_t usec) {
|
|
54
|
+
if (!is_armed()) {
|
|
55
|
+
rearm(usec);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
void dump(FILE *fp) const {
|
|
59
|
+
lcbio_timer_dump(inner, fp);
|
|
60
|
+
}
|
|
61
|
+
private:
|
|
62
|
+
lcbio_pTIMER inner;
|
|
63
|
+
SimpleTimer(const SimpleTimer&);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
template <typename T, void (T::*M)(void)>
|
|
67
|
+
class Timer : public SimpleTimer {
|
|
68
|
+
public:
|
|
69
|
+
Timer(lcbio_pTABLE iot, T* ptr)
|
|
70
|
+
: SimpleTimer(iot, ptr, cb) {
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
~Timer() {
|
|
74
|
+
release();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private:
|
|
78
|
+
static void cb(void *arg) {
|
|
79
|
+
T *obj = reinterpret_cast<T*>(arg);
|
|
80
|
+
(obj->*M)();
|
|
81
|
+
}
|
|
82
|
+
Timer(const Timer&);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
#endif
|
|
@@ -543,6 +543,15 @@ int
|
|
|
543
543
|
mcreq_pipeline_init(mc_PIPELINE *pipeline)
|
|
544
544
|
{
|
|
545
545
|
nb_SETTINGS settings;
|
|
546
|
+
|
|
547
|
+
/* Initialize all members to 0 */
|
|
548
|
+
memset(&pipeline->requests, 0, sizeof pipeline->requests);
|
|
549
|
+
pipeline->parent = NULL;
|
|
550
|
+
pipeline->flush_start = NULL;
|
|
551
|
+
pipeline->index = 0;
|
|
552
|
+
memset(&pipeline->ctxqueued, 0, sizeof pipeline->ctxqueued);
|
|
553
|
+
pipeline->buf_done_callback = NULL;
|
|
554
|
+
|
|
546
555
|
netbuf_default_settings(&settings);
|
|
547
556
|
|
|
548
557
|
/** Initialize datapool */
|
|
@@ -550,7 +559,7 @@ mcreq_pipeline_init(mc_PIPELINE *pipeline)
|
|
|
550
559
|
|
|
551
560
|
/** Initialize request pool */
|
|
552
561
|
settings.data_basealloc = sizeof(mc_PACKET) * 32;
|
|
553
|
-
netbuf_init(&pipeline->reqpool, &settings)
|
|
562
|
+
netbuf_init(&pipeline->reqpool, &settings);;
|
|
554
563
|
return 0;
|
|
555
564
|
}
|
|
556
565
|
|
|
@@ -911,7 +920,7 @@ mcreq_dump_packet(const mc_PACKET *packet, FILE *fp, mcreq_payload_dump_fn dumpf
|
|
|
911
920
|
fprintf(fp, "%sValue is user allocated\n", indent);
|
|
912
921
|
}
|
|
913
922
|
fprintf(fp, "%sValue: %p, %u bytes\n", indent,
|
|
914
|
-
SPAN_BUFFER(&packet->u_value.single), packet->u_value.single.size);
|
|
923
|
+
(void *)SPAN_BUFFER(&packet->u_value.single), packet->u_value.single.size);
|
|
915
924
|
}
|
|
916
925
|
}
|
|
917
926
|
|
|
@@ -179,10 +179,17 @@ typedef struct {
|
|
|
179
179
|
* packets, or when the packet itself is generated internally rather than
|
|
180
180
|
* on behalf of an API request.
|
|
181
181
|
*/
|
|
182
|
-
typedef struct {
|
|
182
|
+
typedef struct mc_REQDATAEX {
|
|
183
183
|
const void *cookie; /**< User data */
|
|
184
184
|
hrtime_t start; /**< Start time */
|
|
185
|
-
mc_REQDATAPROCS *procs; /**< Common routines for the packet */
|
|
185
|
+
const mc_REQDATAPROCS *procs; /**< Common routines for the packet */
|
|
186
|
+
|
|
187
|
+
#ifdef __cplusplus
|
|
188
|
+
mc_REQDATAEX(const void *cookie_,
|
|
189
|
+
const mc_REQDATAPROCS &procs_, hrtime_t start_)
|
|
190
|
+
: cookie(cookie_), start(start_), procs(&procs_) {
|
|
191
|
+
}
|
|
192
|
+
#endif
|
|
186
193
|
} mc_REQDATAEX;
|
|
187
194
|
|
|
188
195
|
/**
|
|
@@ -29,6 +29,8 @@
|
|
|
29
29
|
#define LOGARGS_T(lvl) LOGARGS(this, lvl)
|
|
30
30
|
|
|
31
31
|
#define LOGFMT "<%s:%s> (SRV=%p,IX=%d) "
|
|
32
|
+
#define PKTFMT "OP=0x%x, RC=0x%x, SEQ=%u"
|
|
33
|
+
#define PKTARGS(pkt) (pkt).opcode(), (pkt).status(), (pkt).opaque()
|
|
32
34
|
|
|
33
35
|
#define LOGID(server) get_ctx_host(server->connctx), get_ctx_port(server->connctx), (void*)server, server->index
|
|
34
36
|
#define LOGID_T() LOGID(this)
|
|
@@ -97,7 +99,7 @@ void
|
|
|
97
99
|
lcb_sched_flush(lcb_t instance)
|
|
98
100
|
{
|
|
99
101
|
for (size_t ii = 0; ii < LCBT_NSERVERS(instance); ii++) {
|
|
100
|
-
Server *server =
|
|
102
|
+
Server *server = instance->get_server(ii);
|
|
101
103
|
|
|
102
104
|
if (!server->has_pending()) {
|
|
103
105
|
continue;
|
|
@@ -120,8 +122,8 @@ Server::handle_nmv(MemcachedResponse& resinfo, mc_PACKET *oldpkt)
|
|
|
120
122
|
protocol_binary_request_header hdr;
|
|
121
123
|
lcb_error_t err = LCB_ERROR;
|
|
122
124
|
lcb_U16 vbid;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
lcb::clconfig::Provider *cccp =
|
|
126
|
+
instance->confmon->get_provider(lcb::clconfig::CLCONFIG_CCCP);
|
|
125
127
|
|
|
126
128
|
mcreq_read_hdr(oldpkt, &hdr);
|
|
127
129
|
vbid = ntohs(hdr.request.vbucket);
|
|
@@ -132,12 +134,12 @@ Server::handle_nmv(MemcachedResponse& resinfo, mc_PACKET *oldpkt)
|
|
|
132
134
|
|
|
133
135
|
if (resinfo.bodylen() && cccp->enabled) {
|
|
134
136
|
std::string s(resinfo.body<const char*>(), resinfo.vallen());
|
|
135
|
-
err =
|
|
137
|
+
err = lcb::clconfig::cccp_update(cccp, curhost->host, s.c_str());
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
if (err != LCB_SUCCESS) {
|
|
139
141
|
int bs_options;
|
|
140
|
-
if (instance->cur_configinfo->
|
|
142
|
+
if (instance->cur_configinfo->get_origin() == lcb::clconfig::CLCONFIG_CCCP) {
|
|
141
143
|
/**
|
|
142
144
|
* XXX: Not enough to see if cccp was enabled, since cccp might
|
|
143
145
|
* be requested by a user, but would still not actually be active
|
|
@@ -146,11 +148,11 @@ Server::handle_nmv(MemcachedResponse& resinfo, mc_PACKET *oldpkt)
|
|
|
146
148
|
*
|
|
147
149
|
* For this reason, we don't use if (cccp->enabled) {...}
|
|
148
150
|
*/
|
|
149
|
-
bs_options =
|
|
151
|
+
bs_options = BS_REFRESH_THROTTLE;
|
|
150
152
|
} else {
|
|
151
|
-
bs_options =
|
|
153
|
+
bs_options = BS_REFRESH_ALWAYS;
|
|
152
154
|
}
|
|
153
|
-
|
|
155
|
+
instance->bootstrap(bs_options);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
if (!lcb_should_retry(settings, oldpkt, LCB_NOT_MY_VBUCKET)) {
|
|
@@ -164,6 +166,124 @@ Server::handle_nmv(MemcachedResponse& resinfo, mc_PACKET *oldpkt)
|
|
|
164
166
|
return true;
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
/**
|
|
170
|
+
* Determine if this is an error code that we can pass to the user, or can
|
|
171
|
+
* otherwise handle "innately"
|
|
172
|
+
*/
|
|
173
|
+
static bool is_fastpath_error(uint16_t rc) {
|
|
174
|
+
switch (rc) {
|
|
175
|
+
case PROTOCOL_BINARY_RESPONSE_SUCCESS:
|
|
176
|
+
case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
|
|
177
|
+
case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
|
|
178
|
+
case PROTOCOL_BINARY_RESPONSE_E2BIG:
|
|
179
|
+
case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
|
|
180
|
+
case PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL:
|
|
181
|
+
case PROTOCOL_BINARY_RESPONSE_ERANGE:
|
|
182
|
+
case PROTOCOL_BINARY_RESPONSE_NOT_SUPPORTED:
|
|
183
|
+
case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
|
|
184
|
+
case PROTOCOL_BINARY_RESPONSE_ETMPFAIL:
|
|
185
|
+
case PROTOCOL_BINARY_RESPONSE_ENOMEM:
|
|
186
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_PATH_ENOENT:
|
|
187
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_PATH_EEXISTS:
|
|
188
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_PATH_MISMATCH:
|
|
189
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_PATH_EINVAL:
|
|
190
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_PATH_E2BIG:
|
|
191
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_VALUE_CANTINSERT:
|
|
192
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_VALUE_ETOODEEP:
|
|
193
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_DOC_NOTJSON:
|
|
194
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_NUM_ERANGE:
|
|
195
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_DELTA_ERANGE:
|
|
196
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_INVALID_COMBO:
|
|
197
|
+
case PROTOCOL_BINARY_RESPONSE_SUBDOC_MULTI_PATH_FAILURE:
|
|
198
|
+
case PROTOCOL_BINARY_RESPONSE_EACCESS:
|
|
199
|
+
return true;
|
|
200
|
+
default:
|
|
201
|
+
if (rc >= 0xc0 && rc <= 0xcc) {
|
|
202
|
+
// other subdoc?
|
|
203
|
+
return true;
|
|
204
|
+
} else {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#define ERRMAP_HANDLE_CONTINUE 0
|
|
212
|
+
#define ERRMAP_HANDLE_DISCONN 1
|
|
213
|
+
#define ERRMAP_HANDLE_RETRY 2
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Handle an unknown memcached error
|
|
217
|
+
*
|
|
218
|
+
* @param mcresp Response which contains the unknown error
|
|
219
|
+
* @param[out] newerr more user-friendly based on error map attributes
|
|
220
|
+
*
|
|
221
|
+
* @return true if this function handled the error specially (by disconnecting)
|
|
222
|
+
* or false if normal handling should continue.
|
|
223
|
+
*/
|
|
224
|
+
int Server::handle_unknown_error(const mc_PACKET *request,
|
|
225
|
+
const MemcachedResponse& mcresp,
|
|
226
|
+
lcb_error_t& newerr) {
|
|
227
|
+
|
|
228
|
+
if (!settings->errmap->isLoaded() || !settings->use_errmap) {
|
|
229
|
+
// If there's no error map, just return false
|
|
230
|
+
return ERRMAP_HANDLE_CONTINUE;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Look up the error map definition for this error
|
|
234
|
+
const errmap::Error& err = settings->errmap->getError(mcresp.status());
|
|
235
|
+
|
|
236
|
+
if (!err.isValid() || err.hasAttribute(errmap::SPECIAL_HANDLING)) {
|
|
237
|
+
lcb_log(LOGARGS_T(ERR), LOGFMT "Received error not in error map or requires special handling! " PKTFMT, LOGID_T(), PKTARGS(mcresp));
|
|
238
|
+
lcbio_ctx_senderr(connctx, LCB_PROTOCOL_ERROR);
|
|
239
|
+
return ERRMAP_HANDLE_DISCONN;
|
|
240
|
+
} else {
|
|
241
|
+
lcb_log(LOGARGS_T(WARN), LOGFMT "Received server error %s (0x%x) on packet: " PKTFMT, LOGID_T(), err.shortname.c_str(), err.code, PKTARGS(mcresp));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (err.hasAttribute(errmap::FETCH_CONFIG)) {
|
|
245
|
+
instance->bootstrap(BS_REFRESH_THROTTLE);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (err.hasAttribute(errmap::TEMPORARY)) {
|
|
249
|
+
newerr = LCB_GENERIC_TMPERR;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (err.hasAttribute(errmap::CONSTRAINT_FAILURE)) {
|
|
253
|
+
newerr = LCB_GENERIC_CONSTRAINT_ERR;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (err.hasAttribute(errmap::AUTH)) {
|
|
257
|
+
newerr = LCB_AUTH_ERROR;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (err.hasAttribute(errmap::SUBDOC) && newerr == LCB_SUCCESS) {
|
|
261
|
+
newerr = LCB_GENERIC_SUBDOCERR;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
int rv = 0;
|
|
265
|
+
|
|
266
|
+
if (err.hasAttribute(errmap::AUTO_RETRY)) {
|
|
267
|
+
errmap::RetrySpec *spec = err.getRetrySpec();
|
|
268
|
+
|
|
269
|
+
mc_PACKET *newpkt = mcreq_renew_packet(request);
|
|
270
|
+
newpkt->flags &= ~MCREQ_STATE_FLAGS;
|
|
271
|
+
instance->retryq->add((mc_EXPACKET *)newpkt, newerr ? newerr : LCB_ERROR, spec);
|
|
272
|
+
rv |= ERRMAP_HANDLE_RETRY;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (err.hasAttribute(errmap::CONN_STATE_INVALIDATED)) {
|
|
276
|
+
if (newerr != LCB_SUCCESS) {
|
|
277
|
+
newerr = LCB_ERROR;
|
|
278
|
+
}
|
|
279
|
+
lcbio_ctx_senderr(connctx, newerr);
|
|
280
|
+
rv |= ERRMAP_HANDLE_DISCONN;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return rv;
|
|
284
|
+
|
|
285
|
+
}
|
|
286
|
+
|
|
167
287
|
/* This function is called within a loop to process a single packet.
|
|
168
288
|
*
|
|
169
289
|
* If a full packet is available, it will process the packet and return
|
|
@@ -219,12 +339,20 @@ Server::try_read(lcbio_CTX *ctx, rdb_IOROPE *ior)
|
|
|
219
339
|
}
|
|
220
340
|
|
|
221
341
|
if (!request) {
|
|
222
|
-
lcb_log(LOGARGS_T(WARN), LOGFMT "
|
|
342
|
+
lcb_log(LOGARGS_T(WARN), LOGFMT "Server sent us reply for a timed-out command. (OP=0x%x, RC=0x%x, SEQ=%u)", LOGID_T(), mcresp.opcode(), mcresp.status(), mcresp.opaque());
|
|
223
343
|
rdb_consumed(ior, pktsize);
|
|
224
344
|
return PKT_READ_COMPLETE;
|
|
225
345
|
}
|
|
226
346
|
|
|
227
|
-
|
|
347
|
+
lcb_error_t err_override = LCB_SUCCESS;
|
|
348
|
+
ReadState rdstate = PKT_READ_COMPLETE;
|
|
349
|
+
int unknown_err_rv;
|
|
350
|
+
|
|
351
|
+
/* Check if the status code is one which must be handled carefully by the
|
|
352
|
+
* client */
|
|
353
|
+
if (is_fastpath_error(mcresp.status())) {
|
|
354
|
+
// Nothing here!
|
|
355
|
+
} else if (mcresp.status() == PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET) {
|
|
228
356
|
/* consume the header */
|
|
229
357
|
DO_ASSIGN_PAYLOAD()
|
|
230
358
|
if (!handle_nmv(mcresp, request)) {
|
|
@@ -232,13 +360,25 @@ Server::try_read(lcbio_CTX *ctx, rdb_IOROPE *ior)
|
|
|
232
360
|
}
|
|
233
361
|
DO_SWALLOW_PAYLOAD()
|
|
234
362
|
goto GT_DONE;
|
|
363
|
+
} else if ((unknown_err_rv =
|
|
364
|
+
handle_unknown_error(request, mcresp, err_override)) !=
|
|
365
|
+
ERRMAP_HANDLE_CONTINUE) {
|
|
366
|
+
DO_ASSIGN_PAYLOAD()
|
|
367
|
+
if (!(unknown_err_rv & ERRMAP_HANDLE_RETRY)) {
|
|
368
|
+
mcreq_dispatch_response(this, request, &mcresp, err_override);
|
|
369
|
+
}
|
|
370
|
+
DO_SWALLOW_PAYLOAD()
|
|
371
|
+
if (unknown_err_rv & ERRMAP_HANDLE_DISCONN) {
|
|
372
|
+
rdstate = PKT_READ_ABORT;
|
|
373
|
+
}
|
|
374
|
+
goto GT_DONE;
|
|
235
375
|
}
|
|
236
376
|
|
|
237
377
|
/* Figure out if the request is 'ufwd' or not */
|
|
238
378
|
if (!(request->flags & MCREQ_F_UFWD)) {
|
|
239
379
|
DO_ASSIGN_PAYLOAD();
|
|
240
380
|
mcresp.bufh = rdb_get_first_segment(ior);
|
|
241
|
-
mcreq_dispatch_response(this, request, &mcresp,
|
|
381
|
+
mcreq_dispatch_response(this, request, &mcresp, err_override);
|
|
242
382
|
DO_SWALLOW_PAYLOAD()
|
|
243
383
|
|
|
244
384
|
} else {
|
|
@@ -265,7 +405,7 @@ Server::try_read(lcbio_CTX *ctx, rdb_IOROPE *ior)
|
|
|
265
405
|
if (is_last) {
|
|
266
406
|
mcreq_packet_handled(this, request);
|
|
267
407
|
}
|
|
268
|
-
return
|
|
408
|
+
return rdstate;
|
|
269
409
|
}
|
|
270
410
|
|
|
271
411
|
static void
|
|
@@ -307,7 +447,8 @@ Server::maybe_retry_packet(mc_PACKET *pkt, lcb_error_t err)
|
|
|
307
447
|
|
|
308
448
|
mc_PACKET *newpkt = mcreq_renew_packet(pkt);
|
|
309
449
|
newpkt->flags &= ~MCREQ_STATE_FLAGS;
|
|
310
|
-
|
|
450
|
+
// TODO: Load the 4th argument from the error map
|
|
451
|
+
instance->retryq->add((mc_EXPACKET *)newpkt, err, NULL);
|
|
311
452
|
return true;
|
|
312
453
|
}
|
|
313
454
|
|
|
@@ -340,7 +481,7 @@ void Server::purge_single(mc_PACKET *pkt, lcb_error_t err) {
|
|
|
340
481
|
hdr.request.opaque,
|
|
341
482
|
PROTOCOL_BINARY_RESPONSE_EINVAL);
|
|
342
483
|
|
|
343
|
-
lcb_log(LOGARGS_T(WARN), LOGFMT "Failing command (pkt=%p, opaque=%lu, opcode=0x%x) with error
|
|
484
|
+
lcb_log(LOGARGS_T(WARN), LOGFMT "Failing command (pkt=%p, opaque=%lu, opcode=0x%x) with error %s", LOGID_T(), (void*)pkt, (unsigned long)pkt->opaque, hdr.request.opcode, lcb_strerror_short(err));
|
|
344
485
|
int rv = mcreq_dispatch_response(this, pkt, &resp, err);
|
|
345
486
|
lcb_assert(rv == 0);
|
|
346
487
|
}
|
|
@@ -365,8 +506,7 @@ Server::purge(lcb_error_t error, hrtime_t thresh, hrtime_t *next,
|
|
|
365
506
|
}
|
|
366
507
|
|
|
367
508
|
if (affected || policy == REFRESH_ALWAYS) {
|
|
368
|
-
|
|
369
|
-
LCB_BS_REFRESH_THROTTLE|LCB_BS_REFRESH_INCRERR);
|
|
509
|
+
instance->bootstrap(BS_REFRESH_THROTTLE|BS_REFRESH_INCRERR);
|
|
370
510
|
}
|
|
371
511
|
return affected;
|
|
372
512
|
}
|
|
@@ -420,7 +560,7 @@ void Server::io_timeout()
|
|
|
420
560
|
}
|
|
421
561
|
|
|
422
562
|
uint32_t next_us = next_timeout();
|
|
423
|
-
lcb_log(LOGARGS_T(
|
|
563
|
+
lcb_log(LOGARGS_T(TRACE), LOGFMT "Scheduling next timeout for %u ms. This is not an error", LOGID_T(), next_us / 1000);
|
|
424
564
|
lcbio_timer_rearm(io_timer, next_us);
|
|
425
565
|
lcb_maybe_breakout(instance);
|
|
426
566
|
}
|
|
@@ -462,10 +602,10 @@ static void mcserver_flush(Server *s) { s->flush(); }
|
|
|
462
602
|
void
|
|
463
603
|
Server::handle_connected(lcbio_SOCKET *sock, lcb_error_t err, lcbio_OSERR syserr)
|
|
464
604
|
{
|
|
465
|
-
|
|
605
|
+
connreq = NULL;
|
|
466
606
|
|
|
467
607
|
if (err != LCB_SUCCESS) {
|
|
468
|
-
lcb_log(LOGARGS_T(ERR), LOGFMT "
|
|
608
|
+
lcb_log(LOGARGS_T(ERR), LOGFMT "Connection attempt failed. Received %s from libcouchbase, received %d from operating system", LOGID_T(), lcb_strerror_short(err), syserr);
|
|
469
609
|
if (!maybe_reconnect_on_fake_timeout(err)) {
|
|
470
610
|
socket_failed(err);
|
|
471
611
|
}
|
|
@@ -478,9 +618,8 @@ Server::handle_connected(lcbio_SOCKET *sock, lcb_error_t err, lcbio_OSERR syserr
|
|
|
478
618
|
SessionInfo* sessinfo = SessionInfo::get(sock);
|
|
479
619
|
if (sessinfo == NULL) {
|
|
480
620
|
lcb_log(LOGARGS_T(TRACE), "<%s:%s> (SRV=%p) Session not yet negotiated. Negotiating", curhost->host, curhost->port, (void*)this);
|
|
481
|
-
|
|
621
|
+
connreq = SessionRequest::start(
|
|
482
622
|
sock, settings, default_timeout(), on_connected, this);
|
|
483
|
-
LCBIO_CONNREQ_MKGENERIC(&connreq, sreq, lcb::sessreq_cancel);
|
|
484
623
|
return;
|
|
485
624
|
} else {
|
|
486
625
|
compsupport = sessinfo->has_feature(PROTOCOL_BINARY_FEATURE_DATATYPE);
|
|
@@ -494,10 +633,9 @@ Server::handle_connected(lcbio_SOCKET *sock, lcb_error_t err, lcbio_OSERR syserr
|
|
|
494
633
|
procs.cb_flush_ready = on_flush_ready;
|
|
495
634
|
connctx = lcbio_ctx_new(sock, this, &procs);
|
|
496
635
|
connctx->subsys = "memcached";
|
|
497
|
-
|
|
636
|
+
flush_start = (mcreq_flushstart_fn)mcserver_flush;
|
|
498
637
|
|
|
499
638
|
uint32_t tmo = next_timeout();
|
|
500
|
-
lcb_log(LOGARGS_T(DEBUG), LOGFMT "Setting initial timeout=%ums", LOGID_T(), tmo/1000);
|
|
501
639
|
lcbio_timer_rearm(io_timer, tmo);
|
|
502
640
|
flush();
|
|
503
641
|
}
|
|
@@ -505,10 +643,9 @@ Server::handle_connected(lcbio_SOCKET *sock, lcb_error_t err, lcbio_OSERR syserr
|
|
|
505
643
|
void
|
|
506
644
|
Server::connect()
|
|
507
645
|
{
|
|
508
|
-
|
|
646
|
+
connreq = instance->memd_sockpool->get(*curhost,
|
|
509
647
|
default_timeout(), on_connected, this);
|
|
510
|
-
|
|
511
|
-
mc_PIPELINE::flush_start = flush_noop;
|
|
648
|
+
flush_start = flush_noop;
|
|
512
649
|
state = Server::S_CLEAN;
|
|
513
650
|
}
|
|
514
651
|
|
|
@@ -520,7 +657,7 @@ buf_done_cb(mc_PIPELINE *pl, const void *cookie, void *, void *)
|
|
|
520
657
|
}
|
|
521
658
|
|
|
522
659
|
Server::Server(lcb_t instance_, int ix)
|
|
523
|
-
: state(S_CLEAN),
|
|
660
|
+
: mc_PIPELINE(), state(S_CLEAN),
|
|
524
661
|
io_timer(lcbio_timer_new(instance_->iotable, this, timeout_server)),
|
|
525
662
|
instance(instance_),
|
|
526
663
|
settings(lcb_settings_ref2(instance_->settings)),
|
|
@@ -529,11 +666,10 @@ Server::Server(lcb_t instance_, int ix)
|
|
|
529
666
|
connctx(NULL),
|
|
530
667
|
curhost(new lcb_host_t())
|
|
531
668
|
{
|
|
532
|
-
std::memset(static_cast<mc_PIPELINE*>(this), 0, sizeof(mc_PIPELINE));
|
|
533
669
|
mcreq_pipeline_init(this);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
670
|
+
flush_start = (mcreq_flushstart_fn)server_connect;
|
|
671
|
+
buf_done_callback = buf_done_cb;
|
|
672
|
+
index = ix;
|
|
537
673
|
|
|
538
674
|
std::memset(&connreq, 0, sizeof connreq);
|
|
539
675
|
std::memset(curhost, 0, sizeof *curhost);
|
|
@@ -550,7 +686,7 @@ Server::Server(lcb_t instance_, int ix)
|
|
|
550
686
|
Server::Server()
|
|
551
687
|
: state(S_TEMPORARY),
|
|
552
688
|
io_timer(NULL), instance(NULL), settings(NULL), compsupport(0),
|
|
553
|
-
mutation_tokens(0), connctx(NULL), curhost(NULL)
|
|
689
|
+
mutation_tokens(0), connctx(NULL), connreq(NULL), curhost(NULL)
|
|
554
690
|
{
|
|
555
691
|
}
|
|
556
692
|
|
|
@@ -573,14 +709,14 @@ static void
|
|
|
573
709
|
close_cb(lcbio_SOCKET *sock, int, void *)
|
|
574
710
|
{
|
|
575
711
|
lcbio_ref(sock);
|
|
576
|
-
|
|
712
|
+
lcb::io::Pool::discard(sock);
|
|
577
713
|
}
|
|
578
714
|
|
|
579
715
|
static void
|
|
580
716
|
on_error(lcbio_CTX *ctx, lcb_error_t err)
|
|
581
717
|
{
|
|
582
718
|
Server *server = Server::get(ctx);
|
|
583
|
-
lcb_log(LOGARGS(server, WARN), LOGFMT "Got socket error
|
|
719
|
+
lcb_log(LOGARGS(server, WARN), LOGFMT "Got socket error %s", LOGID(server), lcb_strerror_short(err));
|
|
584
720
|
if (server->check_closed()) {
|
|
585
721
|
return;
|
|
586
722
|
}
|
|
@@ -622,7 +758,7 @@ Server::start_errored_ctx(State next_state)
|
|
|
622
758
|
|
|
623
759
|
state = next_state;
|
|
624
760
|
/* Cancel any pending connection attempt? */
|
|
625
|
-
|
|
761
|
+
lcb::io::ConnectionRequest::cancel(&connreq);
|
|
626
762
|
|
|
627
763
|
/* If the server is being destroyed, silence the timer */
|
|
628
764
|
if (next_state == Server::S_CLOSED && io_timer != NULL) {
|
|
@@ -636,13 +772,15 @@ Server::start_errored_ctx(State next_state)
|
|
|
636
772
|
return;
|
|
637
773
|
} else {
|
|
638
774
|
/* Not closed but don't have a current context */
|
|
639
|
-
mc_PIPELINE::flush_start = (mcreq_flushstart_fn)server_connect;
|
|
640
775
|
if (has_pending()) {
|
|
641
776
|
if (!lcbio_timer_armed(io_timer)) {
|
|
642
777
|
/* TODO: Maybe throttle reconnection attempts? */
|
|
643
778
|
lcbio_timer_rearm(io_timer, default_timeout());
|
|
644
779
|
}
|
|
645
780
|
connect();
|
|
781
|
+
} else {
|
|
782
|
+
// Connect once someone actually wants a connection.
|
|
783
|
+
flush_start = (mcreq_flushstart_fn)server_connect;
|
|
646
784
|
}
|
|
647
785
|
}
|
|
648
786
|
|
|
@@ -656,7 +794,7 @@ Server::start_errored_ctx(State next_state)
|
|
|
656
794
|
/* Close the socket not to leak resources */
|
|
657
795
|
lcbio_shutdown(lcbio_ctx_sock(ctx));
|
|
658
796
|
if (next_state == Server::S_ERRDRAIN) {
|
|
659
|
-
|
|
797
|
+
flush_start = (mcreq_flushstart_fn)flush_errdrain;
|
|
660
798
|
}
|
|
661
799
|
} else {
|
|
662
800
|
finalize_errored_ctx();
|
|
@@ -701,7 +839,6 @@ Server::finalize_errored_ctx()
|
|
|
701
839
|
/* Otherwise, cycle the state back to CLEAN and reinit
|
|
702
840
|
* the connection */
|
|
703
841
|
state = Server::S_CLEAN;
|
|
704
|
-
mc_PIPELINE::flush_start = (mcreq_flushstart_fn)server_connect;
|
|
705
842
|
connect();
|
|
706
843
|
}
|
|
707
844
|
}
|
|
@@ -723,8 +860,3 @@ Server::check_closed()
|
|
|
723
860
|
finalize_errored_ctx();
|
|
724
861
|
return 1;
|
|
725
862
|
}
|
|
726
|
-
|
|
727
|
-
int
|
|
728
|
-
mcserver_supports_compression(mc_SERVER *server) {
|
|
729
|
-
return server->compsupport;
|
|
730
|
-
}
|