iodine 0.7.60 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.clang-format +15 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -3
  5. data/CHANGELOG.md +132 -12
  6. data/Gemfile +5 -7
  7. data/LICENSE.txt +1 -1
  8. data/README.md +147 -671
  9. data/Rakefile +9 -16
  10. data/examples/chatroom.nru +9 -0
  11. data/examples/client +74 -0
  12. data/examples/config-hello.nru +9 -0
  13. data/examples/config-hello.ru +11 -0
  14. data/examples/config-hijack.ru +13 -0
  15. data/examples/config-shootout.ru +43 -0
  16. data/examples/config.nru +120 -0
  17. data/examples/config.rb +37 -0
  18. data/examples/config.ru +42 -53
  19. data/examples/fake +24 -0
  20. data/examples/hello_neorack +137 -0
  21. data/examples/routes.nru +29 -0
  22. data/examples/routes.ru +42 -0
  23. data/exe/iodine +218 -258
  24. data/ext/iodine/extconf.rb +27 -100
  25. data/ext/iodine/fio-stl.h +128336 -0
  26. data/ext/iodine/fio-stl.md +26396 -0
  27. data/ext/iodine/iodine.c +213 -1393
  28. data/ext/iodine/iodine.h +250 -55
  29. data/ext/iodine/iodine_arg_helper.h +329 -0
  30. data/ext/iodine/iodine_caller.h +234 -25
  31. data/ext/iodine/iodine_cli.h +434 -0
  32. data/ext/iodine/iodine_compression.h +312 -0
  33. data/ext/iodine/iodine_connection.h +3484 -34
  34. data/ext/iodine/iodine_core.h +363 -0
  35. data/ext/iodine/iodine_crypto.h +1441 -0
  36. data/ext/iodine/iodine_defer.h +225 -4
  37. data/ext/iodine/iodine_json.h +738 -4
  38. data/ext/iodine/iodine_listener.h +263 -0
  39. data/ext/iodine/iodine_log.h +297 -0
  40. data/ext/iodine/iodine_minimap.h +543 -0
  41. data/ext/iodine/iodine_mustache.h +461 -4
  42. data/ext/iodine/iodine_pubsub_eng.h +729 -0
  43. data/ext/iodine/iodine_pubsub_history.h +547 -0
  44. data/ext/iodine/iodine_pubsub_msg.h +228 -0
  45. data/ext/iodine/iodine_redis.h +322 -0
  46. data/ext/iodine/iodine_store.h +418 -16
  47. data/ext/iodine/iodine_threads.h +279 -0
  48. data/ext/iodine/iodine_tls.h +515 -6
  49. data/ext/iodine/iodine_utils.h +923 -0
  50. data/iodine.gemspec +37 -42
  51. data/lib/iodine/benchmark.rb +1690 -0
  52. data/lib/iodine/documentation.rb +3085 -0
  53. data/lib/iodine/version.rb +17 -1
  54. data/lib/iodine.rb +54 -255
  55. data/logo.svg +36 -0
  56. data/mustache.md +55 -0
  57. data/sig/iodine.rbs +4 -0
  58. metadata +58 -184
  59. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  60. data/.github/workflows/ruby.yml +0 -42
  61. data/.gitignore +0 -21
  62. data/LIMITS.md +0 -41
  63. data/SPEC-PubSub-Draft.md +0 -159
  64. data/SPEC-WebSocket-Draft.md +0 -239
  65. data/bin/console +0 -22
  66. data/bin/info.md +0 -353
  67. data/bin/mustache_bench.rb +0 -100
  68. data/bin/poc/Gemfile.lock +0 -23
  69. data/bin/poc/README.md +0 -37
  70. data/bin/poc/config.ru +0 -66
  71. data/bin/poc/gemfile +0 -1
  72. data/bin/poc/www/index.html +0 -57
  73. data/examples/async_task.ru +0 -92
  74. data/examples/bates/README.md +0 -3
  75. data/examples/bates/config.ru +0 -342
  76. data/examples/bates/david+bold.pdf +0 -0
  77. data/examples/bates/public/drop-pdf.png +0 -0
  78. data/examples/bates/public/index.html +0 -600
  79. data/examples/echo.ru +0 -59
  80. data/examples/etag.ru +0 -16
  81. data/examples/hello.ru +0 -29
  82. data/examples/pubsub_engine.ru +0 -81
  83. data/examples/rack3.ru +0 -12
  84. data/examples/redis.ru +0 -70
  85. data/examples/shootout.ru +0 -73
  86. data/examples/sub-protocols.ru +0 -90
  87. data/examples/tcp_client.rb +0 -66
  88. data/examples/x-sendfile.ru +0 -14
  89. data/ext/iodine/fio.c +0 -11995
  90. data/ext/iodine/fio.h +0 -6371
  91. data/ext/iodine/fio_cli.c +0 -431
  92. data/ext/iodine/fio_cli.h +0 -189
  93. data/ext/iodine/fio_json_parser.h +0 -688
  94. data/ext/iodine/fio_siphash.c +0 -157
  95. data/ext/iodine/fio_siphash.h +0 -37
  96. data/ext/iodine/fio_tls.h +0 -129
  97. data/ext/iodine/fio_tls_missing.c +0 -649
  98. data/ext/iodine/fio_tls_openssl.c +0 -1106
  99. data/ext/iodine/fio_tmpfile.h +0 -50
  100. data/ext/iodine/fiobj.h +0 -44
  101. data/ext/iodine/fiobj4fio.h +0 -21
  102. data/ext/iodine/fiobj_ary.c +0 -333
  103. data/ext/iodine/fiobj_ary.h +0 -139
  104. data/ext/iodine/fiobj_data.c +0 -1187
  105. data/ext/iodine/fiobj_data.h +0 -167
  106. data/ext/iodine/fiobj_hash.c +0 -409
  107. data/ext/iodine/fiobj_hash.h +0 -176
  108. data/ext/iodine/fiobj_json.c +0 -622
  109. data/ext/iodine/fiobj_json.h +0 -68
  110. data/ext/iodine/fiobj_mem.h +0 -71
  111. data/ext/iodine/fiobj_mustache.c +0 -317
  112. data/ext/iodine/fiobj_mustache.h +0 -62
  113. data/ext/iodine/fiobj_numbers.c +0 -344
  114. data/ext/iodine/fiobj_numbers.h +0 -127
  115. data/ext/iodine/fiobj_str.c +0 -433
  116. data/ext/iodine/fiobj_str.h +0 -172
  117. data/ext/iodine/fiobject.c +0 -620
  118. data/ext/iodine/fiobject.h +0 -655
  119. data/ext/iodine/hpack.h +0 -1923
  120. data/ext/iodine/http.c +0 -2743
  121. data/ext/iodine/http.h +0 -1002
  122. data/ext/iodine/http1.c +0 -910
  123. data/ext/iodine/http1.h +0 -29
  124. data/ext/iodine/http1_parser.h +0 -878
  125. data/ext/iodine/http_internal.c +0 -1279
  126. data/ext/iodine/http_internal.h +0 -237
  127. data/ext/iodine/http_mime_parser.h +0 -350
  128. data/ext/iodine/iodine_caller.c +0 -230
  129. data/ext/iodine/iodine_connection.c +0 -941
  130. data/ext/iodine/iodine_defer.c +0 -420
  131. data/ext/iodine/iodine_fiobj2rb.h +0 -120
  132. data/ext/iodine/iodine_helpers.c +0 -282
  133. data/ext/iodine/iodine_helpers.h +0 -12
  134. data/ext/iodine/iodine_http.c +0 -1181
  135. data/ext/iodine/iodine_http.h +0 -23
  136. data/ext/iodine/iodine_json.c +0 -302
  137. data/ext/iodine/iodine_mustache.c +0 -567
  138. data/ext/iodine/iodine_pubsub.c +0 -580
  139. data/ext/iodine/iodine_pubsub.h +0 -26
  140. data/ext/iodine/iodine_rack_io.c +0 -273
  141. data/ext/iodine/iodine_rack_io.h +0 -20
  142. data/ext/iodine/iodine_store.c +0 -148
  143. data/ext/iodine/iodine_tcp.c +0 -346
  144. data/ext/iodine/iodine_tcp.h +0 -13
  145. data/ext/iodine/iodine_tls.c +0 -261
  146. data/ext/iodine/mustache_parser.h +0 -1546
  147. data/ext/iodine/redis_engine.c +0 -957
  148. data/ext/iodine/redis_engine.h +0 -79
  149. data/ext/iodine/resp_parser.h +0 -317
  150. data/ext/iodine/websocket_parser.h +0 -506
  151. data/ext/iodine/websockets.c +0 -743
  152. data/ext/iodine/websockets.h +0 -185
  153. data/lib/iodine/connection.rb +0 -61
  154. data/lib/iodine/json.rb +0 -42
  155. data/lib/iodine/mustache.rb +0 -113
  156. data/lib/iodine/pubsub.rb +0 -55
  157. data/lib/iodine/rack_utils.rb +0 -43
  158. data/lib/iodine/tls.rb +0 -16
  159. data/lib/rack/handler/iodine.rb +0 -33
  160. data/logo.png +0 -0
