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_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 #else
36 #endif
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 /******************************************************************************
43  * TYPES
44  *****************************************************************************/
45 
46 #define AS_ASYNC_STATE_UNREGISTERED 0
47 #define AS_ASYNC_STATE_TLS_CONNECT 1
48 #define AS_ASYNC_STATE_AUTH_WRITE 2
49 #define AS_ASYNC_STATE_AUTH_READ_HEADER 4
50 #define AS_ASYNC_STATE_AUTH_READ_BODY 8
51 #define AS_ASYNC_STATE_WRITE 16
52 #define AS_ASYNC_STATE_READ_HEADER 32
53 #define AS_ASYNC_STATE_READ_BODY 64
54 
55 #define AS_ASYNC_AUTH_RETURN_CODE 1
56 
57 #define AS_EVENT_CONNECTION_COMPLETE 0
58 #define AS_EVENT_CONNECTION_PENDING 1
59 #define AS_EVENT_CONNECTION_ERROR 2
60 
61 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
62 
63 struct as_event_command;
64 struct as_event_executor;
65 
66 typedef struct {
67 #if defined(AS_USE_LIBEV)
68  struct ev_io watcher;
69  as_socket socket;
70  int watching;
71 #elif defined(AS_USE_LIBUV)
72  uv_tcp_t socket;
73  // Reuse memory for requests, because only one request is active at a time.
74  union {
75  uv_connect_t connect;
76  uv_write_t write;
77  } req;
78 #else
79 #endif
80  bool pipeline;
82 
83 typedef struct {
87 
88 typedef struct {
90  void* udata;
92 
93 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
94 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor, as_error* err);
95 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
96 
97 typedef struct as_event_command {
98 #if defined(AS_USE_LIBEV)
99  struct ev_timer timer;
100 #elif defined(AS_USE_LIBUV)
101  uv_timer_t timer;
102 #else
103 #endif
108  void* udata;
111  cf_ll_element pipe_link;
112 
113  uint8_t* buf;
114  uint32_t capacity;
115  uint32_t len;
116  uint32_t pos;
117  uint32_t auth_len;
118  uint32_t timeout_ms;
119 
120  uint8_t type;
121  uint8_t state;
123  bool free_buf;
125 
126 typedef struct as_event_executor {
127  pthread_mutex_t lock;
131  void* udata;
132  uint32_t max_concurrent;
133  uint32_t max;
134  uint32_t count;
135  bool valid;
137 
138 typedef enum as_connection_status_e {
143 
144 /******************************************************************************
145  * COMMON FUNCTIONS
146  *****************************************************************************/
147 
148 as_status
150 
151 void
153 
154 void
155 as_event_executor_cancel(as_event_executor* executor, int queued_count);
156 
159 
160 int
161 as_event_create_socket(as_event_command* cmd, int family);
162 
163 void
164 as_event_fd_error(as_event_command* cmd, as_error* err, int fd);
165 
166 void
168 
169 void
171 
172 void
174 
175 void
177 
178 void
180 
181 bool
183 
184 bool
186 
187 bool
189 
190 void
192 
193 /******************************************************************************
194  * IMPLEMENTATION SPECIFIC FUNCTIONS
195  *****************************************************************************/
196 
197 bool
199 
200 void
202 
203 bool
205 
206 void
208 
209 void
211 
212 void
214 
215 bool
217 
218 /******************************************************************************
219  * LIBEV INLINE FUNCTIONS
220  *****************************************************************************/
221 
222 #if defined(AS_USE_LIBEV)
223 
224 static inline int
226 {
227  return as_socket_validate(&conn->socket);
228 }
229 
230 static inline void
232 {
233  if (cmd->timeout_ms) {
234  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
235  }
236 }
237 
238 static inline void
240 {
241  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
242 }
243 
244 static inline void
246 {
248 }
249 
250 /******************************************************************************
251  * LIBUV INLINE FUNCTIONS
252  *****************************************************************************/
253 
254 #elif defined(AS_USE_LIBUV)
255 
256 static inline int
258 {
259  // Libuv does not have a peek function, so use fd directly.
260  uv_os_fd_t fd;
261 
262  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
263  return as_socket_validate_fd(fd);
264  }
265  return false;
266 }
267 
268 static inline void
270 {
271  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
272 }
273 
274 static inline void
276 {
277  // Watcher already stopped by design in libuv.
278 }
279 
280 void
281 as_uv_timer_closed(uv_handle_t* handle);
282 
283 static inline void
285 {
286  if (cmd->timeout_ms) {
287  // libuv requires that cmd can't be freed until timer is closed.
288  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
289  }
290  else {
292  }
293 }
294 
295 /******************************************************************************
296  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
297  *****************************************************************************/
298 
299 #else
300 
301 static inline int
303 {
304  return -1;
305 }
306 
307 static inline void
309 {
310 }
311 
312 static inline void
314 {
315 }
316 
317 static inline void
319 {
320 }
321 
322 #endif
323 
324 /******************************************************************************
325  * COMMON INLINE FUNCTIONS
326  *****************************************************************************/
327 
328 static inline void
330 {
331  // Check if command timed out after coming off queue.
332  if (cmd->timeout_ms && (cf_getms() - *(uint64_t*)cmd) > cmd->timeout_ms) {
333  as_error err;
335  // Tell the libuv version of as_event_command_release() to not try to close the uv_timer_t.
336  cmd->timeout_ms = 0;
337  as_event_error_callback(cmd, &err);
338  return;
339  }
340 
341  // Start processing.
343 }
344 
345 static inline as_event_loop*
347 {
348  // Assign event loop using round robin distribution if not specified.
349  return event_loop ? event_loop : as_event_loop_get();
350 }
351 
352 static inline void
354 {
355  // The command buffer was already allocated with enough space for max authentication size,
356  // so just use the end of the write buffer for authentication bytes.
357  cmd->pos = cmd->len;
358  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
359  cmd->len = cmd->pos + cmd->auth_len;
360 }
361 
362 static inline void
364 {
365  // Authenticate response buffer is at end of write buffer.
366  cmd->pos = cmd->len - cmd->auth_len;
367  cmd->auth_len = sizeof(as_proto);
368  cmd->len = cmd->pos + cmd->auth_len;
370 }
371 
372 static inline void
374 {
375  // Authenticate response buffer is at end of write buffer.
376  cmd->pos = cmd->len - cmd->auth_len;
377  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
378  as_proto_swap_from_be(proto);
379  cmd->auth_len = (uint32_t)proto->sz;
380  cmd->len = cmd->pos + cmd->auth_len;
382 }
383 
384 static inline void
386 {
388  ck_pr_dec_32(&cluster->async_conn_count);
389  as_queue_decr_total(queue);
390 }
391 
392 static inline void
394 {
395  ck_pr_dec_32(&cluster->async_conn_count);
396  as_queue_decr_total(queue);
397 }
398 
399 static inline void
401 {
402  as_queue* queue = cmd->pipe_listener != NULL ?
403  &cmd->node->pipe_conn_qs[cmd->event_loop->index] :
404  &cmd->node->async_conn_qs[cmd->event_loop->index];
405 
406  as_event_decr_connection(cmd->cluster, queue);
407 }
408 
409 #ifdef __cplusplus
410 } // end extern "C"
411 #endif