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  * COMMON FUNCTIONS
145  *****************************************************************************/
146 
147 as_status
149 
150 void
152 
153 void
154 as_event_executor_cancel(as_event_executor* executor, int queued_count);
155 
158 
159 int
161 
162 void
164 
165 void
167 
168 void
170 
171 void
173 
174 void
176 
177 bool
179 
180 bool
182 
183 bool
185 
186 void
188 
189 /******************************************************************************
190  * IMPLEMENTATION SPECIFIC FUNCTIONS
191  *****************************************************************************/
192 
193 bool
195 
196 void
198 
199 bool
201 
202 void
204 
205 void
207 
208 void
210 
211 bool
213 
214 /******************************************************************************
215  * LIBEV INLINE FUNCTIONS
216  *****************************************************************************/
217 
218 #if defined(AS_USE_LIBEV)
219 
220 static inline int
222 {
223  return as_socket_validate(conn->fd);
224 }
225 
226 static inline void
228 {
229  if (cmd->timeout_ms) {
230  ev_timer_stop(cmd->event_loop->loop, &cmd->timer);
231  }
232 }
233 
234 static inline void
236 {
237  ev_io_stop(cmd->event_loop->loop, &conn->watcher);
238 }
239 
240 static inline void
242 {
244 }
245 
246 /******************************************************************************
247  * LIBUV INLINE FUNCTIONS
248  *****************************************************************************/
249 
250 #elif defined(AS_USE_LIBUV)
251 
252 static inline int
254 {
255  // Libuv does not have a peek function, so use fd directly.
256  uv_os_fd_t fd;
257 
258  if (uv_fileno((uv_handle_t*)&conn->socket, &fd) == 0) {
259  return as_socket_validate(fd);
260  }
261  return false;
262 }
263 
264 static inline void
266 {
267  // Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
268 }
269 
270 static inline void
272 {
273  // Watcher already stopped by design in libuv.
274 }
275 
276 void
277 as_uv_timer_closed(uv_handle_t* handle);
278 
279 static inline void
281 {
282  if (cmd->timeout_ms) {
283  // libuv requires that cmd can't be freed until timer is closed.
284  uv_close((uv_handle_t*)&cmd->timer, as_uv_timer_closed);
285  }
286  else {
288  }
289 }
290 
291 /******************************************************************************
292  * EVENT_LIB NOT DEFINED INLINE FUNCTIONS
293  *****************************************************************************/
294 
295 #else
296 
297 static inline int
299 {
300  return -1;
301 }
302 
303 static inline void
305 {
306 }
307 
308 static inline void
310 {
311 }
312 
313 static inline void
315 {
316 }
317 
318 #endif
319 
320 /******************************************************************************
321  * COMMON INLINE FUNCTIONS
322  *****************************************************************************/
323 
324 static inline void
326 {
327  // Check if command timed out after coming off queue.
328  if (cmd->timeout_ms && (cf_getms() - *(uint64_t*)cmd) > cmd->timeout_ms) {
329  as_error err;
331  // Tell the libuv version of as_event_command_release() to not try to close the uv_timer_t.
332  cmd->timeout_ms = 0;
333  as_event_error_callback(cmd, &err);
334  return;
335  }
336 
337  // Start processing.
339 }
340 
341 static inline as_event_loop*
343 {
344  // Assign event loop using round robin distribution if not specified.
345  return event_loop ? event_loop : as_event_loop_get();
346 }
347 
348 static inline void
350 {
351  // The command buffer was already allocated with enough space for max authentication size,
352  // so just use the end of the write buffer for authentication bytes.
353  cmd->pos = cmd->len;
354  cmd->auth_len = as_authenticate_set(cmd->cluster->user, cmd->cluster->password, &cmd->buf[cmd->pos]);
355  cmd->len = cmd->pos + cmd->auth_len;
356 }
357 
358 static inline void
360 {
361  // Authenticate response buffer is at end of write buffer.
362  cmd->pos = cmd->len - cmd->auth_len;
363  cmd->auth_len = sizeof(as_proto);
364  cmd->len = cmd->pos + cmd->auth_len;
366 }
367 
368 static inline void
370 {
371  // Authenticate response buffer is at end of write buffer.
372  cmd->pos = cmd->len - cmd->auth_len;
373  as_proto* proto = (as_proto*)&cmd->buf[cmd->pos];
374  as_proto_swap_from_be(proto);
375  cmd->auth_len = (uint32_t)proto->sz;
376  cmd->len = cmd->pos + cmd->auth_len;
378 }
379 
380 static inline void
382 {
384  ck_pr_dec_32(&cluster->async_conn_count);
385  as_queue_decr_total(queue);
386 }
387 
388 static inline void
390 {
391  ck_pr_dec_32(&cluster->async_conn_count);
392  as_queue_decr_total(queue);
393 }
394 
395 static inline void
397 {
398  as_queue* queue = cmd->pipe_listener != NULL ?
399  &cmd->node->pipe_conn_qs[cmd->event_loop->index] :
400  &cmd->node->async_conn_qs[cmd->event_loop->index];
401 
402  as_event_decr_connection(cmd->cluster, queue);
403 }
404 
405 #ifdef __cplusplus
406 } // end extern "C"
407 #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)
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:892
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:68
uint32_t async_conn_count
Definition: as_cluster.h:276
static as_event_loop * as_event_loop_get()
Definition: as_event.h:218
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_release_connection(as_cluster *cluster, as_event_connection *conn, as_queue *queue)
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)
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