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 void
196 
197 /******************************************************************************
198  * IMPLEMENTATION SPECIFIC FUNCTIONS
199  *****************************************************************************/
200 
201 bool
203 
204 void
206 
207 bool
209 
210 void
212 
213 void
215 
216 void
218 
219 bool
221 
222 void
224 
225 /******************************************************************************
226  * LIBEV INLINE FUNCTIONS
227  *****************************************************************************/
228 
229 #if defined(AS_USE_LIBEV)
230 
231 static inline int
233 {
234  return as_socket_validate(conn->fd);
235 }
236 
237 static inline void
239 {
240  if (cmd->timeout_ms) {
241  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
242  }
243 }
244 
245 static inline void
247 {
248  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
249 }
250 
251 static inline void
253 {
255 }
256 
257 /******************************************************************************
258  * LIBUV INLINE FUNCTIONS
259  *****************************************************************************/
260 
261 #elif defined(AS_USE_LIBUV)
262 
263 static inline int
265 {
266  // Libuv does not have a peek function, so use fd directly.
267  uv_os_fd_t fd;
268 
269  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
270  return as_socket_validate(fd);
271  }
272  return false;
273 }
274 
275 static inline void
277 {
278  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
279 }
280 
281 static inline void
283 {
284  // Watcher already stopped by design in libuv.
285 }
286 
287 void
288 as_uv_timer_closed(uv_handle_t* handle);
289 
290 static inline void
292 {
293  if (cmd->timeout_ms) {
294  // libuv requires that cmd can't be freed until timer is closed.
295  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
296  }
297  else {
299  }
300 }
301 
302 /******************************************************************************
303  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
304  *****************************************************************************/
305 
306 #else
307 
308 static inline int
310 {
311  return -1;
312 }
313 
314 static inline void
316 {
317 }
318 
319 static inline void
321 {
322 }
323 
324 static inline void
326 {
327 }
328 
329 #endif
330 
331 /******************************************************************************
332  * COMMON INLINE FUNCTIONS
333  *****************************************************************************/
334 
335 static inline void
337 {
338  // Check if command timed out after coming off queue.
339  if (cmd->timeout_ms && (cf_getms() - *(uint64_t*)cmd) > cmd->timeout_ms) {
340  as_error err;
342  // Tell the libuv version of as_event_command_release() to not try to close the uv_timer_t.
343  cmd->timeout_ms = 0;
344  as_event_error_callback(cmd, &err);
345  return;
346  }
347 
348  // Start processing.
350 }
351 
352 static inline as_event_loop*
354 {
355  if (! event_loop) {
356  // Assign event loop using round robin distribution.
357  // Not atomic because doesn't need to be exactly accurate.
358  uint32_t current = as_event_loop_current++;
359  event_loop = &as_event_loops[current % as_event_loop_size];
360  }
361  return event_loop;
362 }
363 
364 static inline void
366 {
367  // The command buffer was already allocated with enough space for max authentication size,
368  // so just use the end of the write buffer for authentication bytes.
369  cmd->pos = cmd->len;
370  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
371  cmd->len = cmd->pos + cmd->auth_len;
372 }
373 
374 static inline void
376 {
377  // Authenticate response buffer is at end of write buffer.
378  cmd->pos = cmd->len - cmd->auth_len;
379  cmd->auth_len = sizeof(as_proto);
380  cmd->len = cmd->pos + cmd->auth_len;
382 }
383 
384 static inline void
386 {
387  // Authenticate response buffer is at end of write buffer.
388  cmd->pos = cmd->len - cmd->auth_len;
389  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
390  as_proto_swap_from_be(proto);
391  cmd->auth_len = (uint32_t)proto->sz;
392  cmd->len = cmd->pos + cmd->auth_len;
394 }
395 
396 static inline void
398 {
400  ck_pr_dec_32(&cluster->async_conn_count);
401  as_queue_decr_total(queue);
402 }
403 
404 static inline void
406 {
407  ck_pr_dec_32(&cluster->async_conn_count);
408  as_queue_decr_total(queue);
409 }
410 
411 static inline void
413 {
414  as_queue* queue = cmd->pipe_listener != NULL ?
415  &cmd->node->pipe_conn_qs[cmd->event_loop->index] :
416  &cmd->node->async_conn_qs[cmd->event_loop->index];
417 
418  as_event_decr_connection(cmd->cluster, queue);
419 }
420 
421 #ifdef __cplusplus
422 } // end extern "C"
423 #endif
as_event_loop * event_loop
int as_event_create_socket(as_event_command *cmd)
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)
uint32_t as_event_loop_size
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)
int as_socket_validate(int fd)
void as_event_executor_complete(as_event_command *cmd)
char * password
Definition: as_cluster.h:186
static void as_event_decr_connection(as_cluster *cluster, as_queue *queue)
as_cluster * cluster
bool as_event_send(as_event_command *cmd)
char * as_error_string(as_status status)
as_queue * async_conn_qs
Definition: as_node.h:126
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:60
as_proto proto
Definition: as_proto.h:847
char * user
Definition: as_cluster.h:180
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
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_command_begin(as_event_command *cmd)
bool as_event_send_close_loop(as_event_loop *event_loop)
void as_event_register_external_loop(as_event_loop *event_loop)
#define as_error_set_message(__err, __code, __msg)
Definition: as_error.h:143
uint32_t as_authenticate_set(const char *user, const char *credential, uint8_t *buffer)
static void as_event_command_execute_in_loop(as_event_command *cmd)
uint32_t index
Definition: as_event.h:67
uint32_t async_conn_count
Definition: as_cluster.h:276
cf_ll_element pipe_link
as_event_connection * conn
static void as_event_set_auth_write(as_event_command *cmd)
as_event_loop * as_event_loops
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_release_connection(as_cluster *cluster, as_event_connection *conn, as_queue *queue)
uint32_t as_event_loop_current
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)
void as_event_close_loop(as_event_loop *event_loop)
as_event_connection base
void as_event_error_callback(as_event_command *cmd, as_error *err)
as_queue * pipe_conn_qs
Definition: as_node.h:132
void as_event_connect_error(as_event_command *cmd, as_error *err, int fd)
as_connection_status as_event_get_connection(as_event_command *cmd)
static void as_queue_decr_total(as_queue *queue)
Definition: as_queue.h:170