Main Page
Modules
Data Structures
Files
File List
Globals
All
Data Structures
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Friends
Macros
Groups
Pages
aerospike
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
;
80
}
as_event_connection
;
81
82
typedef
struct
{
83
as_event_connection
base
;
84
struct
as_event_command
*
cmd
;
85
}
as_async_connection
;
86
87
typedef
struct
{
88
as_pipe_listener
listener
;
89
void
*
udata
;
90
}
as_queued_pipe_cb
;
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
103
as_event_loop
*
event_loop
;
104
as_event_connection
*
conn
;
105
as_cluster
*
cluster
;
106
as_node
*
node
;
107
void
*
udata
;
108
as_event_parse_results_fn
parse_results
;
109
as_pipe_listener
pipe_listener
;
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
;
121
bool
deserialize
;
122
bool
free_buf
;
123
}
as_event_command
;
124
125
typedef
struct
as_event_executor
{
126
pthread_mutex_t
lock
;
127
struct
as_event_command
**
commands
;
128
as_event_loop
*
event_loop
;
129
as_event_executor_complete_fn
complete_fn
;
130
void
*
udata
;
131
uint32_t
max_concurrent
;
132
uint32_t
max
;
133
uint32_t
count
;
134
bool
valid
;
135
}
as_event_executor
;
136
137
typedef
enum
as_connection_status_e {
138
AS_CONNECTION_FROM_POOL
= 0,
139
AS_CONNECTION_NEW
= 1,
140
AS_CONNECTION_TOO_MANY
= 2
141
}
as_connection_status
;
142
143
/******************************************************************************
144
* GLOBAL VARIABLES
145
*****************************************************************************/
146
147
extern
as_event_loop
*
as_event_loops
;
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
156
as_event_command_execute
(
as_event_command
* cmd,
as_error
* err);
157
158
void
159
as_event_executor_complete
(
as_event_command
* cmd);
160
161
void
162
as_event_executor_cancel
(
as_event_executor
* executor,
int
queued_count);
163
164
as_connection_status
165
as_event_get_connection
(
as_event_command
* cmd);
166
167
int
168
as_event_create_socket
(
as_event_command
* cmd);
169
170
void
171
as_event_connect_error
(
as_event_command
* cmd,
as_error
* err,
int
fd);
172
173
void
174
as_event_error_callback
(
as_event_command
* cmd,
as_error
* err);
175
176
void
177
as_event_socket_error
(
as_event_command
* cmd,
as_error
* err);
178
179
void
180
as_event_response_error
(
as_event_command
* cmd,
as_error
* err);
181
182
void
183
as_event_timeout
(
as_event_command
* cmd);
184
185
bool
186
as_event_command_parse_result
(
as_event_command
* cmd);
187
188
bool
189
as_event_command_parse_header
(
as_event_command
* cmd);
190
191
bool
192
as_event_command_parse_success_failure
(
as_event_command
* cmd);
193
194
void
195
as_event_command_free
(
as_event_command
* cmd);
196
197
/******************************************************************************
198
* IMPLEMENTATION SPECIFIC FUNCTIONS
199
*****************************************************************************/
200
201
bool
202
as_event_create_loop
(
as_event_loop
*
event_loop
);
203
204
void
205
as_event_register_external_loop
(
as_event_loop
*
event_loop
);
206
207
bool
208
as_event_send
(
as_event_command
* cmd);
209
210
void
211
as_event_command_begin
(
as_event_command
* cmd);
212
213
void
214
as_event_close_connection
(
as_event_connection
*
conn
);
215
216
void
217
as_event_node_destroy
(
as_node
*
node
);
218
219
bool
220
as_event_send_close_loop
(
as_event_loop
*
event_loop
);
221
222
void
223
as_event_close_loop
(
as_event_loop
*
event_loop
);
224
225
/******************************************************************************
226
* LIBEV INLINE FUNCTIONS
227
*****************************************************************************/
228
229
#if defined(AS_USE_LIBEV)
230
231
static
inline
int
232
as_event_validate_connection
(
as_event_connection
*
conn
)
233
{
234
return
as_socket_validate
(conn->fd);
235
}
236
237
static
inline
void
238
as_event_stop_timer
(
as_event_command
* cmd)
239
{
240
if
(cmd->
timeout_ms
) {
241
ev_timer_stop(cmd->
event_loop
->
loop
, &cmd->timer);
242
}
243
}
244
245
static
inline
void
246
as_event_stop_watcher
(
as_event_command
* cmd,
as_event_connection
*
conn
)
247
{
248
ev_io_stop(cmd->
event_loop
->
loop
, &conn->watcher);
249
}
250
251
static
inline
void
252
as_event_command_release
(
as_event_command
* cmd)
253
{
254
as_event_command_free
(cmd);
255
}
256
257
/******************************************************************************
258
* LIBUV INLINE FUNCTIONS
259
*****************************************************************************/
260
261
#elif defined(AS_USE_LIBUV)
262
263
static
inline
int
264
as_event_validate_connection
(
as_event_connection
*
conn
)
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
276
as_event_stop_timer
(
as_event_command
* cmd)
277
{
278
// Timer is stopped in libuv by uv_close which occurs later in as_event_command_release().
279
}
280
281
static
inline
void
282
as_event_stop_watcher
(
as_event_command
* cmd,
as_event_connection
* conn)
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
291
as_event_command_release
(
as_event_command
* cmd)
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
{
298
as_event_command_free
(cmd);
299
}
300
}
301
302
/******************************************************************************
303
* EVENT_LIB NOT DEFINED INLINE FUNCTIONS
304
*****************************************************************************/
305
306
#else
307
308
static
inline
int
309
as_event_validate_connection
(
as_event_connection
* conn)
310
{
311
return
-1;
312
}
313
314
static
inline
void
315
as_event_stop_timer
(
as_event_command
* cmd)
316
{
317
}
318
319
static
inline
void
320
as_event_stop_watcher
(
as_event_command
* cmd,
as_event_connection
* conn)
321
{
322
}
323
324
static
inline
void
325
as_event_command_release
(
as_event_command
* cmd)
326
{
327
}
328
329
#endif
330
331
/******************************************************************************
332
* COMMON INLINE FUNCTIONS
333
*****************************************************************************/
334
335
static
inline
void
336
as_event_command_execute_in_loop
(
as_event_command
* cmd)
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;
341
as_error_set_message
(&err,
AEROSPIKE_ERR_TIMEOUT
,
as_error_string
(
AEROSPIKE_ERR_TIMEOUT
));
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.
349
as_event_command_begin
(cmd);
350
}
351
352
static
inline
as_event_loop
*
353
as_event_assign
(
as_event_loop
*
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
365
as_event_set_auth_write
(
as_event_command
* cmd)
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
375
as_event_set_auth_read_header
(
as_event_command
* cmd)
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
;
381
cmd->
state
=
AS_ASYNC_STATE_AUTH_READ_HEADER
;
382
}
383
384
static
inline
void
385
as_event_set_auth_parse_header
(
as_event_command
* cmd)
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
;
393
cmd->
state
=
AS_ASYNC_STATE_AUTH_READ_BODY
;
394
}
395
396
static
inline
void
397
as_event_release_connection
(
as_cluster
*
cluster
,
as_event_connection
* conn,
as_queue
* queue)
398
{
399
as_event_close_connection
(conn);
400
ck_pr_dec_32(&cluster->
async_conn_count
);
401
as_queue_decr_total
(queue);
402
}
403
404
static
inline
void
405
as_event_decr_connection
(
as_cluster
*
cluster
,
as_queue
* queue)
406
{
407
ck_pr_dec_32(&cluster->
async_conn_count
);
408
as_queue_decr_total
(queue);
409
}
410
411
static
inline
void
412
as_event_decr_conn
(
as_event_command
* cmd)
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