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, as_error* err);
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;
150  uint32_t max_concurrent;
151  uint32_t max;
152  uint32_t count;
153  bool valid;
155 
156 typedef enum as_connection_status_e {
161 
162 /******************************************************************************
163  * COMMON FUNCTIONS
164  *****************************************************************************/
165 
166 as_status
168 
169 void
171 
172 void
173 as_event_executor_cancel(as_event_executor* executor, int queued_count);
174 
177 
178 void
180 
181 void
183 
184 void
186 
187 void
189 
190 bool
192 
193 bool
195 
196 bool
198 
199 void
201 
202 /******************************************************************************
203  * IMPLEMENTATION SPECIFIC FUNCTIONS
204  *****************************************************************************/
205 
206 bool
208 
209 void
211 
212 /**
213  * Schedule execution of function on specified event loop.
214  * Command is placed on event loop queue and is never executed directly.
215  */
216 bool
218 
219 bool
221 
222 void
224 
225 void
227 
228 /******************************************************************************
229  * LIBEV INLINE FUNCTIONS
230  *****************************************************************************/
231 
232 #if defined(AS_USE_LIBEV)
233 
234 static inline int
236 {
237  return as_socket_validate(&conn->socket);
238 }
239 
240 static inline void
241 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
242 {
243  // TLS connections default to 55 seconds.
244  if (max_socket_idle == 0 && conn->socket.ctx) {
245  max_socket_idle = 55;
246  }
247 
248  if (max_socket_idle > 0) {
249  conn->socket.idle_check.max_socket_idle = max_socket_idle;
250  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
251  }
252  else {
253  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
254  }
255 }
256 
257 static inline void
259 {
260  if (cmd->total_deadline || cmd->socket_timeout) {
261  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
262  }
263 }
264 
265 static inline void
267 {
268  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
269 }
270 
271 static inline void
273 {
275 }
276 
277 /******************************************************************************
278  * LIBUV INLINE FUNCTIONS
279  *****************************************************************************/
280 
281 #elif defined(AS_USE_LIBUV)
282 
283 static inline int
285 {
286  // Libuv does not have a peek function, so use fd directly.
287  uv_os_fd_t fd;
288 
289  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
290  return as_socket_validate_fd(fd);
291  }
292  return false;
293 }
294 
295 static inline void
296 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
297 {
298 }
299 
300 static inline void
302 {
303  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
304 }
305 
306 static inline void
308 {
309  // Watcher already stopped by design in libuv.
310 }
311 
312 void
313 as_uv_timer_closed(uv_handle_t* handle);
314 
315 static inline void
317 {
318  if (cmd->total_deadline || cmd->socket_timeout) {
319  // libuv requires that cmd can't be freed until timer is closed.
320  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
321  }
322  else {
324  }
325 }
326 
327 /******************************************************************************
328  * LIBEVENT INLINE FUNCTIONS
329  *****************************************************************************/
330 
331 #elif defined(AS_USE_LIBEVENT)
332 
333 static inline int
335 {
336  return as_socket_validate(&conn->socket);
337 }
338 
339 static inline void
340 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
341 {
342  // TLS connections default to 55 seconds.
343  if (max_socket_idle == 0 && conn->socket.ctx) {
344  max_socket_idle = 55;
345  }
346 
347  if (max_socket_idle > 0) {
348  conn->socket.idle_check.max_socket_idle = max_socket_idle;
349  conn->socket.idle_check.last_used = (uint32_t)cf_get_seconds();
350  }
351  else {
352  conn->socket.idle_check.max_socket_idle = conn->socket.idle_check.last_used = 0;
353  }
354 }
355 
356 static inline void
358 {
359  if (cmd->total_deadline || cmd->socket_timeout) {
360  evtimer_del(&cmd->timer);
361  }
362 }
363 
364 static inline void
366 {
367  event_del(&conn->watcher);
368 }
369 
370 static inline void
372 {
374 }
375 
376 /******************************************************************************
377  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
378  *****************************************************************************/
379 
380 #else
381 
382 static inline int
384 {
385  return -1;
386 }
387 
388 static inline void
389 as_event_set_conn_last_used(as_event_connection* conn, uint32_t max_socket_idle)
390 {
391 }
392 
393 static inline void
395 {
396 }
397 
398 static inline void
400 {
401 }
402 
403 static inline void
405 {
406 }
407 
408 #endif
409 
410 /******************************************************************************
411  * COMMON INLINE FUNCTIONS
412  *****************************************************************************/
413 
414 static inline as_event_loop*
416 {
417  // Assign event loop using round robin distribution if not specified.
418  return event_loop ? event_loop : as_event_loop_get();
419 }
420 
421 static inline void
423 {
424  // The command buffer was already allocated with enough space for max authentication size,
425  // so just use the end of the write buffer for authentication bytes.
426  cmd->pos = cmd->len;
427  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
428  cmd->len = cmd->pos + cmd->auth_len;
429 }
430 
431 static inline void
433 {
434  // Authenticate response buffer is at end of write buffer.
435  cmd->pos = cmd->len - cmd->auth_len;
436  cmd->auth_len = sizeof(as_proto);
437  cmd->len = cmd->pos + cmd->auth_len;
439 }
440 
441 static inline void
443 {
444  // Authenticate response buffer is at end of write buffer.
445  cmd->pos = cmd->len - cmd->auth_len;
446  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
447  as_proto_swap_from_be(proto);
448  cmd->auth_len = (uint32_t)proto->sz;
449  cmd->len = cmd->pos + cmd->auth_len;
451 }
452 
453 static inline void
455 {
457  ck_pr_dec_32(&cluster->async_conn_count);
458  as_conn_pool_dec(pool);
459 }
460 
461 static inline void
463 {
464  ck_pr_dec_32(&cluster->async_conn_count);
465  as_conn_pool_dec(pool);
466 }
467 
468 static inline void
470 {
471  as_conn_pool* pool = cmd->pipe_listener != NULL ?
472  &cmd->node->pipe_conn_pools[cmd->event_loop->index] :
473  &cmd->node->async_conn_pools[cmd->event_loop->index];
474 
475  as_event_decr_connection(cmd->cluster, pool);
476 }
477 
478 #ifdef __cplusplus
479 } // end extern "C"
480 #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_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
void(* as_event_executor_complete_fn)(struct as_event_executor *executor, as_error *err)
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)