prometheus-client-mmap 0.7.0.beta41 → 0.7.0.beta42
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/ext/fast_mmaped_file/extconf.rb +15 -0
- data/ext/fast_mmaped_file/fast_mmaped_file.c +49 -24
- data/ext/fast_mmaped_file/file_parsing.c +84 -109
- data/ext/fast_mmaped_file/file_parsing.h +7 -6
- data/ext/fast_mmaped_file/file_reading.c +41 -32
- data/ext/fast_mmaped_file/file_reading.h +1 -1
- data/ext/fast_mmaped_file/globals.h +3 -0
- data/ext/fast_mmaped_file/hashmap.c +409 -466
- data/ext/fast_mmaped_file/jsmn.c +259 -243
- data/ext/fast_mmaped_file/mmap.c +332 -0
- data/ext/fast_mmaped_file/mmap.h +9 -0
- data/ext/fast_mmaped_file/rendering.c +110 -37
- data/ext/fast_mmaped_file/rendering.h +2 -2
- data/ext/fast_mmaped_file/utils.c +3 -2
- data/ext/fast_mmaped_file/utils.h +1 -1
- data/ext/fast_mmaped_file/value_access.c +88 -48
- data/ext/fast_mmaped_file/value_access.h +4 -2
- data/lib/fast_mmaped_file.bundle +0 -0
- data/lib/prometheus/client/helper/entry_parser.rb +1 -1
- data/lib/prometheus/client/helper/mmaped_file.rb +4 -6
- data/lib/prometheus/client/helper/plain_file.rb +3 -3
- data/lib/prometheus/client/mmaped_dict.rb +2 -7
- data/lib/prometheus/client/simple_value.rb +0 -1
- data/lib/prometheus/client/support/unicorn.rb +9 -0
- data/lib/prometheus/client/version.rb +1 -1
- metadata +3 -25
- data/ext/fast_mmaped_file/hashmap.h +0 -266
- data/ext/fast_mmaped_file/jsmn.h +0 -76
- data/lib/prometheus/client/version.rb.orig +0 -9
@@ -0,0 +1,332 @@
|
|
1
|
+
#include <errno.h>
|
2
|
+
#include <fcntl.h>
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <ruby/util.h>
|
5
|
+
#include <sys/mman.h>
|
6
|
+
|
7
|
+
#include "mmap.h"
|
8
|
+
#include "utils.h"
|
9
|
+
|
10
|
+
#if 0
|
11
|
+
#include <stdio.h>
|
12
|
+
#define DEBUGF(format, ...) printf("%d: " format "\n", __LINE__, __VA_ARGS__)
|
13
|
+
#else
|
14
|
+
#define DEBUGF(format, ...)
|
15
|
+
#endif
|
16
|
+
|
17
|
+
typedef struct {
|
18
|
+
VALUE obj, *argv;
|
19
|
+
ID id;
|
20
|
+
int flag, argc;
|
21
|
+
} mm_bang;
|
22
|
+
|
23
|
+
static VALUE mm_protect_bang(VALUE *t) { return rb_funcall2(t[0], (ID)t[1], (int)t[2], (VALUE *)t[3]); }
|
24
|
+
|
25
|
+
static VALUE mm_recycle(VALUE str) {
|
26
|
+
rb_gc_force_recycle(str);
|
27
|
+
return str;
|
28
|
+
}
|
29
|
+
|
30
|
+
static VALUE mm_vunlock(VALUE obj) {
|
31
|
+
mm_ipc *i_mm;
|
32
|
+
|
33
|
+
GET_MMAP(obj, i_mm, 0);
|
34
|
+
return Qnil;
|
35
|
+
}
|
36
|
+
|
37
|
+
static VALUE mm_str(VALUE obj, int modify) {
|
38
|
+
mm_ipc *i_mm;
|
39
|
+
VALUE ret = Qnil;
|
40
|
+
|
41
|
+
GET_MMAP(obj, i_mm, modify & ~MM_ORIGIN);
|
42
|
+
if (modify & MM_MODIFY) {
|
43
|
+
if (i_mm->t->flag & MM_FROZEN) rb_error_frozen("mmap");
|
44
|
+
if (!OBJ_TAINTED(ret) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify mmap");
|
45
|
+
}
|
46
|
+
ret = rb_obj_alloc(rb_cString);
|
47
|
+
if (rb_obj_tainted(obj)) {
|
48
|
+
OBJ_TAINT(ret);
|
49
|
+
}
|
50
|
+
RSTRING(ret)->as.heap.ptr = i_mm->t->addr;
|
51
|
+
RSTRING(ret)->as.heap.aux.capa = i_mm->t->len;
|
52
|
+
RSTRING(ret)->as.heap.len = i_mm->t->real;
|
53
|
+
|
54
|
+
DEBUGF("RString capa: %d, len: %d", RSTRING(ret)->as.heap.aux.capa, RSTRING(ret)->as.heap.len);
|
55
|
+
|
56
|
+
if (modify & MM_ORIGIN) {
|
57
|
+
#if HAVE_RB_DEFINE_ALLOC_FUNC
|
58
|
+
RSTRING(ret)->as.heap.aux.shared = obj;
|
59
|
+
FL_SET(ret, RSTRING_NOEMBED);
|
60
|
+
FL_SET(ret, FL_USER18);
|
61
|
+
#else
|
62
|
+
RSTRING(ret)->orig = ret;
|
63
|
+
#endif
|
64
|
+
}
|
65
|
+
if (i_mm->t->flag & MM_FROZEN) {
|
66
|
+
ret = rb_obj_freeze(ret);
|
67
|
+
}
|
68
|
+
return ret;
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE mm_i_bang(bang_st) mm_bang *bang_st;
|
72
|
+
{
|
73
|
+
VALUE str, res;
|
74
|
+
mm_ipc *i_mm;
|
75
|
+
|
76
|
+
str = mm_str(bang_st->obj, bang_st->flag);
|
77
|
+
if (bang_st->flag & MM_PROTECT) {
|
78
|
+
VALUE tmp[4];
|
79
|
+
tmp[0] = str;
|
80
|
+
tmp[1] = (VALUE)bang_st->id;
|
81
|
+
tmp[2] = (VALUE)bang_st->argc;
|
82
|
+
tmp[3] = (VALUE)bang_st->argv;
|
83
|
+
res = rb_ensure(mm_protect_bang, (VALUE)tmp, mm_recycle, str);
|
84
|
+
} else {
|
85
|
+
res = rb_funcall2(str, bang_st->id, bang_st->argc, bang_st->argv);
|
86
|
+
RB_GC_GUARD(res);
|
87
|
+
}
|
88
|
+
if (res != Qnil) {
|
89
|
+
GET_MMAP(bang_st->obj, i_mm, 0);
|
90
|
+
i_mm->t->real = RSTRING_LEN(str);
|
91
|
+
}
|
92
|
+
return res;
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE mm_bang_i(VALUE obj, int flag, ID id, int argc, VALUE *argv) {
|
96
|
+
VALUE res;
|
97
|
+
mm_ipc *i_mm;
|
98
|
+
mm_bang bang_st;
|
99
|
+
|
100
|
+
GET_MMAP(obj, i_mm, 0);
|
101
|
+
if ((flag & MM_CHANGE) && (i_mm->t->flag & MM_FIXED)) {
|
102
|
+
rb_raise(rb_eTypeError, "try to change the size of a fixed map");
|
103
|
+
}
|
104
|
+
bang_st.obj = obj;
|
105
|
+
bang_st.flag = flag;
|
106
|
+
bang_st.id = id;
|
107
|
+
bang_st.argc = argc;
|
108
|
+
bang_st.argv = argv;
|
109
|
+
if (i_mm->t->flag & MM_IPC) {
|
110
|
+
res = rb_ensure(mm_i_bang, (VALUE)&bang_st, mm_vunlock, obj);
|
111
|
+
} else {
|
112
|
+
res = mm_i_bang(&bang_st);
|
113
|
+
}
|
114
|
+
if (res == Qnil) return res;
|
115
|
+
return (flag & MM_ORIGIN) ? res : obj;
|
116
|
+
}
|
117
|
+
|
118
|
+
static void mm_free(mm_ipc *i_mm) {
|
119
|
+
if (i_mm->t->path) {
|
120
|
+
if (munmap(i_mm->t->addr, i_mm->t->len) != 0) {
|
121
|
+
if (i_mm->t->path != (char *)-1 && i_mm->t->path != NULL) {
|
122
|
+
free(i_mm->t->path);
|
123
|
+
}
|
124
|
+
free(i_mm);
|
125
|
+
|
126
|
+
rb_raise(rb_eRuntimeError, "munmap failed at %s:%d with errno: %d", __FILE__, __LINE__, errno);
|
127
|
+
}
|
128
|
+
|
129
|
+
if (i_mm->t->path != (char *)-1) {
|
130
|
+
if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
|
131
|
+
truncate(i_mm->t->path, i_mm->t->real) == -1) {
|
132
|
+
free(i_mm->t->path);
|
133
|
+
free(i_mm);
|
134
|
+
rb_raise(rb_eTypeError, "truncate");
|
135
|
+
}
|
136
|
+
free(i_mm->t->path);
|
137
|
+
}
|
138
|
+
}
|
139
|
+
free(i_mm);
|
140
|
+
}
|
141
|
+
|
142
|
+
/*
|
143
|
+
* call-seq:
|
144
|
+
* new(file)
|
145
|
+
*
|
146
|
+
* create a new Mmap object
|
147
|
+
*
|
148
|
+
* * <em>file</em>
|
149
|
+
*
|
150
|
+
*
|
151
|
+
* Creates a mapping that's shared with all other processes
|
152
|
+
* mapping the same areas of the file.
|
153
|
+
*
|
154
|
+
*/
|
155
|
+
VALUE mm_s_new(int argc, VALUE *argv, VALUE obj) {
|
156
|
+
VALUE res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
|
157
|
+
rb_obj_call_init(res, argc, argv);
|
158
|
+
return res;
|
159
|
+
}
|
160
|
+
|
161
|
+
VALUE mm_s_alloc(VALUE obj) {
|
162
|
+
VALUE res;
|
163
|
+
mm_ipc *i_mm;
|
164
|
+
|
165
|
+
res = Data_Make_Struct(obj, mm_ipc, 0, mm_free, i_mm);
|
166
|
+
i_mm->t = ALLOC_N(mm_mmap, 1);
|
167
|
+
MEMZERO(i_mm->t, mm_mmap, 1);
|
168
|
+
i_mm->t->incr = EXP_INCR_SIZE;
|
169
|
+
return res;
|
170
|
+
}
|
171
|
+
|
172
|
+
VALUE mm_init(VALUE obj, VALUE fname) {
|
173
|
+
struct stat st;
|
174
|
+
int fd, smode = 0, pmode = 0, vscope, perm, init;
|
175
|
+
MMAP_RETTYPE addr;
|
176
|
+
mm_ipc *i_mm;
|
177
|
+
char *path;
|
178
|
+
size_t size = 0;
|
179
|
+
off_t offset;
|
180
|
+
|
181
|
+
vscope = 0;
|
182
|
+
path = 0;
|
183
|
+
fd = -1;
|
184
|
+
|
185
|
+
fname = rb_str_to_str(fname);
|
186
|
+
SafeStringValue(fname);
|
187
|
+
path = StringValuePtr(fname);
|
188
|
+
|
189
|
+
{
|
190
|
+
if (rb_safe_level() > 0 && OBJ_TAINTED(fname)) {
|
191
|
+
rb_raise(rb_eSecurityError, "Insecure operation");
|
192
|
+
}
|
193
|
+
rb_secure(1);
|
194
|
+
}
|
195
|
+
|
196
|
+
vscope = MAP_SHARED;
|
197
|
+
size = 0;
|
198
|
+
perm = 0666;
|
199
|
+
|
200
|
+
smode = O_RDWR;
|
201
|
+
pmode = PROT_READ | PROT_WRITE;
|
202
|
+
|
203
|
+
if ((fd = open(path, smode, perm)) == -1) {
|
204
|
+
rb_raise(rb_eArgError, "Can't open %s", path);
|
205
|
+
}
|
206
|
+
|
207
|
+
if (fstat(fd, &st) == -1) {
|
208
|
+
rb_raise(rb_eArgError, "Can't stat %s", path);
|
209
|
+
}
|
210
|
+
size = st.st_size;
|
211
|
+
|
212
|
+
Data_Get_Struct(obj, mm_ipc, i_mm);
|
213
|
+
|
214
|
+
offset = 0;
|
215
|
+
init = 0;
|
216
|
+
|
217
|
+
if (size == 0 && (smode & O_RDWR)) {
|
218
|
+
if (lseek(fd, i_mm->t->incr - 1, SEEK_END) == -1) {
|
219
|
+
rb_raise(rb_eIOError, "Can't lseek %zu", i_mm->t->incr - 1);
|
220
|
+
}
|
221
|
+
if (write(fd, "\000", 1) != 1) {
|
222
|
+
rb_raise(rb_eIOError, "Can't extend %s", path);
|
223
|
+
}
|
224
|
+
init = 1;
|
225
|
+
size = i_mm->t->incr;
|
226
|
+
}
|
227
|
+
|
228
|
+
addr = mmap(0, size, pmode, vscope, fd, offset);
|
229
|
+
close(fd);
|
230
|
+
|
231
|
+
if (addr == MAP_FAILED || !addr) {
|
232
|
+
rb_raise(rb_eArgError, "mmap failed (%d)", errno);
|
233
|
+
}
|
234
|
+
|
235
|
+
i_mm->t->addr = addr;
|
236
|
+
i_mm->t->len = size;
|
237
|
+
if (!init) i_mm->t->real = size;
|
238
|
+
i_mm->t->pmode = pmode;
|
239
|
+
i_mm->t->vscope = vscope;
|
240
|
+
i_mm->t->smode = smode & ~O_TRUNC;
|
241
|
+
i_mm->t->path = (path) ? ruby_strdup(path) : (char *)-1;
|
242
|
+
|
243
|
+
if (smode == O_WRONLY) {
|
244
|
+
i_mm->t->flag |= MM_FIXED;
|
245
|
+
}
|
246
|
+
OBJ_TAINT(obj);
|
247
|
+
return obj;
|
248
|
+
}
|
249
|
+
|
250
|
+
/*
|
251
|
+
* Document-method: []
|
252
|
+
* Document-method: slice
|
253
|
+
*
|
254
|
+
* call-seq: [](args)
|
255
|
+
*
|
256
|
+
* Element reference - with the following syntax:
|
257
|
+
*
|
258
|
+
* self[nth]
|
259
|
+
*
|
260
|
+
* retrieve the <em>nth</em> character
|
261
|
+
*
|
262
|
+
* self[start..last]
|
263
|
+
*
|
264
|
+
* return a substring from <em>start</em> to <em>last</em>
|
265
|
+
*
|
266
|
+
* self[start, length]
|
267
|
+
*
|
268
|
+
* return a substring of <em>lenght</em> characters from <em>start</em>
|
269
|
+
*/
|
270
|
+
VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj) { return mm_bang_i(obj, MM_ORIGIN, rb_intern("[]"), argc, argv); }
|
271
|
+
|
272
|
+
/*
|
273
|
+
* Document-method: msync
|
274
|
+
* Document-method: sync
|
275
|
+
* Document-method: flush
|
276
|
+
*
|
277
|
+
* call-seq: msync
|
278
|
+
*
|
279
|
+
* flush the file
|
280
|
+
*/
|
281
|
+
VALUE mm_msync(int argc, VALUE *argv, VALUE obj) {
|
282
|
+
mm_ipc *i_mm;
|
283
|
+
GET_MMAP(obj, i_mm, MM_MODIFY);
|
284
|
+
|
285
|
+
VALUE oflag;
|
286
|
+
int ret;
|
287
|
+
int flag = MS_SYNC;
|
288
|
+
|
289
|
+
if (argc) {
|
290
|
+
rb_scan_args(argc, argv, "01", &oflag);
|
291
|
+
flag = NUM2INT(oflag);
|
292
|
+
}
|
293
|
+
if ((ret = msync(i_mm->t->addr, i_mm->t->len, flag)) != 0) {
|
294
|
+
rb_raise(rb_eArgError, "msync(%d)", ret);
|
295
|
+
}
|
296
|
+
|
297
|
+
return obj;
|
298
|
+
}
|
299
|
+
|
300
|
+
/*
|
301
|
+
* Document-method: munmap
|
302
|
+
* Document-method: unmap
|
303
|
+
*
|
304
|
+
* call-seq: munmap
|
305
|
+
*
|
306
|
+
* terminate the association
|
307
|
+
*/
|
308
|
+
VALUE mm_unmap(VALUE obj) {
|
309
|
+
mm_ipc *i_mm;
|
310
|
+
|
311
|
+
GET_MMAP(obj, i_mm, 0);
|
312
|
+
if (i_mm->t->path) {
|
313
|
+
if (munmap(i_mm->t->addr, i_mm->t->len) != 0) {
|
314
|
+
if (i_mm->t->path != (char *)-1 && i_mm->t->path != NULL) {
|
315
|
+
free(i_mm->t->path);
|
316
|
+
i_mm->t->path = NULL;
|
317
|
+
}
|
318
|
+
|
319
|
+
rb_raise(rb_eRuntimeError, "munmap failed at %s:%d with errno: %d", __FILE__, __LINE__, errno);
|
320
|
+
}
|
321
|
+
|
322
|
+
if (i_mm->t->path != (char *)-1) {
|
323
|
+
if (i_mm->t->real < i_mm->t->len && i_mm->t->vscope != MAP_PRIVATE &&
|
324
|
+
truncate(i_mm->t->path, i_mm->t->real) == -1) {
|
325
|
+
rb_raise(rb_eTypeError, "truncate");
|
326
|
+
}
|
327
|
+
free(i_mm->t->path);
|
328
|
+
}
|
329
|
+
i_mm->t->path = NULL;
|
330
|
+
}
|
331
|
+
return Qnil;
|
332
|
+
}
|
data/ext/fast_mmaped_file/mmap.h
CHANGED
@@ -20,6 +20,8 @@
|
|
20
20
|
#define MMAP_RETTYPE void *
|
21
21
|
#endif
|
22
22
|
|
23
|
+
#define EXP_INCR_SIZE 4096
|
24
|
+
|
23
25
|
typedef struct {
|
24
26
|
MMAP_RETTYPE addr;
|
25
27
|
int smode, pmode, vscope;
|
@@ -46,4 +48,11 @@ typedef struct {
|
|
46
48
|
rb_error_frozen("mmap"); \
|
47
49
|
}
|
48
50
|
|
51
|
+
VALUE mm_s_alloc(VALUE obj);
|
52
|
+
VALUE mm_s_new(int argc, VALUE *argv, VALUE obj);
|
53
|
+
VALUE mm_init(VALUE obj, VALUE fname);
|
54
|
+
VALUE mm_aref_m(int argc, VALUE *argv, VALUE obj);
|
55
|
+
VALUE mm_msync(int argc, VALUE *argv, VALUE obj);
|
56
|
+
VALUE mm_unmap(VALUE obj);
|
57
|
+
|
49
58
|
#endif
|
@@ -1,53 +1,110 @@
|
|
1
|
-
#include
|
1
|
+
#include <float.h>
|
2
2
|
#include <jsmn.h>
|
3
|
-
#include <file_parsing.h>
|
4
|
-
#include <utils.h>
|
5
3
|
|
6
|
-
|
7
|
-
|
4
|
+
#include "file_parsing.h"
|
5
|
+
#include "globals.h"
|
6
|
+
#include "rendering.h"
|
7
|
+
#include "utils.h"
|
8
|
+
|
9
|
+
#ifndef DBL_DECIMAL_DIG
|
10
|
+
#define DBL_DECIMAL_DIG 17
|
11
|
+
#endif
|
12
|
+
|
13
|
+
// inline min_t()
|
14
|
+
|
15
|
+
static inline int is_valid(const jsmntok_t *token) { return token->start < token->end && token->start >= 0; }
|
16
|
+
static inline int valid_not_null(const entry_t *entry, const jsmntok_t *token) {
|
17
|
+
static const char null_s[] = "null";
|
18
|
+
|
19
|
+
if (!is_valid(token)) {
|
20
|
+
return 0;
|
21
|
+
}
|
22
|
+
|
23
|
+
if (token->type != JSMN_PRIMITIVE) {
|
24
|
+
return 1;
|
25
|
+
}
|
26
|
+
|
27
|
+
size_t token_len = token->end - token->start;
|
28
|
+
|
29
|
+
if (token_len < sizeof(null_s) - 1) {
|
30
|
+
return 1;
|
31
|
+
}
|
32
|
+
|
33
|
+
return strncmp(null_s, entry->json + token->start, sizeof(null_s) - 1) != 0;
|
8
34
|
}
|
9
35
|
|
10
|
-
inline
|
11
|
-
|
36
|
+
static inline int append_token(VALUE string, const entry_t *entry, const jsmntok_t *token) {
|
37
|
+
if (!is_valid(token)) {
|
38
|
+
save_exception(prom_eParsingError, "parsing failed: %s", entry->json);
|
39
|
+
return 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
rb_str_cat(string, entry->json + token->start, token->end - token->start);
|
43
|
+
return 1;
|
12
44
|
}
|
13
45
|
|
14
|
-
|
46
|
+
static int append_entry(VALUE string, const entry_t *entry) {
|
15
47
|
jsmn_parser parser;
|
16
48
|
jsmn_init(&parser);
|
17
49
|
|
18
|
-
jsmntok_t
|
19
|
-
int r = jsmn_parse(&parser, entry->json, entry->json_size,
|
50
|
+
jsmntok_t tokens[200];
|
51
|
+
int r = jsmn_parse(&parser, entry->json, entry->json_size, tokens, sizeof(tokens) / sizeof(tokens[0]));
|
20
52
|
|
21
|
-
if (r <
|
22
|
-
|
53
|
+
if (r < 0) {
|
54
|
+
save_exception(prom_eParsingError, "too many labels or malformed json: %s", entry->json);
|
55
|
+
return 0;
|
23
56
|
}
|
24
57
|
|
25
|
-
//
|
26
|
-
|
58
|
+
//
|
59
|
+
// Example JSON "['name', 'name',['label_a','label_b'],['value_a', 'value_b']]"
|
60
|
+
// will be parsed into following token list:
|
61
|
+
//
|
62
|
+
// [ "'name', 'name',['label_a','label_b'],['value_a', 'value_b']",
|
63
|
+
// "name", "name",
|
64
|
+
// "['label_a','label_b']", "label_a", "label_b",
|
65
|
+
// "['value_a', 'value_b']", "value_a", "value_b" ]
|
66
|
+
static int labels_start_offset = 4;
|
67
|
+
|
68
|
+
if (r < labels_start_offset) {
|
69
|
+
save_exception(prom_eParsingError, "malformed json: %s", entry->json);
|
70
|
+
return 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
int label_cnt = (r - 5) / 2;
|
74
|
+
jsmntok_t *name_token = &tokens[2];
|
75
|
+
|
76
|
+
if (!append_token(string, entry, name_token)) {
|
77
|
+
return 0;
|
78
|
+
}
|
79
|
+
if (label_cnt > 0) {
|
80
|
+
if ((r - 5) % 2 != 0) {
|
81
|
+
save_exception(prom_eParsingError, "mismatched number of labels: %s", entry->json);
|
82
|
+
return 0;
|
83
|
+
}
|
27
84
|
|
28
|
-
append_token(string, entry, &t[2]);
|
29
|
-
if (label_cnt > 0){
|
30
85
|
rb_str_cat(string, "{", 1);
|
31
86
|
|
32
|
-
for(int i = 0; i < label_cnt; i++){
|
33
|
-
int key =
|
34
|
-
int val =
|
35
|
-
|
36
|
-
append_token(string, entry, &
|
87
|
+
for (int i = 0; i < label_cnt; i++) {
|
88
|
+
int key = labels_start_offset + i;
|
89
|
+
int val = labels_start_offset + label_cnt + 1 + i;
|
90
|
+
|
91
|
+
if (!append_token(string, entry, &tokens[key])) {
|
92
|
+
return 0;
|
93
|
+
}
|
37
94
|
rb_str_cat(string, "=", 1);
|
38
95
|
|
39
96
|
rb_str_cat(string, "\"", 1);
|
40
|
-
if (
|
41
|
-
append_token(string, entry, &
|
97
|
+
if (valid_not_null(entry, &tokens[val])) {
|
98
|
+
append_token(string, entry, &tokens[val]);
|
42
99
|
}
|
43
100
|
rb_str_cat(string, "\"", 1);
|
44
101
|
|
45
|
-
if (i < label_cnt - 1){
|
102
|
+
if (i < label_cnt - 1) {
|
46
103
|
rb_str_cat(string, ",", 1);
|
47
104
|
}
|
48
105
|
}
|
49
106
|
|
50
|
-
if (is_pid_significant(entry)){
|
107
|
+
if (is_pid_significant(entry)) {
|
51
108
|
rb_str_cat(string, ",pid=\"", 6);
|
52
109
|
rb_str_append(string, entry->pid);
|
53
110
|
rb_str_cat(string, "\"", 1);
|
@@ -58,12 +115,14 @@ void append_entry(VALUE string, const entry_struct *entry){
|
|
58
115
|
|
59
116
|
char value[255];
|
60
117
|
|
61
|
-
//
|
62
|
-
int written = snprintf(value, sizeof(value), "
|
118
|
+
// print value with highest possible precision so that we do not lose any data
|
119
|
+
int written = snprintf(value, sizeof(value), " %.*g\n", DBL_DECIMAL_DIG, entry->value);
|
63
120
|
rb_str_cat(string, value, written);
|
121
|
+
|
122
|
+
return 1;
|
64
123
|
}
|
65
124
|
|
66
|
-
void append_entry_head(VALUE string, const
|
125
|
+
static void append_entry_head(VALUE string, const entry_t *entry) {
|
67
126
|
static const char help_beg[] = "# HELP ";
|
68
127
|
static const char help_fin[] = " Multiprocess metric\n";
|
69
128
|
|
@@ -80,20 +139,34 @@ void append_entry_head(VALUE string, const entry_struct *entry){
|
|
80
139
|
rb_str_cat(string, "\n", 1);
|
81
140
|
}
|
82
141
|
|
83
|
-
|
84
|
-
|
142
|
+
static inline int entry_name_equal(const entry_t *a, const entry_t *b) {
|
143
|
+
if (a == NULL || b == NULL) {
|
144
|
+
return a == b;
|
145
|
+
}
|
146
|
+
|
147
|
+
if (a->name_len != b->name_len) {
|
148
|
+
return 0;
|
149
|
+
}
|
85
150
|
|
86
|
-
|
151
|
+
return strncmp(a->name, b->name, a->name_len) == 0;
|
152
|
+
}
|
87
153
|
|
88
|
-
|
89
|
-
|
90
|
-
|
154
|
+
int entries_to_string(VALUE string, entry_t **sorted_entries, size_t entries_count) {
|
155
|
+
entry_t *previous = NULL;
|
156
|
+
|
157
|
+
for (size_t i = 0; i < entries_count; i++) {
|
158
|
+
entry_t *entry = sorted_entries[i];
|
159
|
+
|
160
|
+
// when entry->name changes write metric header
|
161
|
+
if (!entry_name_equal(previous, entry)) {
|
91
162
|
previous = entry;
|
92
|
-
append_entry_head(
|
163
|
+
append_entry_head(string, entry);
|
93
164
|
}
|
94
165
|
|
95
|
-
append_entry(
|
166
|
+
if (!append_entry(string, entry)) {
|
167
|
+
return 0;
|
168
|
+
}
|
96
169
|
}
|
97
170
|
|
98
|
-
return
|
171
|
+
return 1;
|
99
172
|
}
|