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-2017 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_listener.h>
22 #include <aerospike/as_queue.h>
23 #include <aerospike/as_proto.h>
24 #include <aerospike/as_socket.h>
25 #include <citrusleaf/cf_ll.h>
26 #include <pthread.h>
27 #include <stdint.h>
28 #include <stdbool.h>
29 #include <unistd.h>
30 
31 #if defined(AS_USE_LIBEV)
32 #include <ev.h>
33 #elif defined(AS_USE_LIBUV)
34 #include <uv.h>
35 #elif defined(AS_USE_LIBEVENT)
36 #include <event2/event.h>
37 #else
38 #endif
39 
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
43 
44 /******************************************************************************
45  * TYPES
46  *****************************************************************************/
47 
48 #define AS_ASYNC_STATE_UNREGISTERED 0
49 #define AS_ASYNC_STATE_TLS_CONNECT 1
50 #define AS_ASYNC_STATE_AUTH_WRITE 2
51 #define AS_ASYNC_STATE_AUTH_READ_HEADER 4
52 #define AS_ASYNC_STATE_AUTH_READ_BODY 8
53 #define AS_ASYNC_STATE_WRITE 16
54 #define AS_ASYNC_STATE_READ_HEADER 32
55 #define AS_ASYNC_STATE_READ_BODY 64
56 
57 #define AS_ASYNC_AUTH_RETURN_CODE 1
58 
59 #define AS_EVENT_CONNECTION_COMPLETE 0
60 #define AS_EVENT_CONNECTION_PENDING 1
61 #define AS_EVENT_CONNECTION_ERROR 2
62 
63 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
64 
65 struct as_event_command;
66 struct as_event_executor;
67 
68 typedef struct {
69 #if defined(AS_USE_LIBEV)
70  struct ev_io watcher;
71  as_socket socket;
72  int watching;
73 #elif defined(AS_USE_LIBUV)
74  uv_tcp_t socket;
75  // Reuse memory for requests, because only one request is active at a time.
76  union {
77  uv_connect_t connect;
78  uv_write_t write;
79  } req;
80 #elif defined(AS_USE_LIBEVENT)
81  struct event watcher;
82  as_socket socket;
83  int watching;
84 #else
85 #endif
86  bool pipeline;
88 
89 typedef struct {
93 
94 typedef struct {
96  void* udata;
98 
99 typedef void (*as_event_executable) (void* udata);
100 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
101 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor, as_error* err);
102 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
103 
104 typedef struct as_event_command {
105 #if defined(AS_USE_LIBEV)
106  struct ev_timer timer;
107 #elif defined(AS_USE_LIBUV)
108  uv_timer_t timer;
109 #elif defined(AS_USE_LIBEVENT)
110  struct event timer;
111 #else
112 #endif
117  void* udata;
120  cf_ll_element pipe_link;
121 
122  uint8_t* buf;
123  uint32_t capacity;
124  uint32_t len;
125  uint32_t pos;
126  uint32_t auth_len;
127  uint32_t timeout_ms;
128 
129  uint8_t type;
130  uint8_t state;
132  bool free_buf;
134 
135 typedef struct {
137  void* udata;
139 
140 typedef struct as_event_executor {
141  pthread_mutex_t lock;
145  void* udata;
146  uint32_t max_concurrent;
147  uint32_t max;
148  uint32_t count;
149  bool valid;
151 
152 typedef enum as_connection_status_e {
157 
158 /******************************************************************************
159  * COMMON FUNCTIONS
160  *****************************************************************************/
161 
162 as_status
164 
165 void
167 
168 void
169 as_event_executor_cancel(as_event_executor* executor, int queued_count);
170 
173 
174 void
176 
177 void
179 
180 void
182 
183 void
185 
186 bool
188 
189 bool
191 
192 bool
194 
195 void
197 
198 /******************************************************************************
199  * IMPLEMENTATION SPECIFIC FUNCTIONS
200  *****************************************************************************/
201 
202 bool
204 
205 void
207 
208 /**
209  * Schedule execution of function on specified event loop.
210  * Command is placed on event loop queue and is never executed directly.
211  */
212 bool
214 
215 bool
217 
218 void
220 
221 void
223 
224 /******************************************************************************
225  * LIBEV INLINE FUNCTIONS
226  *****************************************************************************/
227 
228 #if defined(AS_USE_LIBEV)
229 
230 static inline int
232 {
233  return as_socket_validate(&conn->socket);
234 }
235 
236 static inline void
237 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
238 {
239  // TLS connections default to 55 seconds.
240  if (max_socket_idle == 0 && conn->socket.ctx) {
241  max_socket_idle = 55;
242  }
243 
244  if (max_socket_idle > 0) {
245  conn->socket.idle_check.max_socket_idle = max_socket_idle;
246  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
247  }
248  else {
249  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
250  }
251 }
252 
253 static inline void
255 {
256  if (cmd->timeout_ms) {
257  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
258  }
259 }
260 
261 static inline void
263 {
264  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
265 }
266 
267 static inline void
269 {
271 }
272 
273 /******************************************************************************
274  * LIBUV INLINE FUNCTIONS
275  *****************************************************************************/
276 
277 #elif defined(AS_USE_LIBUV)
278 
279 static inline int
281 {
282  // Libuv does not have a peek function, so use fd directly.
283  uv_os_fd_t fd;
284 
285  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
286  return as_socket_validate_fd(fd);
287  }
288  return false;
289 }
290 
291 static inline void
292 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
293 {
294 }
295 
296 static inline void
298 {
299  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
300 }
301 
302 static inline void
304 {
305  // Watcher already stopped by design in libuv.
306 }
307 
308 void
309 as_uv_timer_closed(uv_handle_t* handle);
310 
311 static inline void
313 {
314  if (cmd->timeout_ms) {
315  // libuv requires that cmd can't be freed until timer is closed.
316  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
317  }
318  else {
320  }
321 }
322 
323 /******************************************************************************
324  * LIBEVENT INLINE FUNCTIONS
325  *****************************************************************************/
326 
327 #elif defined(AS_USE_LIBEVENT)
328 
329 static inline int
331 {
332  return as_socket_validate(&conn->socket);
333 }
334 
335 static inline void
336 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
337 {
338  // TLS connections default to 55 seconds.
339  if (max_socket_idle == 0 && conn->socket.ctx) {
340  max_socket_idle = 55;
341  }
342 
343  if (max_socket_idle > 0) {
344  conn->socket.idle_check.max_socket_idle = max_socket_idle;
345  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
346  }
347  else {
348  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
349  }
350 }
351 
352 static inline void
354 {
355  if (cmd->timeout_ms) {
356  evtimer_del(&cmd->timer);
357  }
358 }
359 
360 static inline void
362 {
363  event_del(&conn->watcher);
364 }
365 
366 static inline void
368 {
370 }
371 
372 /******************************************************************************
373  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
374  *****************************************************************************/
375 
376 #else
377 
378 static inline int
380 {
381  return -1;
382 }
383 
384 static inline void
385 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
386 {
387 }
388 
389 static inline void
391 {
392 }
393 
394 static inline void
396 {
397 }
398 
399 static inline void
401 {
402 }
403 
404 #endif
405 
406 /******************************************************************************
407  * COMMON INLINE FUNCTIONS
408  *****************************************************************************/
409 
410 static inline as_event_loop*
412 {
413  // Assign event loop using round robin distribution if not specified.
414  return event_loop ? event_loop : as_event_loop_get();
415 }
416 
417 static inline void
419 {
420  // The command buffer was already allocated with enough space for max authentication size,
421  // so just use the end of the write buffer for authentication bytes.
422  cmd->pos = cmd->len;
423  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
424  cmd->len = cmd->pos + cmd->auth_len;
425 }
426 
427 static inline void
429 {
430  // Authenticate response buffer is at end of write buffer.
431  cmd->pos = cmd->len - cmd->auth_len;
432  cmd->auth_len = sizeof(as_proto);
433  cmd->len = cmd->pos + cmd->auth_len;
435 }
436 
437 static inline void
439 {
440  // Authenticate response buffer is at end of write buffer.
441  cmd->pos = cmd->len - cmd->auth_len;
442  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
443  as_proto_swap_from_be(proto);
444  cmd->auth_len = (uint32_t)proto->sz;
445  cmd->len = cmd->pos + cmd->auth_len;
447 }
448 
449 static inline void
451 {
453  ck_pr_dec_32(&cluster->async_conn_count);
454  as_conn_pool_dec(pool);
455 }
456 
457 static inline void
459 {
460  ck_pr_dec_32(&cluster->async_conn_count);
461  as_conn_pool_dec(pool);
462 }
463 
464 static inline void
466 {
467  as_conn_pool* pool = cmd->pipe_listener != NULL ?
468  &cmd->node->pipe_conn_pools[cmd->event_loop->index] :
469  &cmd->node->async_conn_pools[cmd->event_loop->index];
470 
471  as_event_decr_connection(cmd->cluster, pool);
472 }
473 
474 #ifdef __cplusplus
475 } // end extern "C"
476 #endif