p9y: bsd
[m6w6/libmemcached] / src / libmemcached / instance.cc
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcached/common.h"
17
18 static inline void _server_init(memcached_instance_st *self, Memcached *root,
19 const memcached_string_t &hostname, in_port_t port, uint32_t weight,
20 memcached_connection_t type) {
21 self->options.is_shutting_down = false;
22 self->options.is_dead = false;
23 self->options.ready = false;
24 self->_events = 0;
25 self->_revents = 0;
26 self->cursor_active_ = 0;
27 self->port_ = port;
28 self->fd = INVALID_SOCKET;
29 self->io_bytes_sent = 0;
30 self->request_id = 0;
31 self->server_failure_counter = 0;
32 self->server_failure_counter_query_id = 0;
33 self->server_timeout_counter = 0;
34 self->server_timeout_counter_query_id = 0;
35 self->weight = weight ? weight : 1; // 1 is the default weight value
36 self->io_wait_count.read = 0;
37 self->io_wait_count.write = 0;
38 self->io_wait_count.timeouts = 0;
39 self->io_wait_count._bytes_read = 0;
40 self->major_version = UINT8_MAX;
41 self->micro_version = UINT8_MAX;
42 self->minor_version = UINT8_MAX;
43 self->type = type;
44 self->error_messages = NULL;
45 self->read_ptr = self->read_buffer;
46 self->read_buffer_length = 0;
47 self->write_buffer_offset = 0;
48 self->address_info = NULL;
49 self->address_info_next = NULL;
50
51 self->state = MEMCACHED_SERVER_STATE_NEW;
52 self->next_retry = 0;
53
54 self->root = root;
55 if (root) {
56 self->version = ++root->server_info.version;
57 } else {
58 self->version = UINT_MAX;
59 }
60 self->limit_maxbytes = 0;
61 self->hostname(hostname);
62 }
63
64 static memcached_instance_st *_server_create(memcached_instance_st *self,
65 const memcached_st *memc) {
66 if (self == NULL) {
67 self = libmemcached_xmalloc(memc, memcached_instance_st);
68
69 if (self == NULL) {
70 return NULL; /* MEMCACHED_MEMORY_ALLOCATION_FAILURE */
71 }
72
73 self->options.is_allocated = true;
74 } else {
75 self->options.is_allocated = false;
76 }
77
78 self->options.is_initialized = true;
79
80 return self;
81 }
82
83 void memcached_instance_st::events(short arg) {
84 if ((_events | arg) == _events) {
85 return;
86 }
87
88 _events |= arg;
89 }
90
91 void memcached_instance_st::revents(short arg) {
92 if (arg) {
93 options.ready = true;
94 }
95
96 _revents = arg;
97 _events &= short(~arg);
98 }
99
100 memcached_instance_st *__instance_create_with(memcached_st *memc, memcached_instance_st *self,
101 const memcached_string_t &hostname,
102 const in_port_t port, uint32_t weight,
103 const memcached_connection_t type) {
104 if (memcached_is_valid_servername(hostname) == false) {
105 memcached_set_error(*memc, MEMCACHED_INVALID_ARGUMENTS, MEMCACHED_AT,
106 memcached_literal_param("Invalid hostname provided"));
107 return NULL;
108 }
109
110 self = _server_create(self, memc);
111
112 if (self == NULL) {
113 return NULL;
114 }
115
116 _server_init(self, const_cast<memcached_st *>(memc), hostname, port, weight, type);
117
118 if (memc and memcached_is_udp(memc)) {
119 self->write_buffer_offset = UDP_DATAGRAM_HEADER_LENGTH;
120 memcached_io_init_udp_header(self, 0);
121 }
122
123 return self;
124 }
125
126 void __instance_free(memcached_instance_st *self) {
127 memcached_quit_server(self, false);
128
129 self->clear_addrinfo();
130 assert(self->address_info_next == NULL);
131
132 memcached_error_free(*self);
133
134 if (memcached_is_allocated(self)) {
135 libmemcached_free(self->root, self);
136 } else {
137 self->options.is_initialized = false;
138 }
139 }
140
141 void memcached_instance_free(memcached_instance_st *self) {
142 if (self) {
143 __instance_free(self);
144 }
145 }
146
147 memcached_return_t memcached_server_cursor(const memcached_st *shell,
148 const memcached_server_fn *callback, void *context,
149 uint32_t number_of_callbacks) {
150 const Memcached *memc = memcached2Memcached(shell);
151 memcached_return_t rc;
152 if (memcached_failed(rc = initialize_const_query(memc))) {
153 return rc;
154 }
155
156 size_t errors = 0;
157 for (uint32_t x = 0; x < memcached_instance_list_count(memc); x++) {
158 memcached_instance_st *instance = memcached_instance_by_position(memc, x);
159
160 for (uint32_t y = 0; y < number_of_callbacks; y++) {
161 memcached_return_t ret = (*callback[y])(memc, instance, context);
162
163 if (memcached_failed(ret)) {
164 errors++;
165 continue;
166 }
167 }
168 }
169
170 return errors ? MEMCACHED_SOME_ERRORS : MEMCACHED_SUCCESS;
171 }
172
173 memcached_return_t memcached_server_execute(memcached_st *memc,
174 memcached_server_execute_fn callback, void *context) {
175 if (callback == NULL) {
176 return MEMCACHED_INVALID_ARGUMENTS;
177 }
178
179 bool some_errors = false;
180 ;
181 for (uint32_t x = 0; x < memcached_instance_list_count(memc); x++) {
182 memcached_instance_st *instance = memcached_instance_fetch(memc, x);
183
184 memcached_return_t rc = (*callback)(memc, instance, context);
185 if (rc == MEMCACHED_INVALID_ARGUMENTS) {
186 return rc;
187 } else if (memcached_fatal(rc)) {
188 some_errors = true;
189 }
190 }
191
192 (void) some_errors;
193 return MEMCACHED_SUCCESS;
194 }
195
196 const memcached_instance_st *memcached_server_by_key(memcached_st *shell, const char *key,
197 size_t key_length, memcached_return_t *error) {
198 Memcached *memc = memcached2Memcached(shell);
199 memcached_return_t unused;
200 if (error == NULL) {
201 error = &unused;
202 }
203
204 memcached_return_t rc;
205 if (memcached_failed(rc = initialize_const_query(memc))) {
206 *error = rc;
207 return NULL;
208 }
209
210 if (memcached_failed((memcached_key_test(*memc, (const char **) &key, &key_length, 1)))) {
211 *error = memcached_last_error(memc);
212 return NULL;
213 }
214
215 uint32_t server_key = memcached_generate_hash(memc, key, key_length);
216 return memcached_instance_by_position(memc, server_key);
217 }
218
219 /*
220 If we do not have a valid object to clone from, we toss an error.
221 */
222 static memcached_instance_st *memcached_instance_clone(memcached_instance_st *source) {
223 /* We just do a normal create if source is missing */
224 if (source == NULL) {
225 return NULL;
226 }
227
228 memcached_string_t hostname_ = {memcached_string_make_from_cstr(source->hostname())};
229 return __instance_create_with(source->root, NULL, hostname_, source->port(), source->weight,
230 source->type);
231 }
232
233 void set_last_disconnected_host(memcached_instance_st *self) {
234 assert(self->root);
235 if (self->root) {
236 if (memcached_server_get_last_disconnect(self->root)
237 and memcached_server_get_last_disconnect(self->root)->version == self->version)
238 {
239 return;
240 }
241
242 // const_cast
243 memcached_st *root = (memcached_st *) self->root;
244
245 memcached_instance_free((memcached_instance_st *) (root->last_disconnected_server));
246
247 // We set is_parsing so that no lookup happens
248 root->state.is_parsing = true;
249 root->last_disconnected_server = memcached_instance_clone(self);
250 root->state.is_parsing = false;
251
252 ((memcached_instance_st *) memcached_server_get_last_disconnect(root))->version = self->version;
253 }
254 }
255
256 const memcached_instance_st *memcached_server_get_last_disconnect(const memcached_st *shell) {
257 const Memcached *self = memcached2Memcached(shell);
258 if (self) {
259 return (const memcached_instance_st *) self->last_disconnected_server;
260 }
261
262 return 0;
263 }
264
265 void memcached_instance_next_retry(const memcached_instance_st *self, const time_t absolute_time) {
266 WATCHPOINT_ASSERT(self);
267 if (self) {
268 ((memcached_instance_st *) self)->next_retry = absolute_time;
269 }
270 }
271
272 bool memcached_instance_st::valid() const {
273 if (fd == INVALID_SOCKET) {
274 return false;
275 }
276
277 return true;
278 }
279
280 bool memcached_instance_st::is_shutting_down() const {
281 return options.is_shutting_down;
282 }