@@ -1,957 +0,0 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2019
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
-
8
- #define FIO_INCLUDE_LINKED_LIST
9
- #define FIO_INCLUDE_STR
10
- // #define DEBUG 1
11
- #include <fio.h>
12
-
13
- #include <fiobj.h>
14
-
15
- #include <redis_engine.h>
16
- #include <resp_parser.h>
17
-
18
- #define REDIS_READ_BUFFER 8192
19
- /* *****************************************************************************
20
- The Redis Engine and Callbacks Object
21
- ***************************************************************************** */
22
-
23
- typedef struct {
24
- fio_pubsub_engine_s en;
25
- struct redis_engine_internal_s {
26
- fio_protocol_s protocol;
27
- intptr_t uuid;
28
- resp_parser_s parser;
29
- void (*on_message)(struct redis_engine_internal_s *parser, FIOBJ msg);
30
- FIOBJ str;
31
- FIOBJ ary;
32
- uint32_t ary_count;
33
- uint16_t buf_pos;
34
- uint16_t nesting;
35
- } pub_data, sub_data;
36
- subscription_s *publication_forwarder;
37
- subscription_s *cmd_forwarder;
38
- subscription_s *cmd_reply;
39
- char *address;
40
- char *port;
41
- char *auth;
42
- FIOBJ last_ch;
43
- size_t auth_len;
44
- size_t ref;
45
- fio_ls_embd_s queue;
46
- fio_lock_i lock;
47
- fio_lock_i lock_connection;
48
- uint8_t ping_int;
49
- volatile uint8_t pub_sent;
50
- volatile uint8_t flag;
51
- uint8_t buf[];
52
- } redis_engine_s;
53
-
54
- typedef struct {
55
- fio_ls_embd_s node;
56
- void (*callback)(fio_pubsub_engine_s *e, FIOBJ reply, void *udata);
57
- void *udata;
58
- size_t cmd_len;
59
- uint8_t cmd[];
60
- } redis_commands_s;
61
-
62
- /** converts from a publishing protocol to an `redis_engine_s`. */
63
- #define pub2redis(pr) FIO_LS_EMBD_OBJ(redis_engine_s, pub_data, (pr))
64
- /** converts from a subscribing protocol to an `redis_engine_s`. */
65
- #define sub2redis(pr) FIO_LS_EMBD_OBJ(redis_engine_s, sub_data, (pr))
66
-
67
- /** converts from a `resp_parser_s` to the internal data structure. */
68
- #define parser2data(prsr) \
69
- FIO_LS_EMBD_OBJ(struct redis_engine_internal_s, parser, (prsr))
70
-
71
- /* releases any resources used by an internal engine*/
72
- static inline void redis_internal_reset(struct redis_engine_internal_s *i) {
73
- i->buf_pos = 0;
74
- i->parser = (resp_parser_s){.obj_countdown = 0, .expecting = 0};
75
- fiobj_free((FIOBJ)fio_ct_if(i->ary == FIOBJ_INVALID, (uintptr_t)i->str,
76
- (uintptr_t)i->ary));
77
- i->str = FIOBJ_INVALID;
78
- i->ary = FIOBJ_INVALID;
79
- i->ary_count = 0;
80
- i->nesting = 0;
81
- i->uuid = -1;
82
- }
83
-
84
- /** cleans up and frees the engine data. */
85
- static inline void redis_free(redis_engine_s *r) {
86
- if (fio_atomic_sub(&r->ref, 1))
87
- return;
88
- FIO_LOG_DEBUG("freeing redis engine for %s:%s", r->address, r->port);
89
- redis_internal_reset(&r->pub_data);
90
- redis_internal_reset(&r->sub_data);
91
- fiobj_free(r->last_ch);
92
- while (fio_ls_embd_any(&r->queue)) {
93
- fio_free(
94
- FIO_LS_EMBD_OBJ(redis_commands_s, node, fio_ls_embd_pop(&r->queue)));
95
- }
96
- fio_unsubscribe(r->publication_forwarder);
97
- r->publication_forwarder = NULL;
98
- fio_unsubscribe(r->cmd_forwarder);
99
- r->cmd_forwarder = NULL;
100
- fio_unsubscribe(r->cmd_reply);
101
- r->cmd_reply = NULL;
102
- fio_free(r);
103
- }
104
-
105
- /* *****************************************************************************
106
- Simple RESP formatting
107
- ***************************************************************************** */
108
-
109
- inline static void fiobj2resp___internal(FIOBJ dest, FIOBJ obj) {
110
- fio_str_info_s s;
111
- switch (FIOBJ_TYPE(obj)) {
112
- case FIOBJ_T_NULL:
113
- fiobj_str_write(dest, "$-1\r\n", 5);
114
- break;
115
- case FIOBJ_T_ARRAY:
116
- fiobj_str_write(dest, "*", 1);
117
- fiobj_str_write_i(dest, fiobj_ary_count(obj));
118
- fiobj_str_write(dest, "\r\n", 2);
119
- break;
120
- case FIOBJ_T_HASH:
121
- fiobj_str_write(dest, "*", 1);
122
- fiobj_str_write_i(dest, fiobj_hash_count(obj) * 2);
123
- fiobj_str_write(dest, "\r\n", 2);
124
- break;
125
- case FIOBJ_T_TRUE:
126
- fiobj_str_write(dest, "$4\r\ntrue\r\n", 10);
127
- break;
128
- case FIOBJ_T_FALSE:
129
- fiobj_str_write(dest, "$4\r\nfalse\r\n", 11);
130
- break;
131
- #if 0
132
- /* Numbers aren't as good for commands as one might think... */
133
- case FIOBJ_T_NUMBER:
134
- fiobj_str_write(dest, ":", 1);
135
- fiobj_str_write_i(dest, fiobj_obj2num(obj));
136
- fiobj_str_write(dest, "\r\n", 2);
137
- break;
138
- #else
139
- case FIOBJ_T_NUMBER: /* overflow */
140
- #endif
141
- case FIOBJ_T_FLOAT: /* overflow */
142
- case FIOBJ_T_UNKNOWN: /* overflow */
143
- case FIOBJ_T_STRING: /* overflow */
144
- case FIOBJ_T_DATA:
145
- s = fiobj_obj2cstr(obj);
146
- fiobj_str_write(dest, "$", 1);
147
- fiobj_str_write_i(dest, s.len);
148
- fiobj_str_write(dest, "\r\n", 2);
149
- fiobj_str_write(dest, s.data, s.len);
150
- fiobj_str_write(dest, "\r\n", 2);
151
- break;
152
- }
153
- }
154
-
155
- static int fiobj2resp_task(FIOBJ o, void *dest_) {
156
- if (fiobj_hash_key_in_loop())
157
- fiobj2resp___internal((FIOBJ)dest_, fiobj_hash_key_in_loop());
158
- fiobj2resp___internal((FIOBJ)dest_, o);
159
- return 0;
160
- }
161
-
162
- /**
163
- * Converts FIOBJ objects into a RESP string (client mode).
164
- */
165
- static FIOBJ fiobj2resp(FIOBJ dest, FIOBJ obj) {
166
- fiobj_each2(obj, fiobj2resp_task, (void *)dest);
167
- return dest;
168
- }
169
-
170
- /**
171
- * Converts FIOBJ objects into a RESP string (client mode).
172
- *
173
- * Don't call `fiobj_free`, object will self-destruct.
174
- */
175
- static inline FIOBJ fiobj2resp_tmp(FIOBJ obj) {
176
- return fiobj2resp(fiobj_str_tmp(), obj);
177
- }
178
-
179
- /* *****************************************************************************
180
- RESP parser callbacks
181
- ***************************************************************************** */
182
-
183
- /** a local static callback, called when a parser / protocol error occurs. */
184
- static int resp_on_parser_error(resp_parser_s *parser) {
185
- struct redis_engine_internal_s *i = parser2data(parser);
186
- FIO_LOG_ERROR("(redis) parser error - attempting to restart connection.\n");
187
- fio_close(i->uuid);
188
- return -1;
189
- }
190
-
191
- /** a local static callback, called when the RESP message is complete. */
192
- static int resp_on_message(resp_parser_s *parser) {
193
- struct redis_engine_internal_s *i = parser2data(parser);
194
- FIOBJ msg = i->ary ? i->ary : i->str;
195
- i->on_message(i, msg);
196
- /* cleanup */
197
- fiobj_free(msg);
198
- i->ary = FIOBJ_INVALID;
199
- i->str = FIOBJ_INVALID;
200
- return 0;
201
- }
202
-
203
- /** a local helper to add parsed objects to the data store. */
204
- static inline void resp_add_obj(struct redis_engine_internal_s *dest, FIOBJ o) {
205
- if (dest->ary) {
206
- fiobj_ary_push(dest->ary, o);
207
- --dest->ary_count;
208
- if (!dest->ary_count && dest->nesting) {
209
- FIOBJ tmp = fiobj_ary_shift(dest->ary);
210
- dest->ary_count = fiobj_obj2num(tmp);
211
- fiobj_free(tmp);
212
- dest->ary = fiobj_ary_shift(dest->ary);
213
- --dest->nesting;
214
- }
215
- }
216
- dest->str = o;
217
- }
218
-
219
- /** a local static callback, called when a Number object is parsed. */
220
- static int resp_on_number(resp_parser_s *parser, int64_t num) {
221
- struct redis_engine_internal_s *data = parser2data(parser);
222
- resp_add_obj(data, fiobj_num_new(num));
223
- return 0;
224
- }
225
- /** a local static callback, called when a OK message is received. */
226
- static int resp_on_okay(resp_parser_s *parser) {
227
- struct redis_engine_internal_s *data = parser2data(parser);
228
- resp_add_obj(data, fiobj_true());
229
- return 0;
230
- }
231
- /** a local static callback, called when NULL is received. */
232
- static int resp_on_null(resp_parser_s *parser) {
233
- struct redis_engine_internal_s *data = parser2data(parser);
234
- resp_add_obj(data, fiobj_null());
235
- return 0;
236
- }
237
-
238
- /**
239
- * a local static callback, called when a String should be allocated.
240
- *
241
- * `str_len` is the expected number of bytes that will fill the final string
242
- * object, without any NUL byte marker (the string might be binary).
243
- *
244
- * If this function returns any value besides 0, parsing is stopped.
245
- */
246
- static int resp_on_start_string(resp_parser_s *parser, size_t str_len) {
247
- struct redis_engine_internal_s *data = parser2data(parser);
248
- resp_add_obj(data, fiobj_str_buf(str_len));
249
- return 0;
250
- }
251
- /** a local static callback, called as String objects are streamed. */
252
- static int resp_on_string_chunk(resp_parser_s *parser, void *data, size_t len) {
253
- struct redis_engine_internal_s *i = parser2data(parser);
254
- fiobj_str_write(i->str, data, len);
255
- return 0;
256
- }
257
- /** a local static callback, called when a String object had finished
258
- * streaming.
259
- */
260
- static int resp_on_end_string(resp_parser_s *parser) {
261
- return 0;
262
- (void)parser;
263
- }
264
-
265
- /** a local static callback, called an error message is received. */
266
- static int resp_on_err_msg(resp_parser_s *parser, void *data, size_t len) {
267
- struct redis_engine_internal_s *i = parser2data(parser);
268
- resp_add_obj(i, fiobj_str_new(data, len));
269
- return 0;
270
- }
271
-
272
- /**
273
- * a local static callback, called when an Array should be allocated.
274
- *
275
- * `array_len` is the expected number of objects that will fill the Array
276
- * object.
277
- *
278
- * There's no `resp_on_end_array` callback since the RESP protocol assumes the
279
- * message is finished along with the Array (`resp_on_message` is called).
280
- * However, just in case a non-conforming client/server sends nested Arrays,
281
- * the callback should test against possible overflow or nested Array endings.
282
- *
283
- * If this function returns any value besides 0, parsing is stopped.
284
- */
285
- static int resp_on_start_array(resp_parser_s *parser, size_t array_len) {
286
- struct redis_engine_internal_s *i = parser2data(parser);
287
- if (i->ary) {
288
- ++i->nesting;
289
- FIOBJ tmp = fiobj_ary_new2(array_len + 2);
290
- fiobj_ary_push(tmp, fiobj_num_new(i->ary_count));
291
- fiobj_ary_push(tmp, fiobj_num_new(i->ary));
292
- i->ary = tmp;
293
- } else {
294
- i->ary = fiobj_ary_new2(array_len + 2);
295
- }
296
- i->ary_count = array_len;
297
- return 0;
298
- }
299
-
300
- /* *****************************************************************************
301
- Publication and Command Handling
302
- ***************************************************************************** */
303
-
304
- /* the deferred callback handler */
305
- static void redis_perform_callback(void *e, void *cmd_) {
306
- redis_commands_s *cmd = cmd_;
307
- FIOBJ reply = (FIOBJ)cmd->node.next;
308
- if (cmd->callback)
309
- cmd->callback(e, reply, cmd->udata);
310
- fiobj_free(reply);
311
- FIO_LOG_DEBUG("Handled: %s\n", cmd->cmd);
312
- fio_free(cmd);
313
- }
314
-
315
- /* send command within lock, to ensure flag integrity */
316
- static void redis_send_next_command_unsafe(redis_engine_s *r) {
317
- if (!r->pub_sent && fio_ls_embd_any(&r->queue)) {
318
- r->pub_sent = 1;
319
- redis_commands_s *cmd =
320
- FIO_LS_EMBD_OBJ(redis_commands_s, node, r->queue.next);
321
- fio_write2(r->pub_data.uuid, .data.buffer = cmd->cmd,
322
- .length = cmd->cmd_len, .after.dealloc = FIO_DEALLOC_NOOP);
323
- FIO_LOG_DEBUG("(redis %d) Sending (%zu bytes):\n%s\n", (int)getpid(),
324
- cmd->cmd_len, cmd->cmd);
325
- }
326
- }
327
-
328
- /* attach a command to the queue */
329
- static void redis_attach_cmd(redis_engine_s *r, redis_commands_s *cmd) {
330
- fio_lock(&r->lock);
331
- fio_ls_embd_push(&r->queue, &cmd->node);
332
- redis_send_next_command_unsafe(r);
333
- fio_unlock(&r->lock);
334
- }
335
-
336
- /** a local static callback, called when the RESP message is complete. */
337
- static void resp_on_pub_message(struct redis_engine_internal_s *i, FIOBJ msg) {
338
- redis_engine_s *r = pub2redis(i);
339
- // #if DEBUG
340
- if (FIO_LOG_LEVEL >= FIO_LOG_LEVEL_DEBUG) {
341
- FIOBJ json = fiobj_obj2json(msg, 1);
342
- FIO_LOG_DEBUG("Redis reply:\n%s\n", fiobj_obj2cstr(json).data);
343
- fiobj_free(json);
344
- }
345
- // #endif
346
- /* publishing / command parser */
347
- fio_lock(&r->lock);
348
- fio_ls_embd_s *node = fio_ls_embd_shift(&r->queue);
349
- r->pub_sent = 0;
350
- redis_send_next_command_unsafe(r);
351
- fio_unlock(&r->lock);
352
- if (!node) {
353
- /* TODO: possible ping? from server?! not likely... */
354
- FIO_LOG_WARNING("(redis %d) received a reply when no command was sent.",
355
- (int)getpid());
356
- return;
357
- }
358
- node->next = (void *)fiobj_dup(msg);
359
- fio_defer(redis_perform_callback, &r->en,
360
- FIO_LS_EMBD_OBJ(redis_commands_s, node, node));
361
- }
362
-
363
- /* *****************************************************************************
364
- Subscription Message Handling
365
- ***************************************************************************** */
366
-
367
- /** a local static callback, called when the RESP message is complete. */
368
- static void resp_on_sub_message(struct redis_engine_internal_s *i, FIOBJ msg) {
369
- redis_engine_s *r = sub2redis(i);
370
- /* subscriotion parser */
371
- if (FIOBJ_TYPE(msg) != FIOBJ_T_ARRAY) {
372
- if (FIOBJ_TYPE(msg) != FIOBJ_T_STRING || fiobj_obj2cstr(msg).len != 4 ||
373
- fiobj_obj2cstr(msg).data[0] != 'P') {
374
- FIO_LOG_WARNING("(redis) unexpected data format in "
375
- "subscription stream (%zu bytes):\n %s\n",
376
- fiobj_obj2cstr(msg).len, fiobj_obj2cstr(msg).data);
377
- }
378
- } else {
379
- // FIOBJ *ary = fiobj_ary2ptr(msg);
380
- // for (size_t i = 0; i < fiobj_ary_count(msg); ++i) {
381
- // fio_str_info_s tmp = fiobj_obj2cstr(ary[i]);
382
- // fprintf(stderr, "(%lu) %s\n", (unsigned long)i, tmp.data);
383
- // }
384
- fio_str_info_s tmp = fiobj_obj2cstr(fiobj_ary_index(msg, 0));
385
- if (tmp.len == 7) { /* "message" */
386
- fiobj_free(r->last_ch);
387
- r->last_ch = fiobj_dup(fiobj_ary_index(msg, 1));
388
- fio_publish(.channel = fiobj_obj2cstr(r->last_ch),
389
- .message = fiobj_obj2cstr(fiobj_ary_index(msg, 2)),
390
- .engine = FIO_PUBSUB_CLUSTER);
391
- } else if (tmp.len == 8) { /* "pmessage" */
392
- if (!fiobj_iseq(r->last_ch, fiobj_ary_index(msg, 2)))
393
- fio_publish(.channel = fiobj_obj2cstr(fiobj_ary_index(msg, 2)),
394
- .message = fiobj_obj2cstr(fiobj_ary_index(msg, 3)),
395
- .engine = FIO_PUBSUB_CLUSTER);
396
- }
397
- }
398
- }
399
-
400
- /* *****************************************************************************
401
- Connection Callbacks (fio_protocol_s) and Engine
402
- ***************************************************************************** */
403
-
404
- /** defined later - connects to Redis */
405
- static void redis_connect(void *r, void *i);
406
-
407
- #define defer_redis_connect(r, i) \
408
- do { \
409
- fio_atomic_add(&(r)->ref, 1); \
410
- fio_defer(redis_connect, (r), (i)); \
411
- } while (0);
412
-
413
- /** Called when a data is available, but will not run concurrently */
414
- static void redis_on_data(intptr_t uuid, fio_protocol_s *pr) {
415
- struct redis_engine_internal_s *internal =
416
- (struct redis_engine_internal_s *)pr;
417
- uint8_t *buf;
418
- if (internal->on_message == resp_on_sub_message) {
419
- buf = sub2redis(pr)->buf + REDIS_READ_BUFFER;
420
- } else {
421
- buf = pub2redis(pr)->buf;
422
- }
423
- ssize_t i = fio_read(uuid, buf + internal->buf_pos,
424
- REDIS_READ_BUFFER - internal->buf_pos);
425
- if (i <= 0)
426
- return;
427
-
428
- internal->buf_pos += i;
429
- i = resp_parse(&internal->parser, buf, internal->buf_pos);
430
- if (i) {
431
- memmove(buf, buf + internal->buf_pos - i, i);
432
- }
433
- internal->buf_pos = i;
434
- }
435
-
436
- /** Called when the connection was closed, but will not run concurrently */
437
- static void redis_on_close(intptr_t uuid, fio_protocol_s *pr) {
438
- struct redis_engine_internal_s *internal =
439
- (struct redis_engine_internal_s *)pr;
440
- redis_internal_reset(internal);
441
- redis_engine_s *r;
442
- if (internal->on_message == resp_on_sub_message) {
443
- r = sub2redis(pr);
444
- fiobj_free(r->last_ch);
445
- r->last_ch = FIOBJ_INVALID;
446
- if (r->flag) {
447
- /* reconnection for subscription connection. */
448
- if (uuid != -1) {
449
- FIO_LOG_WARNING("(redis %d) subscription connection lost. "
450
- "Reconnecting...",
451
- (int)getpid());
452
- }
453
- fio_atomic_sub(&r->ref, 1);
454
- defer_redis_connect(r, internal);
455
- } else {
456
- redis_free(r);
457
- }
458
- } else {
459
- r = pub2redis(pr);
460
- if (r->flag && uuid != -1) {
461
- FIO_LOG_WARNING("(redis %d) publication connection lost. "
462
- "Reconnecting...",
463
- (int)getpid());
464
- }
465
- r->pub_sent = 0;
466
- fio_close(r->sub_data.uuid);
467
- redis_free(r);
468
- }
469
- (void)uuid;
470
- }
471
-
472
- /** Called before the facil.io reactor is shut down. */
473
- static uint8_t redis_on_shutdown(intptr_t uuid, fio_protocol_s *pr) {
474
- fio_write2(uuid, .data.buffer = "*1\r\n$4\r\nQUIT\r\n", .length = 14,
475
- .after.dealloc = FIO_DEALLOC_NOOP);
476
- return 0;
477
- (void)pr;
478
- }
479
-
480
- /** Called on connection timeout. */
481
- static void redis_sub_ping(intptr_t uuid, fio_protocol_s *pr) {
482
- fio_write2(uuid, .data.buffer = "*1\r\n$4\r\nPING\r\n", .length = 14,
483
- .after.dealloc = FIO_DEALLOC_NOOP);
484
- (void)pr;
485
- }
486
-
487
- /** Called on connection timeout. */
488
- static void redis_pub_ping(intptr_t uuid, fio_protocol_s *pr) {
489
- redis_engine_s *r = pub2redis(pr);
490
- if (fio_ls_embd_any(&r->queue)) {
491
- FIO_LOG_WARNING("(redis) Redis server unresponsive, disconnecting.");
492
- fio_close(uuid);
493
- return;
494
- }
495
- redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + 15);
496
- FIO_ASSERT_ALLOC(cmd);
497
- *cmd = (redis_commands_s){.cmd_len = 14};
498
- memcpy(cmd->cmd, "*1\r\n$4\r\nPING\r\n\0", 15);
499
- redis_attach_cmd(r, cmd);
500
- }
501
-
502
- /* *****************************************************************************
503
- Connecting to Redis
504
- ***************************************************************************** */
505
-
506
- static void redis_on_auth(fio_pubsub_engine_s *e, FIOBJ reply, void *udata) {
507
- if (FIOBJ_TYPE_IS(reply, FIOBJ_T_TRUE)) {
508
- fio_str_info_s s = fiobj_obj2cstr(reply);
509
- FIO_LOG_WARNING("(redis) Authentication FAILED."
510
- " %.*s",
511
- (int)s.len, s.data);
512
- }
513
- (void)e;
514
- (void)udata;
515
- }
516
-
517
- static void redis_on_connect(intptr_t uuid, void *i_) {
518
- struct redis_engine_internal_s *i = i_;
519
- redis_engine_s *r;
520
- i->uuid = uuid;
521
-
522
- if (i->on_message == resp_on_sub_message) {
523
- r = sub2redis(i);
524
- if (r->auth_len) {
525
- fio_write2(uuid, .data.buffer = r->auth, .length = r->auth_len,
526
- .after.dealloc = FIO_DEALLOC_NOOP);
527
- }
528
- fio_pubsub_reattach(&r->en);
529
- if (r->pub_data.uuid == -1) {
530
- defer_redis_connect(r, &r->pub_data);
531
- }
532
- FIO_LOG_INFO("(redis %d) subscription connection established.",
533
- (int)getpid());
534
- } else {
535
- r = pub2redis(i);
536
- if (r->auth_len) {
537
- redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + r->auth_len);
538
- FIO_ASSERT_ALLOC(cmd);
539
- *cmd =
540
- (redis_commands_s){.cmd_len = r->auth_len, .callback = redis_on_auth};
541
- memcpy(cmd->cmd, r->auth, r->auth_len);
542
- fio_lock(&r->lock);
543
- r->pub_sent = 0;
544
- fio_ls_embd_unshift(&r->queue, &cmd->node);
545
- redis_send_next_command_unsafe(r);
546
- fio_unlock(&r->lock);
547
- } else {
548
- fio_lock(&r->lock);
549
- r->pub_sent = 0;
550
- redis_send_next_command_unsafe(r);
551
- fio_unlock(&r->lock);
552
- }
553
- FIO_LOG_INFO("(redis %d) publication connection established.",
554
- (int)getpid());
555
- }
556
-
557
- i->protocol.rsv = 0;
558
- fio_attach(uuid, &i->protocol);
559
- fio_timeout_set(uuid, r->ping_int);
560
-
561
- return;
562
- }
563
-
564
- static void redis_on_connect_failed(intptr_t uuid, void *i_) {
565
- struct redis_engine_internal_s *i = i_;
566
- i->uuid = -1;
567
- i->protocol.on_close(-1, &i->protocol);
568
- (void)uuid;
569
- }
570
-
571
- static void redis_connect(void *r_, void *i_) {
572
- redis_engine_s *r = r_;
573
- struct redis_engine_internal_s *i = i_;
574
- fio_lock(&r->lock_connection);
575
- if (r->flag == 0 || i->uuid != -1 || !fio_is_running()) {
576
- fio_unlock(&r->lock_connection);
577
- redis_free(r);
578
- return;
579
- }
580
- // fio_atomic_add(&r->ref, 1);
581
- i->uuid = fio_connect(.address = r->address, .port = r->port,
582
- .on_connect = redis_on_connect, .udata = i,
583
- .on_fail = redis_on_connect_failed);
584
- fio_unlock(&r->lock_connection);
585
- }
586
-
587
- /* *****************************************************************************
588
- Engine / Bridge Callbacks (Root Process)
589
- ***************************************************************************** */
590
-
591
- static void redis_on_subscribe_root(const fio_pubsub_engine_s *eng,
592
- fio_str_info_s channel,
593
- fio_match_fn match) {
594
- redis_engine_s *r = (redis_engine_s *)eng;
595
- if (r->sub_data.uuid != -1) {
596
- FIOBJ cmd = fiobj_str_buf(96 + channel.len);
597
- if (match == FIO_MATCH_GLOB)
598
- fiobj_str_write(cmd, "*2\r\n$10\r\nPSUBSCRIBE\r\n$", 22);
599
- else
600
- fiobj_str_write(cmd, "*2\r\n$9\r\nSUBSCRIBE\r\n$", 20);
601
- fiobj_str_write_i(cmd, channel.len);
602
- fiobj_str_write(cmd, "\r\n", 2);
603
- fiobj_str_write(cmd, channel.data, channel.len);
604
- fiobj_str_write(cmd, "\r\n", 2);
605
- // {
606
- // fio_str_info_s s = fiobj_obj2cstr(cmd);
607
- // fprintf(stderr, "(%d) Sending Subscription (%p):\n%s\n", getpid(),
608
- // (void *)r->sub_data.uuid, s.data);
609
- // }
610
- fiobj_send_free(r->sub_data.uuid, cmd);
611
- }
612
- }
613
-
614
- static void redis_on_unsubscribe_root(const fio_pubsub_engine_s *eng,
615
- fio_str_info_s channel,
616
- fio_match_fn match) {
617
- redis_engine_s *r = (redis_engine_s *)eng;
618
- if (r->sub_data.uuid != -1) {
619
- fio_str_s *cmd = fio_str_new2();
620
- fio_str_capa_assert(cmd, 96 + channel.len);
621
- if (match == FIO_MATCH_GLOB)
622
- fio_str_write(cmd, "*2\r\n$12\r\nPUNSUBSCRIBE\r\n$", 24);
623
- else
624
- fio_str_write(cmd, "*2\r\n$11\r\nUNSUBSCRIBE\r\n$", 23);
625
- fio_str_write_i(cmd, channel.len);
626
- fio_str_write(cmd, "\r\n", 2);
627
- fio_str_write(cmd, channel.data, channel.len);
628
- fio_str_write(cmd, "\r\n", 2);
629
- // {
630
- // fio_str_info_s s = fio_str_info(cmd);
631
- // fprintf(stderr, "(%d) Cancel Subscription (%p):\n%s\n", getpid(),
632
- // (void *)r->sub_data.uuid, s.data);
633
- // }
634
- fio_str_send_free2(r->sub_data.uuid, cmd);
635
- }
636
- }
637
-
638
- static void redis_on_publish_root(const fio_pubsub_engine_s *eng,
639
- fio_str_info_s channel, fio_str_info_s msg,
640
- uint8_t is_json) {
641
- redis_engine_s *r = (redis_engine_s *)eng;
642
- redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + channel.len + msg.len + 96);
643
- FIO_ASSERT_ALLOC(cmd);
644
- *cmd = (redis_commands_s){.cmd_len = 0};
645
- memcpy(cmd->cmd, "*3\r\n$7\r\nPUBLISH\r\n$", 18);
646
- char *buf = (char *)cmd->cmd + 18;
647
- buf += fio_ltoa((void *)buf, channel.len, 10);
648
- *buf++ = '\r';
649
- *buf++ = '\n';
650
- memcpy(buf, channel.data, channel.len);
651
- buf += channel.len;
652
- *buf++ = '\r';
653
- *buf++ = '\n';
654
- *buf++ = '$';
655
- buf += fio_ltoa(buf, msg.len, 10);
656
- *buf++ = '\r';
657
- *buf++ = '\n';
658
- memcpy(buf, msg.data, msg.len);
659
- buf += msg.len;
660
- *buf++ = '\r';
661
- *buf++ = '\n';
662
- *buf = 0;
663
- FIO_LOG_DEBUG("(%d) Publishing:\n%s", (int)getpid(), cmd->cmd);
664
- cmd->cmd_len = (uintptr_t)buf - (uintptr_t)(cmd + 1);
665
- redis_attach_cmd(r, cmd);
666
- return;
667
- (void)is_json;
668
- }
669
-
670
- /* *****************************************************************************
671
- Engine / Bridge Stub Callbacks (Child Process)
672
- ***************************************************************************** */
673
-
674
- static void redis_on_mock_subscribe_child(const fio_pubsub_engine_s *eng,
675
- fio_str_info_s channel,
676
- fio_match_fn match) {
677
- /* do nothing, root process is notified about (un)subscriptions by facil.io */
678
- (void)eng;
679
- (void)channel;
680
- (void)match;
681
- }
682
-
683
- static void redis_on_publish_child(const fio_pubsub_engine_s *eng,
684
- fio_str_info_s channel, fio_str_info_s msg,
685
- uint8_t is_json) {
686
- /* attach engine data to channel (prepend) */
687
- fio_str_s tmp = FIO_STR_INIT;
688
- /* by using fio_str_s, short names are allocated on the stack */
689
- fio_str_info_s tmp_info = fio_str_resize(&tmp, channel.len + 8);
690
- fio_u2str64(tmp_info.data, (uintptr_t)eng);
691
- memcpy(tmp_info.data + 8, channel.data, channel.len);
692
- /* forward publication request to Root */
693
- fio_publish(.filter = -1, .channel = tmp_info, .message = msg,
694
- .engine = FIO_PUBSUB_ROOT, .is_json = is_json);
695
- fio_str_free(&tmp);
696
- (void)eng;
697
- }
698
-
699
- /* *****************************************************************************
700
- Root Publication Handler
701
- ***************************************************************************** */
702
-
703
- /* listens to filter -1 and publishes and messages */
704
- static void redis_on_internal_publish(fio_msg_s *msg) {
705
- if (msg->channel.len < 8)
706
- return; /* internal error, unexpected data */
707
- void *en = (void *)(uintptr_t)fio_str2u64(msg->channel.data);
708
- if (en != msg->udata1)
709
- return; /* should be delivered by a different engine */
710
- /* step after the engine data */
711
- msg->channel.len -= 8;
712
- msg->channel.data += 8;
713
- /* forward to publishing */
714
- FIO_LOG_DEBUG("Forwarding to engine %p, on channel %s", msg->udata1,
715
- msg->channel.data);
716
- redis_on_publish_root(msg->udata1, msg->channel, msg->msg, msg->is_json);
717
- }
718
-
719
- /* *****************************************************************************
720
- Sending commands using the Root connection
721
- ***************************************************************************** */
722
-
723
- /* callback from the Redis reply */
724
- static void redis_forward_reply(fio_pubsub_engine_s *e, FIOBJ reply,
725
- void *udata) {
726
- uint8_t *data = udata;
727
- fio_pubsub_engine_s *engine = (fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(data + 0);
728
- void *callback = (void *)(uintptr_t)fio_str2u64(data + 8);
729
- if (engine != e || !callback) {
730
- FIO_LOG_DEBUG("Redis reply not forwarded (callback: %p)", callback);
731
- return;
732
- }
733
- int32_t pid = (int32_t)fio_str2u32(data + 24);
734
- FIOBJ rp = fiobj_obj2json(reply, 0);
735
- fio_publish(.filter = (-10 - (int32_t)pid), .channel.data = (char *)data,
736
- .channel.len = 28, .message = fiobj_obj2cstr(rp), .is_json = 1);
737
- fiobj_free(rp);
738
- }
739
-
740
- /* listens to channel -2 for commands that need to be sent (only ROOT) */
741
- static void redis_on_internal_cmd(fio_msg_s *msg) {
742
- // void*(void *)fio_str2u64(msg->msg.data);
743
- fio_pubsub_engine_s *engine =
744
- (fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(msg->channel.data + 0);
745
- if (engine != msg->udata1) {
746
- return;
747
- }
748
- redis_commands_s *cmd = fio_malloc(sizeof(*cmd) + msg->msg.len + 1 + 28);
749
- FIO_ASSERT_ALLOC(cmd);
750
- *cmd = (redis_commands_s){.callback = redis_forward_reply,
751
- .udata = (cmd->cmd + msg->msg.len + 1),
752
- .cmd_len = msg->msg.len};
753
- memcpy(cmd->cmd, msg->msg.data, msg->msg.len);
754
- memcpy(cmd->cmd + msg->msg.len + 1, msg->channel.data, 28);
755
- redis_attach_cmd((redis_engine_s *)engine, cmd);
756
- // fprintf(stderr, " *** Attached CMD (%d) ***\n%s\n", getpid(), cmd->cmd);
757
- }
758
-
759
- /* Listens on filter `-10 -getpid()` for incoming reply data */
760
- static void redis_on_internal_reply(fio_msg_s *msg) {
761
- fio_pubsub_engine_s *engine =
762
- (fio_pubsub_engine_s *)(uintptr_t)fio_str2u64(msg->channel.data + 0);
763
- if (engine != msg->udata1) {
764
- FIO_LOG_DEBUG("Redis reply not forwarded (engine mismatch: %p != %p)",
765
- (void *)engine, msg->udata1);
766
- return;
767
- }
768
- FIOBJ reply;
769
- fiobj_json2obj(&reply, msg->msg.data, msg->msg.len);
770
- void (*callback)(fio_pubsub_engine_s *, FIOBJ, void *) = (void (*)(
771
- fio_pubsub_engine_s *, FIOBJ, void *))(uintptr_t)fio_str2u64(msg->channel.data + 8);
772
- void *udata = (void *)(uintptr_t)fio_str2u64(msg->channel.data + 16);
773
- callback(engine, reply, udata);
774
- fiobj_free(reply);
775
- }
776
-
777
- /* publishes a Redis command to Root's filter -2 */
778
- intptr_t redis_engine_send(fio_pubsub_engine_s *engine, FIOBJ command,
779
- void (*callback)(fio_pubsub_engine_s *e, FIOBJ reply,
780
- void *udata),
781
- void *udata) {
782
- if ((uintptr_t)engine < 4) {
783
- FIO_LOG_WARNING("(redis send) trying to use one of the core engines");
784
- return -1;
785
- }
786
- // if(fio_is_master()) {
787
- // FIOBJ resp = fiobj2resp_tmp(fio_str_info_s obj1, FIOBJ obj2);
788
- // TODO...
789
- // } else {
790
- /* forward publication request to Root */
791
- fio_str_s tmp = FIO_STR_INIT;
792
- fio_str_info_s ti = fio_str_resize(&tmp, 28);
793
- /* combine metadata */
794
- fio_u2str64(ti.data + 0, (uintptr_t)engine);
795
- fio_u2str64(ti.data + 8, (uintptr_t)callback);
796
- fio_u2str64(ti.data + 16, (uintptr_t)udata);
797
- fio_u2str32(ti.data + 24, (uint32_t)getpid());
798
- FIOBJ cmd = fiobj2resp_tmp(command);
799
- fio_publish(.filter = -2, .channel = ti, .message = fiobj_obj2cstr(cmd),
800
- .engine = FIO_PUBSUB_ROOT, .is_json = 0);
801
- fio_str_free(&tmp);
802
- // }
803
- return 0;
804
- }
805
-
806
- /* *****************************************************************************
807
- Redis Engine Creation
808
- ***************************************************************************** */
809
-
810
- static void redis_on_facil_start(void *r_) {
811
- redis_engine_s *r = r_;
812
- r->flag = 1;
813
- if (!fio_is_valid(r->sub_data.uuid)) {
814
- defer_redis_connect(r, &r->sub_data);
815
- }
816
- }
817
- static void redis_on_facil_shutdown(void *r_) {
818
- redis_engine_s *r = r_;
819
- r->flag = 0;
820
- }
821
-
822
- static void redis_on_engine_fork(void *r_) {
823
- redis_engine_s *r = r_;
824
- r->flag = 0;
825
- r->lock = FIO_LOCK_INIT;
826
- fio_force_close(r->sub_data.uuid);
827
- r->sub_data.uuid = -1;
828
- fio_force_close(r->pub_data.uuid);
829
- r->pub_data.uuid = -1;
830
- while (fio_ls_embd_any(&r->queue)) {
831
- redis_commands_s *cmd =
832
- FIO_LS_EMBD_OBJ(redis_commands_s, node, fio_ls_embd_pop(&r->queue));
833
- fio_free(cmd);
834
- }
835
- r->en = (fio_pubsub_engine_s){
836
- .subscribe = redis_on_mock_subscribe_child,
837
- .unsubscribe = redis_on_mock_subscribe_child,
838
- .publish = redis_on_publish_child,
839
- };
840
- fio_unsubscribe(r->publication_forwarder);
841
- r->publication_forwarder = NULL;
842
- fio_unsubscribe(r->cmd_forwarder);
843
- r->cmd_forwarder = NULL;
844
- fio_unsubscribe(r->cmd_reply);
845
- r->cmd_reply =
846
- fio_subscribe(.filter = -10 - (int32_t)getpid(),
847
- .on_message = redis_on_internal_reply, .udata1 = r);
848
- }
849
-
850
- fio_pubsub_engine_s *redis_engine_create
851
- FIO_IGNORE_MACRO(struct redis_engine_create_args args) {
852
- if (getpid() != fio_parent_pid()) {
853
- FIO_LOG_FATAL("(redis) Redis engine initialization can only "
854
- "be performed in the Root process.");
855
- kill(0, SIGINT);
856
- fio_stop();
857
- return NULL;
858
- }
859
- if (!args.address.len && args.address.data)
860
- args.address.len = strlen(args.address.data);
861
- if (!args.port.len && args.port.data)
862
- args.port.len = strlen(args.port.data);
863
- if (!args.auth.len && args.auth.data) {
864
- args.auth.len = strlen(args.auth.data);
865
- }
866
-
867
- if (!args.address.data || !args.address.len) {
868
- args.address = (fio_str_info_s){.len = 9, .data = (char *)"localhost"};
869
- }
870
- if (!args.port.data || !args.port.len) {
871
- args.port = (fio_str_info_s){.len = 4, .data = (char *)"6379"};
872
- }
873
- redis_engine_s *r =
874
- fio_malloc(sizeof(*r) + args.port.len + 1 + args.address.len + 1 +
875
- args.auth.len + 1 + (REDIS_READ_BUFFER * 2));
876
- FIO_ASSERT_ALLOC(r);
877
- *r = (redis_engine_s){
878
- .en =
879
- {
880
- .subscribe = redis_on_subscribe_root,
881
- .unsubscribe = redis_on_unsubscribe_root,
882
- .publish = redis_on_publish_root,
883
- },
884
- .pub_data =
885
- {
886
- .protocol =
887
- {
888
- .on_data = redis_on_data,
889
- .on_close = redis_on_close,
890
- .on_shutdown = redis_on_shutdown,
891
- .ping = redis_pub_ping,
892
- },
893
- .uuid = -1,
894
- .on_message = resp_on_pub_message,
895
- },
896
- .sub_data =
897
- {
898
- .protocol =
899
- {
900
- .on_data = redis_on_data,
901
- .on_close = redis_on_close,
902
- .on_shutdown = redis_on_shutdown,
903
- .ping = redis_sub_ping,
904
- },
905
- .on_message = resp_on_sub_message,
906
- .uuid = -1,
907
- },
908
- .publication_forwarder =
909
- fio_subscribe(.filter = -1, .udata1 = r,
910
- .on_message = redis_on_internal_publish),
911
- .cmd_forwarder = fio_subscribe(.filter = -2, .udata1 = r,
912
- .on_message = redis_on_internal_cmd),
913
- .cmd_reply =
914
- fio_subscribe(.filter = -10 - (uint32_t)getpid(), .udata1 = r,
915
- .on_message = redis_on_internal_reply),
916
- .address = ((char *)(r + 1) + (REDIS_READ_BUFFER * 2)),
917
- .port =
918
- ((char *)(r + 1) + (REDIS_READ_BUFFER * 2) + args.address.len + 1),
919
- .auth = ((char *)(r + 1) + (REDIS_READ_BUFFER * 2) + args.address.len +
920
- args.port.len + 2),
921
- .auth_len = args.auth.len,
922
- .ref = 1,
923
- .queue = FIO_LS_INIT(r->queue),
924
- .lock = FIO_LOCK_INIT,
925
- .lock_connection = FIO_LOCK_INIT,
926
- .ping_int = args.ping_interval,
927
- .flag = 1,
928
- };
929
- memcpy(r->address, args.address.data, args.address.len);
930
- memcpy(r->port, args.port.data, args.port.len);
931
- if (args.auth.len)
932
- memcpy(r->auth, args.auth.data, args.auth.len);
933
- fio_pubsub_attach(&r->en);
934
- redis_on_facil_start(r);
935
- fio_state_callback_add(FIO_CALL_IN_CHILD, redis_on_engine_fork, r);
936
- fio_state_callback_add(FIO_CALL_ON_SHUTDOWN, redis_on_facil_shutdown, r);
937
- /* if restarting */
938
- fio_state_callback_add(FIO_CALL_PRE_START, redis_on_facil_start, r);
939
-
940
- FIO_LOG_DEBUG("Redis engine initialized %p", (void *)r);
941
- return &r->en;
942
- }
943
-
944
- /* *****************************************************************************
945
- Redis Engine Destruction
946
- ***************************************************************************** */
947
-
948
- void redis_engine_destroy(fio_pubsub_engine_s *engine) {
949
- redis_engine_s *r = (redis_engine_s *)engine;
950
- r->flag = 0;
951
- fio_pubsub_detach(&r->en);
952
- fio_state_callback_remove(FIO_CALL_IN_CHILD, redis_on_engine_fork, r);
953
- fio_state_callback_remove(FIO_CALL_ON_SHUTDOWN, redis_on_facil_shutdown, r);
954
- fio_state_callback_remove(FIO_CALL_PRE_START, redis_on_facil_start, r);
955
- FIO_LOG_DEBUG("Redis engine destroyed %p", (void *)r);
956
- redis_free(r);
957
- }