libcouchbase 0.3.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
}
|