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_REGISTERED 1
50 #define AS_ASYNC_STATE_TLS_CONNECT 2
51 #define AS_ASYNC_STATE_AUTH_WRITE 3
52 #define AS_ASYNC_STATE_AUTH_READ_HEADER 4
53 #define AS_ASYNC_STATE_AUTH_READ_BODY 5
54 #define AS_ASYNC_STATE_COMMAND_WRITE 6
55 #define AS_ASYNC_STATE_COMMAND_READ_HEADER 7
56 #define AS_ASYNC_STATE_COMMAND_READ_BODY 8
57 #define AS_ASYNC_STATE_COMPLETE 9
58 
59 #define AS_ASYNC_FLAGS_MASTER 1
60 #define AS_ASYNC_FLAGS_READ 2
61 #define AS_ASYNC_FLAGS_HAS_TIMER 4
62 #define AS_ASYNC_FLAGS_USING_SOCKET_TIMER 8
63 #define AS_ASYNC_FLAGS_EVENT_RECEIVED 16
64 #define AS_ASYNC_FLAGS_FREE_BUF 32
65 #define AS_ASYNC_FLAGS_CP_MODE 64
66 
67 #define AS_ASYNC_AUTH_RETURN_CODE 1
68 
69 #define AS_EVENT_CONNECTION_COMPLETE 0
70 #define AS_EVENT_CONNECTION_PENDING 1
71 #define AS_EVENT_CONNECTION_ERROR 2
72 
73 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
74 
75 struct as_event_command;
76 struct as_event_executor;
77 
78 typedef struct {
79 #if defined(AS_USE_LIBEV)
80  struct ev_io watcher;
81  as_socket socket;
82 #elif defined(AS_USE_LIBUV)
83  uv_tcp_t socket;
84  // Reuse memory for requests, because only one request is active at a time.
85  union {
86  uv_connect_t connect;
87  uv_write_t write;
88  } req;
89 #elif defined(AS_USE_LIBEVENT)
90  struct event watcher;
91  as_socket socket;
92 #else
93 #endif
94  int watching;
95  bool pipeline;
97 
98 typedef struct {
102 
103 typedef struct {
105  void* udata;
107 
108 typedef void (*as_event_executable) (void* udata);
109 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
110 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor);
111 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
112 
113 typedef struct as_event_command {
114 #if defined(AS_USE_LIBEV)
115  struct ev_timer timer;
116 #elif defined(AS_USE_LIBUV)
117  uv_timer_t timer;
118 #elif defined(AS_USE_LIBEVENT)
119  struct event timer;
120 #else
121 #endif
122  uint64_t total_deadline;
123  uint32_t socket_timeout;
124  uint32_t max_retries;
125  uint32_t iteration;
131  void* partition; // as_partition* or as_partition_shm*
132  void* udata;
135  cf_ll_element pipe_link;
136 
137  uint8_t* buf;
138  uint32_t write_offset;
139  uint32_t write_len;
140  uint32_t read_capacity;
141  uint32_t len;
142  uint32_t pos;
143 
144  uint8_t type;
145  uint8_t state;
146  uint8_t flags;
149 
150 typedef struct {
152  void* udata;
154 
155 typedef struct as_event_executor {
156  pthread_mutex_t lock;
160  void* udata;
162  uint32_t max_concurrent;
163  uint32_t max;
164  uint32_t count;
165  bool notify;
166  bool valid;
168 
169 /******************************************************************************
170  * COMMON FUNCTIONS
171  *****************************************************************************/
172 
173 as_status
175 
176 void
178 
179 void
181 
182 bool
183 as_event_command_retry(as_event_command* cmd, bool alternate);
184 
185 void
187 
188 void
189 as_event_executor_cancel(as_event_executor* executor, int queued_count);
190 
191 void
193 
194 void
196 
197 void
199 
200 void
202 
203 bool
205 
206 bool
208 
209 bool
211 
212 void
214 
215 void
217 
218 /******************************************************************************
219  * IMPLEMENTATION SPECIFIC FUNCTIONS
220  *****************************************************************************/
221 
222 bool
224 
225 void
227 
228 /**
229  * Schedule execution of function on specified event loop.
230  * Command is placed on event loop queue and is never executed directly.
231  */
232 bool
234 
235 void
237 
238 void
240 
241 void
243 
244 void
246 
247 /******************************************************************************
248  * LIBEV INLINE FUNCTIONS
249  *****************************************************************************/
250 
251 #if defined(AS_USE_LIBEV)
252 
253 void as_ev_socket_timeout(struct ev_loop* loop, ev_timer* timer, int revents);
254 void as_ev_total_timeout(struct ev_loop* loop, ev_timer* timer, int revents);
255 
256 static inline int
258 {
259  return as_socket_validate(&conn->socket);
260 }
261 
262 static inline void
263 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
264 {
265  // TLS connections default to 55 seconds.
266  if (max_socket_idle == 0 && conn->socket.ctx) {
267  max_socket_idle = 55;
268  }
269 
270  if (max_socket_idle > 0) {
271  conn->socket.idle_check.max_socket_idle = max_socket_idle;
272  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
273  }
274  else {
275  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
276  }
277 }
278 
279 static inline void
280 as_event_init_total_timer(as_event_command* cmd, uint64_t timeout)
281 {
282  ev_timer_init(&cmd->timer, as_ev_total_timeout, (double)timeout / 1000.0, 0.0);
283  cmd->timer.data = cmd;
284  ev_timer_start(cmd->event_loop->loop, &cmd->timer);
285 }
286 
287 static inline void
288 as_event_set_total_timer(as_event_command* cmd, uint64_t timeout)
289 {
290  ev_timer_start(cmd->event_loop->loop, &cmd->timer);
291 }
292 
293 static inline void
295 {
296  ev_init(&cmd->timer, as_ev_socket_timeout);
297  cmd->timer.repeat = ((double)cmd->socket_timeout) / 1000.0;
298  cmd->timer.data = cmd;
299  ev_timer_again(cmd->event_loop->loop, &cmd->timer);
300 }
301 
302 static inline void
304 {
305  cmd->timer.repeat = (double)cmd->socket_timeout/ 1000.0;
306  ev_timer_again(cmd->event_loop->loop, &cmd->timer);
307 }
308 
309 static inline void
311 {
312  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
313 }
314 
315 static inline void
317 {
318  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
319 }
320 
321 static inline void
323 {
325 }
326 
327 /******************************************************************************
328  * LIBUV INLINE FUNCTIONS
329  *****************************************************************************/
330 
331 #elif defined(AS_USE_LIBUV)
332 
333 void as_uv_total_timeout(uv_timer_t* timer);
334 void as_uv_socket_timeout(uv_timer_t* timer);
335 
336 static inline int
338 {
339  // Libuv does not have a peek function, so use fd directly.
340  uv_os_fd_t fd;
341 
342  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
343  return as_socket_validate_fd(fd);
344  }
345  return false;
346 }
347 
348 static inline void
349 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
350 {
351 }
352 
353 static inline void
354 as_event_init_total_timer(as_event_command* cmd, uint64_t timeout)
355 {
356  uv_timer_init(cmd->event_loop->loop, &cmd->timer);
357  cmd->timer.data = cmd;
358  uv_timer_start(&cmd->timer, as_uv_total_timeout, timeout, 0);
359 }
360 
361 static inline void
362 as_event_set_total_timer(as_event_command* cmd, uint64_t timeout)
363 {
364  uv_timer_start(&cmd->timer, as_uv_total_timeout, timeout, 0);
365 }
366 
367 static inline void
369 {
370  uv_timer_init(cmd->event_loop->loop, &cmd->timer);
371  cmd->timer.data = cmd;
372  uv_timer_start(&cmd->timer, as_uv_socket_timeout, cmd->socket_timeout, cmd->socket_timeout);
373 }
374 
375 static inline void
377 {
378  uv_timer_again(&cmd->timer);
379 }
380 
381 static inline void
383 {
384  uv_timer_stop(&cmd->timer);
385 }
386 
387 static inline void
389 {
390  // Watcher already stopped by design in libuv.
391 }
392 
393 void
394 as_uv_timer_closed(uv_handle_t* handle);
395 
396 static inline void
398 {
399  if (cmd->flags & AS_ASYNC_FLAGS_HAS_TIMER) {
400  // libuv requires that cmd can't be freed until timer is closed.
401  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
402  }
403  else {
405  }
406 }
407 
408 /******************************************************************************
409  * LIBEVENT INLINE FUNCTIONS
410  *****************************************************************************/
411 
412 #elif defined(AS_USE_LIBEVENT)
413 
414 void as_libevent_socket_timeout(evutil_socket_t sock, short events, void* udata);
415 void as_libevent_total_timeout(evutil_socket_t sock, short events, void* udata);
416 
417 static inline int
419 {
420  return as_socket_validate(&conn->socket);
421 }
422 
423 static inline void
424 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
425 {
426  // TLS connections default to 55 seconds.
427  if (max_socket_idle == 0 && conn->socket.ctx) {
428  max_socket_idle = 55;
429  }
430 
431  if (max_socket_idle > 0) {
432  conn->socket.idle_check.max_socket_idle = max_socket_idle;
433  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
434  }
435  else {
436  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
437  }
438 }
439 
440 static inline void
441 as_event_init_total_timer(as_event_command* cmd, uint64_t timeout)
442 {
443  evtimer_assign(&cmd->timer, cmd->event_loop->loop, as_libevent_total_timeout, cmd);
444 
445  struct timeval tv;
446  tv.tv_sec = timeout / 1000;
447  tv.tv_usec = (timeout % 1000) * 1000;
448 
449  evtimer_add(&cmd->timer, &tv);
450 }
451 
452 static inline void
453 as_event_set_total_timer(as_event_command* cmd, uint64_t timeout)
454 {
455  struct timeval tv;
456  tv.tv_sec = timeout / 1000;
457  tv.tv_usec = (timeout % 1000) * 1000;
458 
459  evtimer_add(&cmd->timer, &tv);
460 }
461 
462 static inline void
464 {
465  event_assign(&cmd->timer, cmd->event_loop->loop, -1, EV_PERSIST, as_libevent_socket_timeout, cmd);
466 
467  struct timeval tv;
468  tv.tv_sec = cmd->socket_timeout / 1000;
469  tv.tv_usec = (cmd->socket_timeout % 1000) * 1000;
470 
471  evtimer_add(&cmd->timer, &tv);
472 }
473 
474 static inline void
476 {
477  // libevent socket timers automatically repeat.
478 }
479 
480 static inline void
482 {
483  evtimer_del(&cmd->timer);
484 }
485 
486 static inline void
488 {
489  event_del(&conn->watcher);
490 }
491 
492 static inline void
494 {
496 }
497 
498 /******************************************************************************
499  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
500  *****************************************************************************/
501 
502 #else
503 
504 static inline int
506 {
507  return -1;
508 }
509 
510 static inline void
511 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
512 {
513 }
514 
515 static inline void
517 {
518 }
519 
520 static inline void
522 {
523 }
524 
525 static inline void
527 {
528 }
529 
530 static inline void
532 {
533 }
534 
535 static inline void
537 {
538 }
539 
540 static inline void
542 {
543 }
544 
545 static inline void
547 {
548 }
549 
550 #endif
551 
552 /******************************************************************************
553  * COMMON INLINE FUNCTIONS
554  *****************************************************************************/
555 
556 static inline as_event_loop*
558 {
559  // Assign event loop using round robin distribution if not specified.
560  return event_loop ? event_loop : as_event_loop_get();
561 }
562 
563 static inline void
565 {
566  // Authentication write buffer is always located after command write buffer.
567  uint8_t* buf = (uint8_t*)cmd + cmd->write_offset + cmd->write_len;
568  uint32_t len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, buf);
569  cmd->len = cmd->write_len + len;
570  cmd->pos = cmd->write_len;
571 }
572 
573 static inline void
575 {
576  // Authenticate read buffer uses the standard read buffer (buf).
577  cmd->len = sizeof(as_proto);
578  cmd->pos = 0;
580 }
581 
582 static inline void
584 {
585  // Authenticate read buffer uses the standard read buffer (buf).
586  as_proto* proto = (as_proto*)cmd->buf;
587  as_proto_swap_from_be(proto);
588  cmd->len = (uint32_t)proto->sz;
589  cmd->pos = 0;
591 }
592 
593 static inline void
595 {
596  cmd->len = cmd->write_len;
597  cmd->pos = 0;
598 }
599 
600 static inline void
602 {
604  as_conn_pool_dec(pool);
605 }
606 
607 static inline void
609 {
610  as_conn_pool* pool = &cmd->node->async_conn_pools[cmd->event_loop->index];
611  as_event_release_connection(cmd->conn, pool);
612 }
613 
614 static inline void
616 {
617  as_conn_pool* pool = cmd->pipe_listener != NULL ?
618  &cmd->node->pipe_conn_pools[cmd->event_loop->index] :
619  &cmd->node->async_conn_pools[cmd->event_loop->index];
620 
621  as_conn_pool_dec(pool);
622 }
623 
624 static inline void
626 {
627  as_event_connection* conn = cmd->conn;
628 
629  if (conn->watching > 0) {
630  as_event_stop_watcher(cmd, conn);
631  as_event_release_connection(conn, pool);
632  }
633  else {
634  cf_free(conn);
635  as_conn_pool_dec(pool);
636  }
637 }
638 
639 static inline bool
641 {
642  if (cmd->pipe_listener) {
643  return false;
644  }
645 
646  as_event_stop_watcher(cmd, cmd->conn);
648  return as_event_command_retry(cmd, true);
649 }
650 
651 #ifdef __cplusplus
652 } // end extern "C"
653 #endif
as_event_loop * event_loop
as_event_parse_results_fn parse_results
bool as_event_command_parse_success_failure(as_event_command *cmd)
as_policy_replica
Definition: as_policy.h:277
as_event_executor_complete_fn complete_fn
bool(* as_event_parse_results_fn)(struct as_event_command *cmd)
#define AS_ASYNC_STATE_AUTH_READ_HEADER
as_pipe_listener listener
as_status
Definition: as_status.h:30
void as_event_command_write_start(as_event_command *cmd)
static bool as_event_socket_retry(as_event_command *cmd)
void as_event_command_free(as_event_command *cmd)
static void as_event_set_auth_parse_header(as_event_command *cmd)
void as_proto_swap_from_be(as_proto *m)
static void as_event_set_auth_read_header(as_event_command *cmd)
bool as_event_command_parse_header(as_event_command *cmd)
void as_event_executor_cancel(as_event_executor *executor, int queued_count)
static void as_event_command_release(as_event_command *cmd)
void as_event_node_destroy(as_node *node)
void(* as_event_executor_complete_fn)(struct as_event_executor *executor)
static void as_event_release_async_connection(as_event_command *cmd)
void as_event_socket_error(as_event_command *cmd, as_error *err)
static void as_event_repeat_socket_timer(as_event_command *cmd)
void as_event_executor_complete(as_event_command *cmd)
char * password
Definition: as_cluster.h:122
void(* as_event_executable)(void *udata)
as_cluster * cluster
static void as_event_set_conn_last_used(as_event_connection *conn, uint32_t max_socket_idle)
struct as_event_command ** commands
bool as_event_create_loop(as_event_loop *event_loop)
as_event_loop * event_loop
as_status as_event_command_execute(as_event_command *cmd, as_error *err)
void * loop
Definition: as_event.h:67
as_event_executable executable
int as_socket_validate(as_socket *sock)
as_conn_pool * pipe_conn_pools
Definition: as_node.h:224
as_proto proto
Definition: as_proto.h:48
int as_socket_validate_fd(int fd)
char * user
Definition: as_cluster.h:116
bool as_event_command_retry(as_event_command *cmd, bool alternate)
void as_event_close_cluster(as_cluster *cluster)
static int as_event_validate_connection(as_event_connection *conn)
#define AS_ASYNC_STATE_AUTH_READ_BODY
static void as_event_stop_watcher(as_event_command *cmd, as_event_connection *conn)
void(* as_pipe_listener)(void *udata, as_event_loop *event_loop)
Definition: as_listener.h:73
static void as_event_set_write(as_event_command *cmd)
void as_event_response_error(as_event_command *cmd, as_error *err)
static void as_event_decr_conn(as_event_command *cmd)
void as_event_total_timeout(as_event_command *cmd)
static void as_event_connection_timeout(as_event_command *cmd, as_conn_pool *pool)
bool as_event_execute(as_event_loop *event_loop, as_event_executable executable, void *udata)
void as_event_register_external_loop(as_event_loop *event_loop)
uint32_t as_authenticate_set(const char *user, const char *credential, uint8_t *buffer)
static void as_event_set_total_timer(as_event_command *cmd, uint64_t timeout)
static void as_conn_pool_dec(as_conn_pool *pool)
Definition: as_node.h:346
uint32_t index
Definition: as_event.h:75
as_conn_pool * async_conn_pools
Definition: as_node.h:218
void as_event_socket_timeout(as_event_command *cmd)
void as_event_connect(as_event_command *cmd)
static as_event_loop * as_event_loop_get()
Definition: as_event.h:228
cf_ll_element pipe_link
as_event_connection * conn
static void as_event_set_auth_write(as_event_command *cmd)
static void as_event_stop_timer(as_event_command *cmd)
void as_event_close_connection(as_event_connection *conn)
static void as_event_init_socket_timer(as_event_command *cmd)
pthread_mutex_t lock
as_pipe_listener pipe_listener
as_policy_replica replica
void(* as_event_executor_destroy_fn)(struct as_event_executor *executor)
bool as_event_command_parse_result(as_event_command *cmd)
struct as_event_command * cmd
static as_event_loop * as_event_assign(as_event_loop *event_loop)
static void as_event_release_connection(as_event_connection *conn, as_conn_pool *pool)
as_event_connection base
void as_event_error_callback(as_event_command *cmd, as_error *err)
static void as_event_init_total_timer(as_event_command *cmd, uint64_t timeout)
void as_event_parse_error(as_event_command *cmd, as_error *err)
#define AS_ASYNC_FLAGS_HAS_TIMER