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_FLAGS_FREE_BUF 1
58 #define AS_ASYNC_FLAGS_EVENT_RECEIVED 2
59 
60 #define AS_ASYNC_AUTH_RETURN_CODE 1
61 
62 #define AS_EVENT_CONNECTION_COMPLETE 0
63 #define AS_EVENT_CONNECTION_PENDING 1
64 #define AS_EVENT_CONNECTION_ERROR 2
65 
66 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
67 
68 struct as_event_command;
69 struct as_event_executor;
70 
71 typedef struct {
72 #if defined(AS_USE_LIBEV)
73  struct ev_io watcher;
74  as_socket socket;
75  int watching;
76 #elif defined(AS_USE_LIBUV)
77  uv_tcp_t socket;
78  // Reuse memory for requests, because only one request is active at a time.
79  union {
80  uv_connect_t connect;
81  uv_write_t write;
82  } req;
83 #elif defined(AS_USE_LIBEVENT)
84  struct event watcher;
85  as_socket socket;
86  int watching;
87 #else
88 #endif
89  bool pipeline;
91 
92 typedef struct {
96 
97 typedef struct {
99  void* udata;
101 
102 typedef void (*as_event_executable) (void* udata);
103 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
104 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor);
105 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
106 
107 typedef struct as_event_command {
108 #if defined(AS_USE_LIBEV)
109  struct ev_timer timer;
110 #elif defined(AS_USE_LIBUV)
111  uv_timer_t timer;
112 #elif defined(AS_USE_LIBEVENT)
113  struct event timer;
114 #else
115 #endif
120  void* udata;
123  cf_ll_element pipe_link;
124 
125  uint8_t* buf;
126  uint64_t total_deadline;
127  uint32_t socket_timeout;
128  uint32_t capacity;
129  uint32_t len;
130  uint32_t pos;
131  uint32_t auth_len;
132 
133  uint8_t type;
134  uint8_t state;
135  uint8_t flags;
138 
139 typedef struct {
141  void* udata;
143 
144 typedef struct as_event_executor {
145  pthread_mutex_t lock;
149  void* udata;
151  uint32_t max_concurrent;
152  uint32_t max;
153  uint32_t count;
154  bool notify;
155  bool valid;
157 
158 typedef enum as_connection_status_e {
163 
164 /******************************************************************************
165  * COMMON FUNCTIONS
166  *****************************************************************************/
167 
168 as_status
170 
171 void
173 
174 void
175 as_event_executor_cancel(as_event_executor* executor, int queued_count);
176 
179 
180 void
182 
183 void
185 
186 void
188 
189 void
191 
192 bool
194 
195 bool
197 
198 bool
200 
201 void
203 
204 /******************************************************************************
205  * IMPLEMENTATION SPECIFIC FUNCTIONS
206  *****************************************************************************/
207 
208 bool
210 
211 void
213 
214 /**
215  * Schedule execution of function on specified event loop.
216  * Command is placed on event loop queue and is never executed directly.
217  */
218 bool
220 
221 bool
223 
224 void
226 
227 void
229 
230 /******************************************************************************
231  * LIBEV INLINE FUNCTIONS
232  *****************************************************************************/
233 
234 #if defined(AS_USE_LIBEV)
235 
236 static inline int
238 {
239  return as_socket_validate(&conn->socket);
240 }
241 
242 static inline void
243 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
244 {
245  // TLS connections default to 55 seconds.
246  if (max_socket_idle == 0 && conn->socket.ctx) {
247  max_socket_idle = 55;
248  }
249 
250  if (max_socket_idle > 0) {
251  conn->socket.idle_check.max_socket_idle = max_socket_idle;
252  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
253  }
254  else {
255  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
256  }
257 }
258 
259 static inline void
261 {
262  if (cmd->total_deadline || cmd->socket_timeout) {
263  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
264  }
265 }
266 
267 static inline void
269 {
270  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
271 }
272 
273 static inline void
275 {
277 }
278 
279 /******************************************************************************
280  * LIBUV INLINE FUNCTIONS
281  *****************************************************************************/
282 
283 #elif defined(AS_USE_LIBUV)
284 
285 static inline int
287 {
288  // Libuv does not have a peek function, so use fd directly.
289  uv_os_fd_t fd;
290 
291  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
292  return as_socket_validate_fd(fd);
293  }
294  return false;
295 }
296 
297 static inline void
298 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
299 {
300 }
301 
302 static inline void
304 {
305  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
306 }
307 
308 static inline void
310 {
311  // Watcher already stopped by design in libuv.
312 }
313 
314 void
315 as_uv_timer_closed(uv_handle_t* handle);
316 
317 static inline void
319 {
320  if (cmd->total_deadline || cmd->socket_timeout) {
321  // libuv requires that cmd can't be freed until timer is closed.
322  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
323  }
324  else {
326  }
327 }
328 
329 /******************************************************************************
330  * LIBEVENT INLINE FUNCTIONS
331  *****************************************************************************/
332 
333 #elif defined(AS_USE_LIBEVENT)
334 
335 static inline int
337 {
338  return as_socket_validate(&conn->socket);
339 }
340 
341 static inline void
342 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
343 {
344  // TLS connections default to 55 seconds.
345  if (max_socket_idle == 0 && conn->socket.ctx) {
346  max_socket_idle = 55;
347  }
348 
349  if (max_socket_idle > 0) {
350  conn->socket.idle_check.max_socket_idle = max_socket_idle;
351  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
352  }
353  else {
354  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
355  }
356 }
357 
358 static inline void
360 {
361  if (cmd->total_deadline || cmd->socket_timeout) {
362  evtimer_del(&cmd->timer);
363  }
364 }
365 
366 static inline void
368 {
369  event_del(&conn->watcher);
370 }
371 
372 static inline void
374 {
376 }
377 
378 /******************************************************************************
379  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
380  *****************************************************************************/
381 
382 #else
383 
384 static inline int
386 {
387  return -1;
388 }
389 
390 static inline void
391 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
392 {
393 }
394 
395 static inline void
397 {
398 }
399 
400 static inline void
402 {
403 }
404 
405 static inline void
407 {
408 }
409 
410 #endif
411 
412 /******************************************************************************
413  * COMMON INLINE FUNCTIONS
414  *****************************************************************************/
415 
416 static inline as_event_loop*
418 {
419  // Assign event loop using round robin distribution if not specified.
420  return event_loop ? event_loop : as_event_loop_get();
421 }
422 
423 static inline void
425 {
426  // The command buffer was already allocated with enough space for max authentication size,
427  // so just use the end of the write buffer for authentication bytes.
428  cmd->pos = cmd->len;
429  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
430  cmd->len = cmd->pos + cmd->auth_len;
431 }
432 
433 static inline void
435 {
436  // Authenticate response buffer is at end of write buffer.
437  cmd->pos = cmd->len - cmd->auth_len;
438  cmd->auth_len = sizeof(as_proto);
439  cmd->len = cmd->pos + cmd->auth_len;
441 }
442 
443 static inline void
445 {
446  // Authenticate response buffer is at end of write buffer.
447  cmd->pos = cmd->len - cmd->auth_len;
448  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
449  as_proto_swap_from_be(proto);
450  cmd->auth_len = (uint32_t)proto->sz;
451  cmd->len = cmd->pos + cmd->auth_len;
453 }
454 
455 static inline void
457 {
459  ck_pr_dec_32(&cluster->async_conn_count);
460  as_conn_pool_dec(pool);
461 }
462 
463 static inline void
465 {
466  ck_pr_dec_32(&cluster->async_conn_count);
467  as_conn_pool_dec(pool);
468 }
469 
470 static inline void
472 {
473  as_conn_pool* pool = cmd->pipe_listener != NULL ?
474  &cmd->node->pipe_conn_pools[cmd->event_loop->index] :
475  &cmd->node->async_conn_pools[cmd->event_loop->index];
476 
477  as_event_decr_connection(cmd->cluster, pool);
478 }
479 
480 #ifdef __cplusplus
481 } // end extern "C"
482 #endif
as_event_loop * event_loop
as_event_parse_results_fn parse_results
void as_event_timeout(as_event_command *cmd)
bool as_event_command_parse_success_failure(as_event_command *cmd)
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_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)
void as_event_socket_error(as_event_command *cmd, as_error *err)
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:223
as_proto proto
Definition: as_proto.h:48
int as_socket_validate_fd(int fd)
char * user
Definition: as_cluster.h:116
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
bool as_event_command_begin(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)
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_conn_pool_dec(as_conn_pool *pool)
Definition: as_node.h:345
uint32_t index
Definition: as_event.h:75
as_conn_pool * async_conn_pools
Definition: as_node.h:217
uint32_t async_conn_count
Definition: as_cluster.h:240
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)
pthread_mutex_t lock
as_connection_status
as_pipe_listener pipe_listener
static void as_event_decr_connection(as_cluster *cluster, as_conn_pool *pool)
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_cluster *cluster, as_event_connection *conn, as_conn_pool *pool)
as_event_connection base
void as_event_error_callback(as_event_command *cmd, as_error *err)
as_connection_status as_event_get_connection(as_event_command *cmd)