All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
as_event_internal.h
Go to the documentation of this file.
1 /*
2  * Copyright 2008-2016 Aerospike, Inc.
3  *
4  * Portions may be licensed to Aerospike, Inc. under one or more contributor
5  * license agreements.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
8  * use this file except in compliance with the License. You may obtain a copy of
9  * the License at http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14  * License for the specific language governing permissions and limitations under
15  * the License.
16  */
17 #pragma once
18 
19 #include <aerospike/as_admin.h>
20 #include <aerospike/as_cluster.h>
21 #include <aerospike/as_queue.h>
22 #include <aerospike/as_proto.h>
23 #include <aerospike/as_socket.h>
24 #include <citrusleaf/cf_ll.h>
25 #include <pthread.h>
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include <unistd.h>
29 
30 #if defined(AS_USE_LIBEV)
31 #include <ev.h>
32 #elif defined(AS_USE_LIBUV)
33 #include <uv.h>
34 #else
35 #endif
36 
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40 
41 /******************************************************************************
42  * TYPES
43  *****************************************************************************/
44 
45 #define AS_ASYNC_STATE_UNREGISTERED 0
46 #define AS_ASYNC_STATE_AUTH_WRITE 1
47 #define AS_ASYNC_STATE_AUTH_READ_HEADER 2
48 #define AS_ASYNC_STATE_AUTH_READ_BODY 4
49 #define AS_ASYNC_STATE_WRITE 8
50 #define AS_ASYNC_STATE_READ_HEADER 16
51 #define AS_ASYNC_STATE_READ_BODY 32
52 
53 #define AS_ASYNC_AUTH_RETURN_CODE 1
54 
55 #define AS_EVENT_CONNECTION_COMPLETE 0
56 #define AS_EVENT_CONNECTION_PENDING 1
57 #define AS_EVENT_CONNECTION_ERROR 2
58 
59 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
60 
61 struct as_event_command;
62 struct as_event_executor;
63 
64 typedef struct {
65 #if defined(AS_USE_LIBEV)
66  struct ev_io watcher;
67  int fd;
68 #elif defined(AS_USE_LIBUV)
69  uv_tcp_t socket;
70 
71  // Reuse memory for requests, because only one request is active at a time.
72  union {
73  uv_connect_t connect;
74  uv_write_t write;
75  } req;
76 #else
77 #endif
78  bool pipeline;
80 
81 typedef struct {
85 
86 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
87 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor, as_error* err);
88 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
89 
90 typedef struct as_event_command {
91 #if defined(AS_USE_LIBEV)
92  struct ev_timer timer;
93 #elif defined(AS_USE_LIBUV)
94  uv_timer_t timer;
95 #else
96 #endif
101  void* udata;
103  cf_ll_element pipe_link;
104 
105  uint8_t* buf;
106  uint32_t capacity;
107  uint32_t len;
108  uint32_t pos;
109  uint32_t auth_len;
110  uint32_t timeout_ms;
111 
112  uint8_t type;
113  uint8_t state;
114  bool pipeline;
116  bool free_buf;
118 
119 typedef struct as_event_executor {
120  pthread_mutex_t lock;
124  void* udata;
125  uint32_t max_concurrent;
126  uint32_t max;
127  uint32_t count;
128  bool valid;
130 
131 /******************************************************************************
132  * GLOBAL VARIABLES
133  *****************************************************************************/
134 
136 extern uint32_t as_event_loop_size;
137 extern uint32_t as_event_loop_current;
138 
139 /******************************************************************************
140  * COMMON FUNCTIONS
141  *****************************************************************************/
142 
143 as_status
145 
146 void
148 
149 void
150 as_event_executor_cancel(as_event_executor* executor, int queued_count);
151 
152 bool
154 
155 int
157 
158 void
160 
161 void
163 
164 void
166 
167 void
169 
170 void
172 
173 bool
175 
176 bool
178 
179 bool
181 
182 /******************************************************************************
183  * IMPLEMENTATION SPECIFIC FUNCTIONS
184  *****************************************************************************/
185 
186 bool
188 
189 void
191 
192 bool
194 
195 void
197 
198 void
200 
201 void
203 
204 bool
206 
207 static inline void
209 {
210  ck_pr_dec_32(&cmd->cluster->async_pending);
211  as_node_release(cmd->node);
212 
213  if (cmd->free_buf) {
214  cf_free(cmd->buf);
215  }
216  cf_free(cmd);
217 }
218 
219 /******************************************************************************
220  * LIBEV INLINE FUNCTIONS
221  *****************************************************************************/
222 
223 #if defined(AS_USE_LIBEV)
224 
225 static inline bool
227 {
228  return as_socket_validate(conn->fd, pipeline);
229 }
230 
231 static inline void
233 {
234  if (cmd->timeout_ms) {
235  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
236  }
237 }
238 
239 static inline void
241 {
242  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
243 }
244 
245 static inline void
247 {
249 }
250 
251 /******************************************************************************
252  * LIBUV INLINE FUNCTIONS
253  *****************************************************************************/
254 
255 #elif defined(AS_USE_LIBUV)
256 
257 static inline bool
259 {
260  // Libuv does not have a peek function, so use fd directly.
261  uv_os_fd_t fd;
262 
263  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
264  return as_socket_validate(fd, pipeline);
265  }
266  return false;
267 }
268 
269 static inline void
271 {
272  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
273 }
274 
275 static inline void
277 {
278  // Watcher already stopped by design in libuv.
279 }
280 
281 void
282 as_uv_timer_closed(uv_handle_t* handle);
283 
284 static inline void
286 {
287  if (cmd->timeout_ms) {
288  // libuv requires that cmd can't be freed until timer is closed.
289  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
290  }
291  else {
293  }
294 }
295 
296 /******************************************************************************
297  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
298  *****************************************************************************/
299 
300 #else
301 
302 static inline bool
304 {
305  return false;
306 }
307 
308 static inline void
310 {
311 }
312 
313 static inline void
315 {
316 }
317 
318 static inline void
320 {
321 }
322 
323 #endif
324 
325 /******************************************************************************
326  * COMMON INLINE FUNCTIONS
327  *****************************************************************************/
328 
329 static inline void
331 {
332  // Check if command timed out after coming off queue.
333  if (cmd->timeout_ms && (cf_getms() - *(uint64_t*)cmd) > cmd->timeout_ms) {
334  as_error err;
336  // Tell the libuv version of as_event_command_release() to not try to close the uv_timer_t.
337  cmd->timeout_ms = 0;
338  as_event_error_callback(cmd, &err);
339  return;
340  }
341 
342  // Start processing.
344 }
345 
346 static inline as_event_loop*
348 {
349  if (! event_loop) {
350  // Assign event loop using round robin distribution.
351  // Not atomic because doesn't need to be exactly accurate.
352  uint32_t current = as_event_loop_current++;
353  event_loop = &as_event_loops[current % as_event_loop_size];
354  }
355  return event_loop;
356 }
357 
358 static inline void
360 {
361  // The command buffer was already allocated with enough space for max authentication size,
362  // so just use the end of the write buffer for authentication bytes.
363  cmd->pos = cmd->len;
364  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
365  cmd->len = cmd->pos + cmd->auth_len;
366 }
367 
368 static inline void
370 {
371  // Authenticate response buffer is at end of write buffer.
372  cmd->pos = cmd->len - cmd->auth_len;
373  cmd->auth_len = sizeof(as_proto);
374  cmd->len = cmd->pos + cmd->auth_len;
376 }
377 
378 static inline void
380 {
381  // Authenticate response buffer is at end of write buffer.
382  cmd->pos = cmd->len - cmd->auth_len;
383  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
384  as_proto_swap_from_be(proto);
385  cmd->auth_len = (uint32_t)proto->sz;
386  cmd->len = cmd->pos + cmd->auth_len;
388 }
389 
390 static inline void
392 {
393  ck_pr_dec_32(&cluster->async_conn_count);
394 
395  if (pipeline) {
396  ck_pr_dec_32(&node->pipe_conn_count);
397  }
398  else {
399  ck_pr_dec_32(&node->async_conn_count);
400  }
401 }
402 
403 #ifdef __cplusplus
404 } // end extern "C"
405 #endif