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_AUTH_WRITE 1
48 #define AS_ASYNC_STATE_AUTH_READ_HEADER 2
49 #define AS_ASYNC_STATE_AUTH_READ_BODY 4
50 #define AS_ASYNC_STATE_WRITE 8
51 #define AS_ASYNC_STATE_READ_HEADER 16
52 #define AS_ASYNC_STATE_READ_BODY 32
53 
54 #define AS_ASYNC_AUTH_RETURN_CODE 1
55 
56 #define AS_EVENT_CONNECTION_COMPLETE 0
57 #define AS_EVENT_CONNECTION_PENDING 1
58 #define AS_EVENT_CONNECTION_ERROR 2
59 
60 #define AS_EVENT_QUEUE_INITIAL_CAPACITY 256
61 
62 struct as_event_command;
63 struct as_event_executor;
64 
65 typedef struct {
66 #if defined(AS_USE_LIBEV)
67  struct ev_io watcher;
68  int fd;
69 #elif defined(AS_USE_LIBUV)
70  uv_tcp_t socket;
71 
72  // Reuse memory for requests, because only one request is active at a time.
73  union {
74  uv_connect_t connect;
75  uv_write_t write;
76  } req;
77 #else
78 #endif
79  bool pipeline;
81 
82 typedef struct {
86 
87 typedef struct {
89  void* udata;
91 
92 typedef bool (*as_event_parse_results_fn) (struct as_event_command* cmd);
93 typedef void (*as_event_executor_complete_fn) (struct as_event_executor* executor, as_error* err);
94 typedef void (*as_event_executor_destroy_fn) (struct as_event_executor* executor);
95 
96 typedef struct as_event_command {
97 #if defined(AS_USE_LIBEV)
98  struct ev_timer timer;
99 #elif defined(AS_USE_LIBUV)
100  uv_timer_t timer;
101 #else
102 #endif
107  void* udata;
110  cf_ll_element pipe_link;
111 
112  uint8_t* buf;
113  uint32_t capacity;
114  uint32_t len;
115  uint32_t pos;
116  uint32_t auth_len;
117  uint32_t timeout_ms;
118 
119  uint8_t type;
120  uint8_t state;
122  bool free_buf;
124 
125 typedef struct as_event_executor {
126  pthread_mutex_t lock;
130  void* udata;
131  uint32_t max_concurrent;
132  uint32_t max;
133  uint32_t count;
134  bool valid;
136 
137 typedef enum as_connection_status_e {
142 
143 /******************************************************************************
144  * GLOBAL VARIABLES
145  *****************************************************************************/
146 
148 extern uint32_t as_event_loop_size;
149 extern uint32_t as_event_loop_current;
150 
151 /******************************************************************************
152  * COMMON FUNCTIONS
153  *****************************************************************************/
154 
155 as_status
157 
158 void
160 
161 void
162 as_event_executor_cancel(as_event_executor* executor, int queued_count);
163 
166 
167 int
169 
170 void
172 
173 void
175 
176 void
178 
179 void
181 
182 void
184 
185 bool
187 
188 bool
190 
191 bool
193 
194 /******************************************************************************
195  * IMPLEMENTATION SPECIFIC FUNCTIONS
196  *****************************************************************************/
197 
198 bool
200 
201 void
203 
204 bool
206 
207 void
209 
210 void
212 
213 void
215 
216 bool
218 
219 void
221 
222 static inline void
224 {
225  ck_pr_dec_32(&cmd->cluster->async_pending);
226  as_node_release(cmd->node);
227 
228  if (cmd->free_buf) {
229  cf_free(cmd->buf);
230  }
231  cf_free(cmd);
232 }
233 
234 /******************************************************************************
235  * LIBEV INLINE FUNCTIONS
236  *****************************************************************************/
237 
238 #if defined(AS_USE_LIBEV)
239 
240 static inline int
242 {
243  return as_socket_validate(conn->fd);
244 }
245 
246 static inline void
248 {
249  if (cmd->timeout_ms) {
250  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
251  }
252 }
253 
254 static inline void
256 {
257  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
258 }
259 
260 static inline void
262 {
264 }
265 
266 /******************************************************************************
267  * LIBUV INLINE FUNCTIONS
268  *****************************************************************************/
269 
270 #elif defined(AS_USE_LIBUV)
271 
272 static inline int
274 {
275  // Libuv does not have a peek function, so use fd directly.
276  uv_os_fd_t fd;
277 
278  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
279  return as_socket_validate(fd);
280  }
281  return false;
282 }
283 
284 static inline void
286 {
287  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
288 }
289 
290 static inline void
292 {
293  // Watcher already stopped by design in libuv.
294 }
295 
296 void
297 as_uv_timer_closed(uv_handle_t* handle);
298 
299 static inline void
301 {
302  if (cmd->timeout_ms) {
303  // libuv requires that cmd can't be freed until timer is closed.
304  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
305  }
306  else {
308  }
309 }
310 
311 /******************************************************************************
312  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
313  *****************************************************************************/
314 
315 #else
316 
317 static inline int
319 {
320  return -1;
321 }
322 
323 static inline void
325 {
326 }
327 
328 static inline void
330 {
331 }
332 
333 static inline void
335 {
336 }
337 
338 #endif
339 
340 /******************************************************************************
341  * COMMON INLINE FUNCTIONS
342  *****************************************************************************/
343 
344 static inline void
346 {
347  // Check if command timed out after coming off queue.
348  if (cmd->timeout_ms && (cf_getms() - *(uint64_t*)cmd) > cmd->timeout_ms) {
349  as_error err;
351  // Tell the libuv version of as_event_command_release() to not try to close the uv_timer_t.
352  cmd->timeout_ms = 0;
353  as_event_error_callback(cmd, &err);
354  return;
355  }
356 
357  // Start processing.
359 }
360 
361 static inline as_event_loop*
363 {
364  if (! event_loop) {
365  // Assign event loop using round robin distribution.
366  // Not atomic because doesn't need to be exactly accurate.
367  uint32_t current = as_event_loop_current++;
368  event_loop = &as_event_loops[current % as_event_loop_size];
369  }
370  return event_loop;
371 }
372 
373 static inline void
375 {
376  // The command buffer was already allocated with enough space for max authentication size,
377  // so just use the end of the write buffer for authentication bytes.
378  cmd->pos = cmd->len;
379  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
380  cmd->len = cmd->pos + cmd->auth_len;
381 }
382 
383 static inline void
385 {
386  // Authenticate response buffer is at end of write buffer.
387  cmd->pos = cmd->len - cmd->auth_len;
388  cmd->auth_len = sizeof(as_proto);
389  cmd->len = cmd->pos + cmd->auth_len;
391 }
392 
393 static inline void
395 {
396  // Authenticate response buffer is at end of write buffer.
397  cmd->pos = cmd->len - cmd->auth_len;
398  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
399  as_proto_swap_from_be(proto);
400  cmd->auth_len = (uint32_t)proto->sz;
401  cmd->len = cmd->pos + cmd->auth_len;
403 }
404 
405 static inline void
407 {
409  ck_pr_dec_32(&cluster->async_conn_count);
410  as_queue_decr_total(queue);
411 }
412 
413 static inline void
415 {
416  ck_pr_dec_32(&cluster->async_conn_count);
417  as_queue_decr_total(queue);
418 }
419 
420 static inline void
422 {
423  as_queue* queue = cmd->pipe_listener != NULL ?
424  &cmd->node->pipe_conn_qs[cmd->event_loop->index] :
425  &cmd->node->async_conn_qs[cmd->event_loop->index];
426 
427  as_event_decr_connection(cmd->cluster, queue);
428 }
429 
430 #ifdef __cplusplus
431 } // end extern "C"
432 #endif