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.
- checksums.yaml +4 -4
- data/.clang-format +15 -0
- data/.rspec +1 -0
- data/.yardopts +1 -3
- data/CHANGELOG.md +132 -12
- data/Gemfile +5 -7
- data/LICENSE.txt +1 -1
- data/README.md +147 -671
- data/Rakefile +9 -16
- data/examples/chatroom.nru +9 -0
- data/examples/client +74 -0
- data/examples/config-hello.nru +9 -0
- data/examples/config-hello.ru +11 -0
- data/examples/config-hijack.ru +13 -0
- data/examples/config-shootout.ru +43 -0
- data/examples/config.nru +120 -0
- data/examples/config.rb +37 -0
- data/examples/config.ru +42 -53
- data/examples/fake +24 -0
- data/examples/hello_neorack +137 -0
- data/examples/routes.nru +29 -0
- data/examples/routes.ru +42 -0
- data/exe/iodine +218 -258
- data/ext/iodine/extconf.rb +27 -100
- data/ext/iodine/fio-stl.h +128336 -0
- data/ext/iodine/fio-stl.md +26396 -0
- data/ext/iodine/iodine.c +213 -1393
- data/ext/iodine/iodine.h +250 -55
- data/ext/iodine/iodine_arg_helper.h +329 -0
- data/ext/iodine/iodine_caller.h +234 -25
- data/ext/iodine/iodine_cli.h +434 -0
- data/ext/iodine/iodine_compression.h +312 -0
- data/ext/iodine/iodine_connection.h +3484 -34
- data/ext/iodine/iodine_core.h +363 -0
- data/ext/iodine/iodine_crypto.h +1441 -0
- data/ext/iodine/iodine_defer.h +225 -4
- data/ext/iodine/iodine_json.h +738 -4
- data/ext/iodine/iodine_listener.h +263 -0
- data/ext/iodine/iodine_log.h +297 -0
- data/ext/iodine/iodine_minimap.h +543 -0
- data/ext/iodine/iodine_mustache.h +461 -4
- data/ext/iodine/iodine_pubsub_eng.h +729 -0
- data/ext/iodine/iodine_pubsub_history.h +547 -0
- data/ext/iodine/iodine_pubsub_msg.h +228 -0
- data/ext/iodine/iodine_redis.h +322 -0
- data/ext/iodine/iodine_store.h +418 -16
- data/ext/iodine/iodine_threads.h +279 -0
- data/ext/iodine/iodine_tls.h +515 -6
- data/ext/iodine/iodine_utils.h +923 -0
- data/iodine.gemspec +37 -42
- data/lib/iodine/benchmark.rb +1690 -0
- data/lib/iodine/documentation.rb +3085 -0
- data/lib/iodine/version.rb +17 -1
- data/lib/iodine.rb +54 -255
- data/logo.svg +36 -0
- data/mustache.md +55 -0
- data/sig/iodine.rbs +4 -0
- metadata +58 -184
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
- data/.github/workflows/ruby.yml +0 -42
- data/.gitignore +0 -21
- data/LIMITS.md +0 -41
- data/SPEC-PubSub-Draft.md +0 -159
- data/SPEC-WebSocket-Draft.md +0 -239
- data/bin/console +0 -22
- data/bin/info.md +0 -353
- data/bin/mustache_bench.rb +0 -100
- data/bin/poc/Gemfile.lock +0 -23
- data/bin/poc/README.md +0 -37
- data/bin/poc/config.ru +0 -66
- data/bin/poc/gemfile +0 -1
- data/bin/poc/www/index.html +0 -57
- data/examples/async_task.ru +0 -92
- data/examples/bates/README.md +0 -3
- data/examples/bates/config.ru +0 -342
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +0 -600
- data/examples/echo.ru +0 -59
- data/examples/etag.ru +0 -16
- data/examples/hello.ru +0 -29
- data/examples/pubsub_engine.ru +0 -81
- data/examples/rack3.ru +0 -12
- data/examples/redis.ru +0 -70
- data/examples/shootout.ru +0 -73
- data/examples/sub-protocols.ru +0 -90
- data/examples/tcp_client.rb +0 -66
- data/examples/x-sendfile.ru +0 -14
- data/ext/iodine/fio.c +0 -11995
- data/ext/iodine/fio.h +0 -6371
- data/ext/iodine/fio_cli.c +0 -431
- data/ext/iodine/fio_cli.h +0 -189
- data/ext/iodine/fio_json_parser.h +0 -688
- data/ext/iodine/fio_siphash.c +0 -157
- data/ext/iodine/fio_siphash.h +0 -37
- data/ext/iodine/fio_tls.h +0 -129
- data/ext/iodine/fio_tls_missing.c +0 -649
- data/ext/iodine/fio_tls_openssl.c +0 -1106
- data/ext/iodine/fio_tmpfile.h +0 -50
- data/ext/iodine/fiobj.h +0 -44
- data/ext/iodine/fiobj4fio.h +0 -21
- data/ext/iodine/fiobj_ary.c +0 -333
- data/ext/iodine/fiobj_ary.h +0 -139
- data/ext/iodine/fiobj_data.c +0 -1187
- data/ext/iodine/fiobj_data.h +0 -167
- data/ext/iodine/fiobj_hash.c +0 -409
- data/ext/iodine/fiobj_hash.h +0 -176
- data/ext/iodine/fiobj_json.c +0 -622
- data/ext/iodine/fiobj_json.h +0 -68
- data/ext/iodine/fiobj_mem.h +0 -71
- data/ext/iodine/fiobj_mustache.c +0 -317
- data/ext/iodine/fiobj_mustache.h +0 -62
- data/ext/iodine/fiobj_numbers.c +0 -344
- data/ext/iodine/fiobj_numbers.h +0 -127
- data/ext/iodine/fiobj_str.c +0 -433
- data/ext/iodine/fiobj_str.h +0 -172
- data/ext/iodine/fiobject.c +0 -620
- data/ext/iodine/fiobject.h +0 -655
- data/ext/iodine/hpack.h +0 -1923
- data/ext/iodine/http.c +0 -2743
- data/ext/iodine/http.h +0 -1002
- data/ext/iodine/http1.c +0 -910
- data/ext/iodine/http1.h +0 -29
- data/ext/iodine/http1_parser.h +0 -878
- data/ext/iodine/http_internal.c +0 -1279
- data/ext/iodine/http_internal.h +0 -237
- data/ext/iodine/http_mime_parser.h +0 -350
- data/ext/iodine/iodine_caller.c +0 -230
- data/ext/iodine/iodine_connection.c +0 -941
- data/ext/iodine/iodine_defer.c +0 -420
- data/ext/iodine/iodine_fiobj2rb.h +0 -120
- data/ext/iodine/iodine_helpers.c +0 -282
- data/ext/iodine/iodine_helpers.h +0 -12
- data/ext/iodine/iodine_http.c +0 -1181
- data/ext/iodine/iodine_http.h +0 -23
- data/ext/iodine/iodine_json.c +0 -302
- data/ext/iodine/iodine_mustache.c +0 -567
- data/ext/iodine/iodine_pubsub.c +0 -580
- data/ext/iodine/iodine_pubsub.h +0 -26
- data/ext/iodine/iodine_rack_io.c +0 -273
- data/ext/iodine/iodine_rack_io.h +0 -20
- data/ext/iodine/iodine_store.c +0 -148
- data/ext/iodine/iodine_tcp.c +0 -346
- data/ext/iodine/iodine_tcp.h +0 -13
- data/ext/iodine/iodine_tls.c +0 -261
- data/ext/iodine/mustache_parser.h +0 -1546
- data/ext/iodine/redis_engine.c +0 -957
- data/ext/iodine/redis_engine.h +0 -79
- data/ext/iodine/resp_parser.h +0 -317
- data/ext/iodine/websocket_parser.h +0 -506
- data/ext/iodine/websockets.c +0 -743
- data/ext/iodine/websockets.h +0 -185
- data/lib/iodine/connection.rb +0 -61
- data/lib/iodine/json.rb +0 -42
- data/lib/iodine/mustache.rb +0 -113
- data/lib/iodine/pubsub.rb +0 -55
- data/lib/iodine/rack_utils.rb +0 -43
- data/lib/iodine/tls.rb +0 -16
- data/lib/rack/handler/iodine.rb +0 -33
- data/logo.png +0 -0
data/ext/iodine/iodine_store.h
CHANGED
|
@@ -1,20 +1,422 @@
|
|
|
1
|
-
#
|
|
2
|
-
#define
|
|
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
|
-
|
|
9
|
+
Use:
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
18
|
-
|
|
14
|
+
// Removed a Ruby Object from the store, releasing it's GC hold
|
|
15
|
+
STORE.release(VALUE o);
|
|
19
16
|
|
|
20
|
-
|
|
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 */
|