prometheus-client-mmap 0.16.2 → 0.18.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/README.md +22 -10
- data/ext/fast_mmaped_file/hashmap.c +467 -410
- data/ext/fast_mmaped_file/jsmn.c +244 -259
- data/ext/fast_mmaped_file/mmap.c +58 -0
- data/ext/fast_mmaped_file/mmap.h +6 -0
- data/ext/fast_mmaped_file/value_access.c +9 -6
- data/lib/fast_mmaped_file.bundle +0 -0
- data/lib/mmap.rb +7 -0
- data/lib/prometheus/#client.rb# +58 -0
- data/lib/prometheus/client/push.rb +120 -12
- data/lib/prometheus/client/version.rb +1 -1
- metadata +6 -4
data/ext/fast_mmaped_file/jsmn.c
CHANGED
@@ -3,319 +3,303 @@
|
|
3
3
|
/**
|
4
4
|
* Allocates a fresh unused token from the token pull.
|
5
5
|
*/
|
6
|
-
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
7
|
+
jsmntok_t *tokens, size_t num_tokens) {
|
8
|
+
jsmntok_t *tok;
|
9
|
+
if (parser->toknext >= num_tokens) {
|
10
|
+
return NULL;
|
11
|
+
}
|
12
|
+
tok = &tokens[parser->toknext++];
|
13
|
+
tok->start = tok->end = -1;
|
14
|
+
tok->size = 0;
|
14
15
|
#ifdef JSMN_PARENT_LINKS
|
15
|
-
|
16
|
+
tok->parent = -1;
|
16
17
|
#endif
|
17
|
-
|
18
|
+
return tok;
|
18
19
|
}
|
19
20
|
|
20
21
|
/**
|
21
22
|
* Fills token type and boundaries.
|
22
23
|
*/
|
23
|
-
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
25
|
+
int start, int end) {
|
26
|
+
token->type = type;
|
27
|
+
token->start = start;
|
28
|
+
token->end = end;
|
29
|
+
token->size = 0;
|
28
30
|
}
|
29
31
|
|
30
32
|
/**
|
31
33
|
* Fills next available token with JSON primitive.
|
32
34
|
*/
|
33
|
-
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
34
|
-
|
35
|
-
|
35
|
+
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
36
|
+
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
37
|
+
jsmntok_t *token;
|
38
|
+
int start;
|
36
39
|
|
37
|
-
|
40
|
+
start = parser->pos;
|
38
41
|
|
39
|
-
|
40
|
-
|
42
|
+
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
43
|
+
switch (js[parser->pos]) {
|
41
44
|
#ifndef JSMN_STRICT
|
42
|
-
|
43
|
-
|
45
|
+
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
46
|
+
case ':':
|
44
47
|
#endif
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
55
|
-
parser->pos = start;
|
56
|
-
return JSMN_ERROR_INVAL;
|
57
|
-
}
|
58
|
-
}
|
48
|
+
case '\t' : case '\r' : case '\n' : case ' ' :
|
49
|
+
case ',' : case ']' : case '}' :
|
50
|
+
goto found;
|
51
|
+
}
|
52
|
+
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
53
|
+
parser->pos = start;
|
54
|
+
return JSMN_ERROR_INVAL;
|
55
|
+
}
|
56
|
+
}
|
59
57
|
#ifdef JSMN_STRICT
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
/* In strict mode primitive must be followed by a comma/object/array */
|
59
|
+
parser->pos = start;
|
60
|
+
return JSMN_ERROR_PART;
|
63
61
|
#endif
|
64
62
|
|
65
63
|
found:
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
if (tokens == NULL) {
|
65
|
+
parser->pos--;
|
66
|
+
return 0;
|
67
|
+
}
|
68
|
+
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
69
|
+
if (token == NULL) {
|
70
|
+
parser->pos = start;
|
71
|
+
return JSMN_ERROR_NOMEM;
|
72
|
+
}
|
73
|
+
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
76
74
|
#ifdef JSMN_PARENT_LINKS
|
77
|
-
|
75
|
+
token->parent = parser->toksuper;
|
78
76
|
#endif
|
79
|
-
|
80
|
-
|
77
|
+
parser->pos--;
|
78
|
+
return 0;
|
81
79
|
}
|
82
80
|
|
83
81
|
/**
|
84
82
|
* Fills next token with JSON string.
|
85
83
|
*/
|
86
|
-
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
87
|
-
|
84
|
+
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
85
|
+
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
86
|
+
jsmntok_t *token;
|
88
87
|
|
89
|
-
|
88
|
+
int start = parser->pos;
|
90
89
|
|
91
|
-
|
90
|
+
parser->pos++;
|
92
91
|
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
/* Skip starting quote */
|
93
|
+
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
94
|
+
char c = js[parser->pos];
|
96
95
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
96
|
+
/* Quote: end of string */
|
97
|
+
if (c == '\"') {
|
98
|
+
if (tokens == NULL) {
|
99
|
+
return 0;
|
100
|
+
}
|
101
|
+
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
102
|
+
if (token == NULL) {
|
103
|
+
parser->pos = start;
|
104
|
+
return JSMN_ERROR_NOMEM;
|
105
|
+
}
|
106
|
+
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
108
107
|
#ifdef JSMN_PARENT_LINKS
|
109
|
-
|
108
|
+
token->parent = parser->toksuper;
|
110
109
|
#endif
|
111
|
-
|
112
|
-
|
110
|
+
return 0;
|
111
|
+
}
|
113
112
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
return JSMN_ERROR_INVAL;
|
148
|
-
}
|
149
|
-
}
|
150
|
-
}
|
151
|
-
parser->pos = start;
|
152
|
-
return JSMN_ERROR_PART;
|
113
|
+
/* Backslash: Quoted symbol expected */
|
114
|
+
if (c == '\\' && parser->pos + 1 < len) {
|
115
|
+
int i;
|
116
|
+
parser->pos++;
|
117
|
+
switch (js[parser->pos]) {
|
118
|
+
/* Allowed escaped symbols */
|
119
|
+
case '\"': case '/' : case '\\' : case 'b' :
|
120
|
+
case 'f' : case 'r' : case 'n' : case 't' :
|
121
|
+
break;
|
122
|
+
/* Allows escaped symbol \uXXXX */
|
123
|
+
case 'u':
|
124
|
+
parser->pos++;
|
125
|
+
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
|
126
|
+
/* If it isn't a hex character we have an error */
|
127
|
+
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
128
|
+
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
129
|
+
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
130
|
+
parser->pos = start;
|
131
|
+
return JSMN_ERROR_INVAL;
|
132
|
+
}
|
133
|
+
parser->pos++;
|
134
|
+
}
|
135
|
+
parser->pos--;
|
136
|
+
break;
|
137
|
+
/* Unexpected symbol */
|
138
|
+
default:
|
139
|
+
parser->pos = start;
|
140
|
+
return JSMN_ERROR_INVAL;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
parser->pos = start;
|
145
|
+
return JSMN_ERROR_PART;
|
153
146
|
}
|
154
147
|
|
155
148
|
/**
|
156
149
|
* Parse JSON string and fill tokens.
|
157
150
|
*/
|
158
|
-
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
151
|
+
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
152
|
+
jsmntok_t *tokens, unsigned int num_tokens) {
|
153
|
+
int r;
|
154
|
+
int i;
|
155
|
+
jsmntok_t *token;
|
156
|
+
int count = parser->toknext;
|
163
157
|
|
164
|
-
|
165
|
-
|
166
|
-
|
158
|
+
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
159
|
+
char c;
|
160
|
+
jsmntype_t type;
|
167
161
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
162
|
+
c = js[parser->pos];
|
163
|
+
switch (c) {
|
164
|
+
case '{': case '[':
|
165
|
+
count++;
|
166
|
+
if (tokens == NULL) {
|
167
|
+
break;
|
168
|
+
}
|
169
|
+
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
170
|
+
if (token == NULL)
|
171
|
+
return JSMN_ERROR_NOMEM;
|
172
|
+
if (parser->toksuper != -1) {
|
173
|
+
tokens[parser->toksuper].size++;
|
180
174
|
#ifdef JSMN_PARENT_LINKS
|
181
|
-
|
175
|
+
token->parent = parser->toksuper;
|
182
176
|
#endif
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
177
|
+
}
|
178
|
+
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
179
|
+
token->start = parser->pos;
|
180
|
+
parser->toksuper = parser->toknext - 1;
|
181
|
+
break;
|
182
|
+
case '}': case ']':
|
183
|
+
if (tokens == NULL)
|
184
|
+
break;
|
185
|
+
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
192
186
|
#ifdef JSMN_PARENT_LINKS
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
187
|
+
if (parser->toknext < 1) {
|
188
|
+
return JSMN_ERROR_INVAL;
|
189
|
+
}
|
190
|
+
token = &tokens[parser->toknext - 1];
|
191
|
+
for (;;) {
|
192
|
+
if (token->start != -1 && token->end == -1) {
|
193
|
+
if (token->type != type) {
|
194
|
+
return JSMN_ERROR_INVAL;
|
195
|
+
}
|
196
|
+
token->end = parser->pos + 1;
|
197
|
+
parser->toksuper = token->parent;
|
198
|
+
break;
|
199
|
+
}
|
200
|
+
if (token->parent == -1) {
|
201
|
+
if(token->type != type || parser->toksuper == -1) {
|
202
|
+
return JSMN_ERROR_INVAL;
|
203
|
+
}
|
204
|
+
break;
|
205
|
+
}
|
206
|
+
token = &tokens[token->parent];
|
207
|
+
}
|
214
208
|
#else
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
209
|
+
for (i = parser->toknext - 1; i >= 0; i--) {
|
210
|
+
token = &tokens[i];
|
211
|
+
if (token->start != -1 && token->end == -1) {
|
212
|
+
if (token->type != type) {
|
213
|
+
return JSMN_ERROR_INVAL;
|
214
|
+
}
|
215
|
+
parser->toksuper = -1;
|
216
|
+
token->end = parser->pos + 1;
|
217
|
+
break;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
/* Error if unmatched closing bracket */
|
221
|
+
if (i == -1) return JSMN_ERROR_INVAL;
|
222
|
+
for (; i >= 0; i--) {
|
223
|
+
token = &tokens[i];
|
224
|
+
if (token->start != -1 && token->end == -1) {
|
225
|
+
parser->toksuper = i;
|
226
|
+
break;
|
227
|
+
}
|
228
|
+
}
|
235
229
|
#endif
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
230
|
+
break;
|
231
|
+
case '\"':
|
232
|
+
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
233
|
+
if (r < 0) return r;
|
234
|
+
count++;
|
235
|
+
if (parser->toksuper != -1 && tokens != NULL)
|
236
|
+
tokens[parser->toksuper].size++;
|
237
|
+
break;
|
238
|
+
case '\t' : case '\r' : case '\n' : case ' ':
|
239
|
+
break;
|
240
|
+
case ':':
|
241
|
+
parser->toksuper = parser->toknext - 1;
|
242
|
+
break;
|
243
|
+
case ',':
|
244
|
+
if (tokens != NULL && parser->toksuper != -1 &&
|
245
|
+
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
246
|
+
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
254
247
|
#ifdef JSMN_PARENT_LINKS
|
255
|
-
|
248
|
+
parser->toksuper = tokens[parser->toksuper].parent;
|
256
249
|
#else
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
250
|
+
for (i = parser->toknext - 1; i >= 0; i--) {
|
251
|
+
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
252
|
+
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
253
|
+
parser->toksuper = i;
|
254
|
+
break;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
}
|
265
258
|
#endif
|
266
|
-
|
267
|
-
|
259
|
+
}
|
260
|
+
break;
|
268
261
|
#ifdef JSMN_STRICT
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
case 't':
|
282
|
-
case 'f':
|
283
|
-
case 'n':
|
284
|
-
/* And they must not be keys of the object */
|
285
|
-
if (tokens != NULL && parser->toksuper != -1) {
|
286
|
-
jsmntok_t *t = &tokens[parser->toksuper];
|
287
|
-
if (t->type == JSMN_OBJECT || (t->type == JSMN_STRING && t->size != 0)) {
|
288
|
-
return JSMN_ERROR_INVAL;
|
289
|
-
}
|
290
|
-
}
|
262
|
+
/* In strict mode primitives are: numbers and booleans */
|
263
|
+
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
264
|
+
case '5': case '6': case '7' : case '8': case '9':
|
265
|
+
case 't': case 'f': case 'n' :
|
266
|
+
/* And they must not be keys of the object */
|
267
|
+
if (tokens != NULL && parser->toksuper != -1) {
|
268
|
+
jsmntok_t *t = &tokens[parser->toksuper];
|
269
|
+
if (t->type == JSMN_OBJECT ||
|
270
|
+
(t->type == JSMN_STRING && t->size != 0)) {
|
271
|
+
return JSMN_ERROR_INVAL;
|
272
|
+
}
|
273
|
+
}
|
291
274
|
#else
|
292
|
-
|
293
|
-
|
275
|
+
/* In non-strict mode every unquoted value is a primitive */
|
276
|
+
default:
|
294
277
|
#endif
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
278
|
+
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
279
|
+
if (r < 0) return r;
|
280
|
+
count++;
|
281
|
+
if (parser->toksuper != -1 && tokens != NULL)
|
282
|
+
tokens[parser->toksuper].size++;
|
283
|
+
break;
|
300
284
|
|
301
285
|
#ifdef JSMN_STRICT
|
302
|
-
|
303
|
-
|
304
|
-
|
286
|
+
/* Unexpected char in strict mode */
|
287
|
+
default:
|
288
|
+
return JSMN_ERROR_INVAL;
|
305
289
|
#endif
|
306
|
-
|
307
|
-
|
290
|
+
}
|
291
|
+
}
|
308
292
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
293
|
+
if (tokens != NULL) {
|
294
|
+
for (i = parser->toknext - 1; i >= 0; i--) {
|
295
|
+
/* Unmatched opened object or array */
|
296
|
+
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
297
|
+
return JSMN_ERROR_PART;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
}
|
317
301
|
|
318
|
-
|
302
|
+
return count;
|
319
303
|
}
|
320
304
|
|
321
305
|
/**
|
@@ -323,7 +307,8 @@ int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *token
|
|
323
307
|
* available.
|
324
308
|
*/
|
325
309
|
void jsmn_init(jsmn_parser *parser) {
|
326
|
-
|
327
|
-
|
328
|
-
|
310
|
+
parser->pos = 0;
|
311
|
+
parser->toknext = 0;
|
312
|
+
parser->toksuper = -1;
|
329
313
|
}
|
314
|
+
|
data/ext/fast_mmaped_file/mmap.c
CHANGED
@@ -15,6 +15,58 @@
|
|
15
15
|
#define DEBUGF(format, ...)
|
16
16
|
#endif
|
17
17
|
|
18
|
+
/* This is the ID of the WeakMap used to track strings allocated that
|
19
|
+
* are backed by a memory-mapped file.
|
20
|
+
*/
|
21
|
+
#define WEAK_OBJ_TRACKER "@weak_obj_tracker"
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Maps a given VALUE to some key for the WeakMap. For now, we just use
|
25
|
+
* the integer value as the key since that suffices, though this does
|
26
|
+
* require Ruby 2.7 due to https://bugs.ruby-lang.org/issues/16035.
|
27
|
+
*/
|
28
|
+
static VALUE weak_obj_tracker_get_key(VALUE val) { return val; }
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Adds a T_STRING type to the WeakMap. The WeakMap should be stored
|
32
|
+
* as an instance variable.
|
33
|
+
*/
|
34
|
+
static void weak_obj_tracker_add(VALUE obj, VALUE val) {
|
35
|
+
Check_Type(val, T_STRING);
|
36
|
+
|
37
|
+
VALUE tracker = rb_iv_get(obj, WEAK_OBJ_TRACKER);
|
38
|
+
VALUE key = weak_obj_tracker_get_key(val);
|
39
|
+
|
40
|
+
rb_funcall(tracker, rb_intern("[]="), 2, key, val);
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* Iterator function for updating a single element from the WeakMap.
|
45
|
+
*/
|
46
|
+
VALUE mm_update_obj_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, self)) {
|
47
|
+
Check_Type(self, T_DATA);
|
48
|
+
Check_Type(i, T_STRING);
|
49
|
+
rb_check_arity(argc, 1, 1);
|
50
|
+
|
51
|
+
mm_ipc *i_mm;
|
52
|
+
GET_MMAP(self, i_mm, MM_MODIFY);
|
53
|
+
|
54
|
+
RSTRING(i)->as.heap.ptr = i_mm->t->addr;
|
55
|
+
RSTRING(i)->as.heap.len = i_mm->t->real;
|
56
|
+
|
57
|
+
return Qtrue;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* This iterates through the WeakMap defined on the class and updates
|
62
|
+
* the RStrings to use the newly-allocated memory region.
|
63
|
+
*/
|
64
|
+
void mm_update(VALUE obj) {
|
65
|
+
VALUE tracker = rb_iv_get(obj, WEAK_OBJ_TRACKER);
|
66
|
+
|
67
|
+
rb_block_call(tracker, rb_intern("each_value"), 0, NULL, mm_update_obj_i, obj);
|
68
|
+
}
|
69
|
+
|
18
70
|
typedef struct {
|
19
71
|
VALUE obj, *argv;
|
20
72
|
ID id;
|
@@ -48,6 +100,8 @@ static VALUE mm_str(VALUE obj, int modify) {
|
|
48
100
|
RSTRING(ret)->as.heap.aux.capa = i_mm->t->len;
|
49
101
|
RSTRING(ret)->as.heap.len = i_mm->t->real;
|
50
102
|
|
103
|
+
weak_obj_tracker_add(obj, ret);
|
104
|
+
|
51
105
|
DEBUGF("RString capa: %d, len: %d", RSTRING(ret)->as.heap.aux.capa, RSTRING(ret)->as.heap.len);
|
52
106
|
|
53
107
|
if (modify & MM_ORIGIN) {
|
@@ -208,6 +262,10 @@ VALUE mm_init(VALUE obj, VALUE fname) {
|
|
208
262
|
path = 0;
|
209
263
|
fd = -1;
|
210
264
|
|
265
|
+
VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
|
266
|
+
VALUE weak_obj_tracker = rb_class_new_instance(0, NULL, klass);
|
267
|
+
rb_iv_set(obj, WEAK_OBJ_TRACKER, weak_obj_tracker);
|
268
|
+
|
211
269
|
fname = rb_str_to_str(fname);
|
212
270
|
SafeStringValue(fname);
|
213
271
|
path = StringValuePtr(fname);
|
data/ext/fast_mmaped_file/mmap.h
CHANGED
@@ -52,4 +52,10 @@ VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj);
|
|
52
52
|
VALUE mm_msync(int argc, VALUE *argv, VALUE obj);
|
53
53
|
VALUE mm_unmap(VALUE obj);
|
54
54
|
|
55
|
+
/* If memory is ever reallocated, any allocated Ruby strings that have not been
|
56
|
+
* garbage collected need to be updated with the new region. If this isn't done,
|
57
|
+
* iterating over the Ruby object space and accessing the string data will seg fault.
|
58
|
+
*/
|
59
|
+
void mm_update(VALUE obj);
|
60
|
+
|
55
61
|
#endif
|