iodine 0.7.59 → 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 -20
  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 -146
  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,20 +1,422 @@
1
- #ifndef H_IODINE_STORAGE_H
2
- #define H_IODINE_STORAGE_H
1
+ #if !defined(H___IODINE_STORE___H)
2
+ #define H___IODINE_STORE___H
3
+ #if !defined(IODINE_STORE_SKIP_PRINT)
4
+ #include "iodine.h"
5
+ #endif
6
+ /* *****************************************************************************
7
+ Ruby Object Storage (GC management)
3
8
 
4
- #include "ruby.h"
9
+ Use:
5
10
 
6
- extern struct IodineStorage_s {
7
- /** Adds an object to the storage (or increases it's reference count). */
8
- VALUE (*add)(VALUE);
9
- /** Removes an object from the storage (or decreases it's reference count). */
10
- VALUE (*remove)(VALUE);
11
- /** Should be called after forking to reset locks */
12
- void (*after_fork)(void);
13
- /** Prints debugging information to the console. */
14
- void (*print)(void);
15
- } IodineStore;
11
+ // Adds a Ruby Object from the store, holding it against GC cleanup
12
+ STORE.hold(VALUE o);
16
13
 
17
- /** Initializes the storage unit for first use. */
18
- void iodine_storage_init(void);
14
+ // Removed a Ruby Object from the store, releasing it's GC hold
15
+ STORE.release(VALUE o);
19
16
 
