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 bool
242 {
243  return as_socket_validate(conn->fd, pipeline);
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 bool
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, pipeline);
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 bool
319 {
320  return false;
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
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
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_socket_validate(int fd, bool pipe)
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:186
static void as_event_decr_connection(as_cluster *cluster, as_queue *queue)
static bool as_event_validate_connection(as_event_connection *conn, bool pipeline)
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)
#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)
uint32_t async_pending
Definition: as_cluster.h:270
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)
static void as_event_command_free(as_event_command *cmd)
static void as_node_release(as_node *node)
Definition: as_node.h:291
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