20
- #endif
17
+ // Performs callback during every GC cycle
18
+ STORE.on_gc(void (*fn)(void *), void *arg);
19
+
20
+ // Returns a frozen String object (from cache, if exists)
21
+ VALUE str = STORE.frozen_str(fio_buf_info_s cstr);
22
+
23
+ // Returns a frozen Header String object (from cache, if exists)
24
+ VALUE str = STORE.header_name(fio_buf_info_s header_name);
25
+
26
+
27
+ ***************************************************************************** */
28
+
29
+ /* *****************************************************************************
30
+ Ruby Garbage Collection Protection Object
31
+ ***************************************************************************** */
32
+
33
+ typedef struct {
34
+ void (*fn)(void *);
35
+ void *arg;
36
+ } store___task_s;
37
+
38
+ #define FIO_ARRAY_NAME store___todo
39
+ #define FIO_ARRAY_TYPE store___task_s
40
+ #define FIO_ARRAY_TYPE_CMP(a, b) ((a).fn == (b).fn && (a).arg == (b).arg)
41
+ #define FIO_ARRAY_EXPONENTIAL 1
42
+ #define FIO_MAP_NAME iodine_reference_store_map
43
+ #define FIO_MAP_KEY VALUE
44
+ #define FIO_MAP_VALUE size_t
45
+ #define FIO_MAP_HASH_FN(o) fio_risky_ptr((void *)(o))
46
+ #define FIO_THREADS
47
+ #include FIO_INCLUDE_FILE
48
+
49
+ #define FIO_MAP_KEY_KSTR
50
+ #define FIO_MAP_HASH_FN(o) \
51
+ fio_risky_hash((o).buf, (o).len, (uint64_t)&iodine_rb_IODINE);
52
+ #define FIO_MAP_NAME iodine_reference_store_frzn
53
+ #define FIO_MAP_VALUE VALUE
54
+ #include FIO_INCLUDE_FILE
55
+
56
+ /* MUST be a log 2 */
57
+ #define IODINE___SINGLE_USE_COUNT 16
58
+
59
+ FIO_SFUNC void iodine_store___gc_stop(void);
60
+ FIO_SFUNC void iodine_store___gc_start(void);
61
+ FIO_SFUNC void iodine_store___cache(VALUE o);
62
+ FIO_SFUNC void iodine_store___hold(VALUE o);
63
+ FIO_SFUNC void iodine_store___release(VALUE o);
64
+ FIO_SFUNC VALUE iodine_store___held_count(VALUE self);
65
+ FIO_SFUNC void iodine_store___on_gc(void (*fn)(void *), void *arg);
66
+ FIO_SFUNC VALUE iodine_store___frozen_str(fio_str_info_s n);
67
+ FIO_SFUNC VALUE iodine_store___header_name(fio_str_info_s n);
68
+ FIO_SFUNC void iodine_store___destroy(void);
69
+
70
+ static struct value_reference_counter_store_s {
71
+ iodine_reference_store_map_s map;
72
+ iodine_reference_store_frzn_s frozen;
73
+ iodine_reference_store_frzn_s headers;
74
+ store___todo_s todo;
75
+ size_t limit;
76
+ size_t gc_stop_counter;
77
+ fio_thread_mutex_t lock;
78
+ /** Adds a VALUE to the store, protecting it from the GC. */
79
+ void (*const hold)(VALUE);
80
+ /** Removed a VALUE to the store, if it's `hold` count drops to zero. */
81
+ void (*const release)(VALUE);
82
+ /** Stops the Garbage Collector, or increases the stop count. */
83
+ void (*const gc_stop)(void);
84
+ /** Decreases the `gc_stop` count and re-starts Garbage Collector. */
85
+ void (*const gc_start)(void);
86
+ /** Adds a task to be performed during the next GC cycle. */
87
+ void (*const on_gc)(void (*fn)(void *), void *arg);
88
+ /** Returns a frozen String, possibly cached. */
89
+ VALUE (*const frozen_str)(fio_str_info_s);
90
+ /** Returns a frozen String header name (`HTTP_` + uppercase). */
91
+ VALUE (*const header_name)(fio_str_info_s);
92
+ /* releases all objects */
93
+ void (*const destroy)(void);
94
+ /** Stores a value in a ring cache, never lets go until overwritten. */
95
+ void (*const cache)(VALUE);
96
+ VALUE single_use[IODINE___SINGLE_USE_COUNT];
97
+ } STORE = {
98
+ FIO_MAP_INIT,
99
+ FIO_MAP_INIT,
100
+ FIO_MAP_INIT,
101
+ FIO_ARRAY_INIT,
102
+ 228,
103
+ 0,
104
+ FIO_THREAD_MUTEX_INIT,
105
+ iodine_store___hold,
106
+ iodine_store___release,
107
+ iodine_store___gc_stop,
108
+ iodine_store___gc_start,
109
+ iodine_store___on_gc,
110
+ iodine_store___frozen_str,
111
+ iodine_store___header_name,
112
+ iodine_store___destroy,
113
+ iodine_store___cache,
114
+ };
115
+
116
+ FIO_SFUNC void iodine_store___gc_stop(void) {
117
+ size_t state = fio_atomic_add(&STORE.gc_stop_counter, 1);
118
+ if (state)
119
+ return;
120
+ FIO_LOG_DEBUG("GC Paused.");
121
+ rb_gc_disable();
122
+ }
123
+ FIO_SFUNC void iodine_store___gc_start(void) {
124
+ size_t state = fio_atomic_sub(&STORE.gc_stop_counter, 1);
125
+ if (state + 256 > 256)
126
+ return;
127
+ if (state + 256 < 256) {
128
+ fio_atomic_add(&STORE.gc_stop_counter, 1);
129
+ return;
130
+ }
131
+ FIO_LOG_DEBUG("GC Resumed.");
132
+ rb_gc_enable();
133
+ }
134
+
135
+ /**
136
+ * Prints the number of object withheld from the GC (for debugging).
137
+ *
138
+ * Iodine::Base.print_debug
139
+ */
140
+ FIO_SFUNC VALUE iodine_store___print_debug(VALUE self) {
141
+ #ifndef IODINE_STORE_SKIP_PRINT
142
+ fprintf(
143
+ stderr,
144
+ "DEBUG: (%d) Iodine-Ruby memory store info:\n"
145
+ " \tRuby Objects Held: %-4zu (%-4zu current capacity)\n"
146
+ " \tCached Frozen Strings: %-4zu/%-4zu (%-4zu capacity)\n"
147
+ " \tCached Rack Headers: %-4zu/%-4zu (%-4zu capacity)\n"
148
+ " \tTasks to do: %-4zu\n"
149
+ #if FIO_LEAK_COUNTER
150
+ " \tIodine Objects Allocated:\n"
151
+ " \tConnections: %-4zu\tMiniMaps: %-4zu\n"
152
+ " \tMustache: %-4zu\tPubSubMessages: %-4zu\n"
153
+ " \tfacil.io Objects Allocated:\n"
154
+ " \tHTTP Handles: %-4zu\tfio_bstr_s: %-4zu\n"
155
+ " \tIO Objects: %-4zu\n"
156
+ #endif /* FIO_LEAK_COUNTER */
157
+ ,
158
+ (int)fio_getpid(),
159
+ (size_t)iodine_reference_store_map_count(&STORE.map),
160
+ (size_t)iodine_reference_store_map_capa(&STORE.map),
161
+ (size_t)iodine_reference_store_frzn_count(&STORE.frozen),
162
+ STORE.limit,
163
+ (size_t)iodine_reference_store_frzn_capa(&STORE.frozen),
164
+ (size_t)iodine_reference_store_frzn_count(&STORE.headers),
165
+ STORE.limit,
166
+ (size_t)iodine_reference_store_frzn_capa(&STORE.headers),
167
+ (size_t)store___todo_count(&STORE.todo)
168
+ #if FIO_LEAK_COUNTER
169
+ ,
170
+ FIO_LEAK_COUNTER_COUNT(iodine_connection),
171
+ FIO_LEAK_COUNTER_COUNT(iodine_minimap),
172
+ FIO_LEAK_COUNTER_COUNT(iodine_mustache),
173
+ FIO_LEAK_COUNTER_COUNT(iodine_pubsub_msg),
174
+ FIO_LEAK_COUNTER_COUNT(fio_http),
175
+ FIO_LEAK_COUNTER_COUNT(fio_bstr_s),
176
+ FIO_LEAK_COUNTER_COUNT(fio___io)
177
+ #endif /* FIO_LEAK_COUNTER */
178
+ );
179
+ // fio_state_callback_print_state();
180
+ #endif /* IODINE_STORE_SKIP_PRINT */
181
+ return self;
182
+ }
183
+
184
+ /** Sets Iodine's cache limit for frozen strings, limited to 65,535 items. */
185
+ FIO_SFUNC VALUE iodine_store___cache_limit_set(VALUE self, VALUE nlim) {
186
+ Check_Type(nlim, T_FIXNUM);
187
+ unsigned long long l = NUM2ULL(nlim);
188
+ if (l > 65536)
189
+ l = 65536;
190
+ STORE.limit = l;
191
+ return ULL2NUM(l);
192
+ }
193
+ /** Gets Iodine's cache limit for frozen strings. */
194
+ FIO_SFUNC VALUE iodine_store___cache_limit_get(VALUE self) {
195
+ return ULL2NUM((unsigned long long)STORE.limit);
196
+ }
197
+
198
+ FIO_IFUNC void store___todo_perform_tasks_unsafe(
199
+ struct value_reference_counter_store_s *s) {
200
+ store___task_s tsk = {NULL};
201
+ while (!store___todo_pop(&s->todo, &tsk))
202
+ tsk.fn(tsk.arg);
203
+ }
204
+
205
+ FIO_IFUNC void iodine_store___hold_unsafe(VALUE o) {
206
+ iodine_reference_store_map_node_s *n =
207
+ iodine_reference_store_map_get_ptr(&STORE.map, o);
208
+ if (!n) {
209
+ iodine_reference_store_map_set(&STORE.map, o, 1, NULL);
210
+ } else {
211
+ fio_atomic_add(&n->value, 1);
212
+ }
213
+ }
214
+
215
+ FIO_SFUNC void iodine_store___cache(VALUE o) {
216
+ static volatile size_t i;
217
+ if (IODINE_STORE_IS_SKIP(o))
218
+ return;
219
+ STORE.single_use[fio_atomic_add(&i, 1) & ((IODINE___SINGLE_USE_COUNT)-1)] = o;
220
+ }
221
+
222
+ FIO_SFUNC void iodine_store___hold(VALUE o) {
223
+ if (IODINE_STORE_IS_SKIP(o))
224
+ return;
225
+ fio_thread_mutex_lock(&STORE.lock);
226
+ iodine_store___hold_unsafe(o);
227
+ fio_thread_mutex_unlock(&STORE.lock);
228
+ }
229
+ FIO_SFUNC void iodine_store___release(VALUE o) {
230
+ if (IODINE_STORE_IS_SKIP(o) || !iodine_reference_store_map_count(&STORE.map))
231
+ return;
232
+ fio_thread_mutex_lock(&STORE.lock);
233
+ iodine_reference_store_map_node_s *n =
234
+ iodine_reference_store_map_get_ptr(&STORE.map, o);
235
+ if (n && !fio_atomic_sub_fetch(&n->value, 1)) {
236
+ iodine_reference_store_map_remove(&STORE.map, o, NULL);
237
+ }
238
+ fio_thread_mutex_unlock(&STORE.lock);
239
+ }
240
+
241
+ /** Returns the number of Ruby objects currently protected from the GC.
242
+ *
243
+ * Iodine::Base.store_size
244
+ *
245
+ * Unlike GC-dependent probes (WeakRef + GC.start), this count is
246
+ * deterministic: it reflects actual `STORE.hold` / `STORE.release` balance,
247
+ * unaffected by conservative stack scanning. */
248
+ FIO_SFUNC VALUE iodine_store___held_count(VALUE self) {
249
+ (void)self;
250
+ return RB_SIZE2NUM((size_t)iodine_reference_store_map_count(&STORE.map));
251
+ }
252
+
253
+ FIO_SFUNC VALUE iodine_store___frozen_str(fio_str_info_s n) {
254
+ VALUE r;
255
+ fio_thread_mutex_lock(&STORE.lock);
256
+ r = iodine_reference_store_frzn_get(&STORE.frozen, n);
257
+ fio_thread_mutex_unlock(&STORE.lock);
258
+ if (r)
259
+ return r;
260
+
261
+ r = rb_str_new(n.buf, n.len); /* might invoke GC, can't be in a lock */
262
+ rb_str_freeze(r);
263
+ if (iodine_reference_store_frzn_count(&STORE.frozen) < STORE.limit) {
264
+ /* May cause STORE.frozen to grow slightly more than limit, acceptable */
265
+ fio_thread_mutex_lock(&STORE.lock);
266
+ iodine_reference_store_frzn_set(&STORE.frozen, n, r, NULL);
267
+ fio_thread_mutex_unlock(&STORE.lock);
268
+ }
269
+ return r;
270
+ }
271
+
272
+ FIO_SFUNC VALUE iodine_store___header_name(fio_str_info_s n) {
273
+ VALUE r;
274
+ size_t offset;
275
+ if (!n.len || n.len > 1023)
276
+ return Qnil;
277
+ FIO_STR_INFO_TMP_VAR(buffer, 1152);
278
+ /* CONTENT_LENGTH and CONTENT_TYPE should be copied without HTTP_ */
279
+ const uint64_t content_length1 = fio_buf2u64u("content-");
280
+ const uint64_t content_length2 = fio_buf2u64u("t-length");
281
+ const uint64_t content_type1 = fio_buf2u64u("content-");
282
+ const uint32_t content_type2 = fio_buf2u32u("type");
283
+
284
+ fio_thread_mutex_lock(&STORE.lock);
285
+ r = iodine_reference_store_frzn_get(&STORE.headers, n);
286
+ fio_thread_mutex_unlock(&STORE.lock);
287
+ if (r)
288
+ return r;
289
+
290
+ offset = 5 * !((n.len == 14 && fio_buf2u64u(n.buf) == content_length1 &&
291
+ fio_buf2u64u(n.buf + 6) == content_length2) ||
292
+ (n.len == 12 && fio_buf2u64u(n.buf) == content_type1 &&
293
+ fio_buf2u32u(n.buf + 8) == content_type2));
294
+ fio_string_write2(&buffer,
295
+ NULL,
296
+ FIO_STRING_WRITE_STR2("HTTP_", offset),
297
+ FIO_STRING_WRITE_STR_INFO(n));
298
+ for (size_t i = offset; i < buffer.len; ++i) {
299
+ if (buffer.buf[i] >= 'a' && buffer.buf[i] <= 'z')
300
+ buffer.buf[i] = buffer.buf[i] ^ 32;
301
+ else if (buffer.buf[i] == '-')
302
+ buffer.buf[i] = '_';
303
+ }
304
+ r = rb_str_new(buffer.buf, buffer.len);
305
+ rb_str_freeze(r);
306
+ if (iodine_reference_store_frzn_count(&STORE.headers) < STORE.limit) {
307
+ fio_thread_mutex_lock(&STORE.lock);
308
+ iodine_reference_store_frzn_set(&STORE.headers, n, r, NULL);
309
+ fio_thread_mutex_unlock(&STORE.lock);
310
+ }
311
+ return r;
312
+ }
313
+
314
+ FIO_SFUNC void iodine_store___destroy(void) {
315
+ fio_thread_mutex_destroy(&STORE.lock);
316
+ store___todo_perform_tasks_unsafe(&STORE);
317
+ iodine_reference_store_map_destroy(&STORE.map);
318
+ iodine_reference_store_frzn_destroy(&STORE.frozen);
319
+ iodine_reference_store_frzn_destroy(&STORE.headers);
320
+ store___todo_destroy(&STORE.todo);
321
+ STORE.map = (iodine_reference_store_map_s){0};
322
+ STORE.frozen = (iodine_reference_store_frzn_s){0};
323
+ STORE.headers = (iodine_reference_store_frzn_s){0};
324
+ STORE.todo = (store___todo_s){0};
325
+ STORE.lock = (fio_thread_mutex_t)FIO_THREAD_MUTEX_INIT;
326
+ }
327
+
328
+ FIO_SFUNC void iodine_store___on_gc(void (*fn)(void *), void *arg) {
329
+ if (!fn && !arg)
330
+ return;
331
+ fio_thread_mutex_lock(&STORE.lock);
332
+ store___todo_push(&STORE.todo, (store___task_s){.fn = fn, .arg = arg});
333
+ fio_thread_mutex_unlock(&STORE.lock);
334
+ }
335
+
336
+ FIO_SFUNC int iodine_store___gc_mark__key(
337
+ iodine_reference_store_map_each_s *e) {
338
+ rb_gc_mark(e->key);
339
+ return 0;
340
+ }
341
+ FIO_SFUNC int iodine_store___gc_mark__val(
342
+ iodine_reference_store_frzn_each_s *e) {
343
+ rb_gc_mark(e->value);
344
+ return 0;
345
+ }
346
+
347
+ FIO_SFUNC void iodine_store___gc_mark(
348
+ struct value_reference_counter_store_s *s) {
349
+ if (!s)
350
+ return;
351
+ if (!iodine_reference_store_map_count(&s->map) &&
352
+ !store___todo_count(&s->todo))
353
+ return;
354
+ // can we skip the lock?
355
+ fio_thread_mutex_lock(&s->lock);
356
+ store___todo_perform_tasks_unsafe(s);
357
+ iodine_reference_store_map_each(&s->map,
358
+ iodine_store___gc_mark__key,
359
+ NULL,
360
+ 0);
361
+ iodine_reference_store_frzn_each(&s->frozen,
362
+ iodine_store___gc_mark__val,
363
+ NULL,
364
+ 0);
365
+ iodine_reference_store_frzn_each(&s->headers,
366
+ iodine_store___gc_mark__val,
367
+ NULL,
368
+ 0);
369
+ for (size_t i = 0; i < IODINE___SINGLE_USE_COUNT; ++i) {
370
+ VALUE tmp = STORE.single_use[i];
371
+ STORE.single_use[i] = Qnil;
372
+ if (IODINE_STORE_IS_SKIP(tmp))
373
+ continue;
374
+ rb_gc_mark(tmp);
375
+ }
376
+ // can we skip the lock?
377
+ fio_thread_mutex_unlock(&s->lock);
378
+ if (FIO_LOG_LEVEL >= FIO_LOG_LEVEL_DEBUG)
379
+ iodine_store___print_debug(Qnil);
380
+ }
381
+
382
+ FIO_SFUNC void value_reference_counter_store_destroy(VALUE i_) {
383
+ (void)i_;
384
+ iodine_store___destroy();
385
+ for (size_t i = 0;
386
+ i < (sizeof(STORE.single_use) / sizeof(STORE.single_use[0]));
387
+ ++i)
388
+ STORE.single_use[i] = Qnil;
389
+ }
390
+
391
+ static void iodine_setup_value_reference_counter(VALUE klass) {
392
+ static const struct rb_data_type_struct storage_type_struct = {
393
+ .wrap_struct_name = "CRubyReferenceStore",
394
+ .function.dfree = (void (*)(void *))value_reference_counter_store_destroy,
395
+ .function.dmark = (void (*)(void *))iodine_store___gc_mark,
396
+ };
397
+ static VALUE keep_alive = 0;
398
+ if (keep_alive)
399
+ return;
400
+ /** Container Class for Ruby-C bridge (GC protected objects). */
401
+ rb_define_singleton_method(klass,
402
+ "print_debug",
403
+ iodine_store___print_debug,
404
+ 0);
405
+ rb_define_singleton_method(klass, "store_size", iodine_store___held_count, 0);
406
+ rb_define_singleton_method(klass,
407
+ "cache_limit=",
408
+ iodine_store___cache_limit_set,
409
+ 1);
410
+ rb_define_singleton_method(klass,
411
+ "cache_limit",
412
+ iodine_store___cache_limit_get,
413
+ 0);
414
+ keep_alive = TypedData_Wrap_Struct(klass, &storage_type_struct, &STORE);
415
+ rb_global_variable(&keep_alive);
416
+ fio_state_callback_add(
417
+ FIO_CALL_AT_EXIT,
418
+ (void (*)(void *))value_reference_counter_store_destroy,
419
+ (void *)&STORE);
420
+ }
421
+
422
+ #endif /* H___IODINE_STORE___H */