prometheus-client-mmap 0.7.0.beta39 → 0.7.0.beta40

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 588b2d270f9bf3e00435fcac7442db8e7d6adea7
4
- data.tar.gz: c9a90cdf6392e9a772a7ee131d4e3391d98027c3
3
+ metadata.gz: 2f51d0d3d39230181b8a35905cac312c52dde03b
4
+ data.tar.gz: 1ec3f78ad1276fb225d73e31f1f0e91369c8afa2
5
5
  SHA512:
6
- metadata.gz: 680f78fb4a00d297bf5afa78b45ab38b98c362ec44408de5af420b3674fe5859ae89449ec57b4105d10a4864ba5468e0f4e35b3e8847dd433d7398641488a50d
7
- data.tar.gz: baa5985553a72cab9a157b21b5a42b3682c59ee742410068922221497e21af356434239491c0d230600825a1eb1781adce3c3d87d2d9d63345feb61c71ec4397
6
+ metadata.gz: bf88cde2f108d7b3ade4ae808e0be40256acfa39cc8df26a3ce6ed7e023113314907f777afee1e28ac252293f46815b5bc898b9ab35485ccc61cc387b1c49934
7
+ data.tar.gz: 2d47f29dba886af6f5d3d462754712074e3c7d3e11c1072f399fd9621055299ec16dd5baa5e18c765220e013171d8b21596c7f96593ceb94479773821cd1b3cc
@@ -1,5 +1,5 @@
1
1
  require 'mkmf'
2
- $CFLAGS << ' -std=c99 -Wall -Wextra -Werror'
2
+ $CFLAGS << ' -std=c11 -Wall -Wextra -Werror'
3
3
 
4
4
  CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
5
5
 
@@ -1,175 +1,101 @@
1
1
  #include <ruby.h>
2
2
  #include <ruby/intern.h>
3
- #include <sys/mman.h>
4
- #include <unistd.h>
5
- #include <fcntl.h>
6
3
  #include <errno.h>
7
4
 
8
- #include "mmap.h"
5
+ #include <utils.h>
6
+ #include <value_access.h>
7
+ #include <globals.h>
9
8
 
10
- VALUE MMAPED_FILE = Qnil;
11
-
12
- #define START_POSITION 8
13
- #define INITIAL_SIZE (2 * sizeof(int32_t))
14
-
15
- int open_and_extend_file(mm_ipc *i_mm, size_t len) {
16
- int fd;
17
-
18
- if ((fd = open(i_mm->t->path, i_mm->t->smode)) == -1) {
19
- rb_raise(rb_eArgError, "Can't open %s", i_mm->t->path);
20
- }
21
-
22
- if (lseek(fd, len - i_mm->t->len - 1, SEEK_END) == -1) {
23
- close(fd);
24
- rb_raise(rb_eIOError, "Can't lseek %zu", len - i_mm->t->len - 1);
25
- }
26
-
27
- if (write(fd, "\000", 1) != 1) {
28
- close(fd);
29
- rb_raise(rb_eIOError, "Can't extend %s", i_mm->t->path);
30
- }
31
-
32
- return fd;
33
- }
34
-
35
- void expand(mm_ipc *i_mm, size_t len) {
36
- if (len < i_mm->t->len) {
37
- rb_raise(rb_eArgError, "Can't reduce the size of mmap");
38
- }
39
-
40
- if (munmap(i_mm->t->addr, i_mm->t->len)) {
41
- rb_raise(rb_eArgError, "munmap failed");
42
- }
43
-
44
- int fd = open_and_extend_file(i_mm, len);
45
-
46
- i_mm->t->addr = mmap(0, len, i_mm->t->pmode, i_mm->t->vscope, fd, i_mm->t->offset);
47
-
48
- if (i_mm->t->addr == MAP_FAILED) {
49
- close(fd);
50
- rb_raise(rb_eArgError, "mmap failed");
51
- }
52
-
53
- if (close(fd) == -1) {
54
- rb_raise(rb_eArgError, "Can't close %s", i_mm->t->path);
55
- }
56
-
57
- if ((i_mm->t->flag & MM_LOCK) && mlock(i_mm->t->addr, len) == -1) {
58
- rb_raise(rb_eArgError, "mlock(%d)", errno);
59
- }
60
- i_mm->t->len = len;
61
- i_mm->t->real = len;
62
- }
63
-
64
- inline uint32_t padding_length(uint32_t key_length) {
65
- return 8 - (sizeof(uint32_t) + key_length) % 8; // padding | 8 byte aligned
66
- }
67
-
68
- void save_entry(mm_ipc *i_mm, uint32_t offset, VALUE key, VALUE value){
69
- uint32_t key_length = (uint32_t)RSTRING_LEN(key);
70
-
71
- char *pos = (char *)i_mm->t->addr + offset;
72
9
 
73
- memcpy(pos, &key_length, sizeof(uint32_t));
74
- pos += sizeof(uint32_t);
10
+ #include <jsmn.h>
11
+ #include <hashmap.h>
12
+ #include <file_reading.h>
13
+ #include <file_parsing.h>
14
+ #include <rendering.h>
75
15
 
76
- memmove(pos, StringValuePtr(key), key_length);
77
- pos += key_length;
78
-
79
- memset(pos, ' ', padding_length(key_length));
80
- pos += padding_length(key_length);
81
-
82
- double val = NUM2DBL(value);
83
- memcpy(pos, &val, sizeof(double));
84
- }
85
-
86
- inline uint32_t load_used(mm_ipc *i_mm) {
87
- uint32_t used = *((uint32_t *)i_mm->t->addr);
88
-
89
- if (used == 0) {
90
- used = START_POSITION;
91
- }
92
- return used;
93
- }
94
-
95
- inline void save_used(mm_ipc *i_mm, uint32_t used) {
96
- *((uint32_t *)i_mm->t->addr) = used;
97
- }
98
-
99
- VALUE method_load_used(VALUE self) {
100
- mm_ipc *i_mm;
101
-
102
- GET_MMAP(self, i_mm, MM_MODIFY);
103
- return UINT2NUM(load_used(i_mm));
104
- }
105
-
106
- VALUE method_save_used(VALUE self, VALUE value) {
107
- Check_Type(value, T_FIXNUM);
108
- mm_ipc *i_mm;
109
-
110
- GET_MMAP(self, i_mm, MM_MODIFY);
16
+ VALUE MMAPED_FILE = Qnil;
111
17
 
112
- if (i_mm->t->len < INITIAL_SIZE) {
113
- expand(i_mm, INITIAL_SIZE);
18
+ ID sym_min;
19
+ ID sym_max;
20
+ ID sym_livesum;
21
+ ID sym_gauge;
22
+ ID sym_pid;
23
+ ID sym_samples;
24
+ ID sym_key_name;
25
+
26
+ int aggregate_files(struct hashmap *map, VALUE list_of_files){
27
+ buffer_t reading_buffer = (buffer_t) { .buffer = NULL };
28
+ for(int i =0; i< RARRAY_LEN(list_of_files); i++){
29
+ VALUE params = RARRAY_PTR(list_of_files)[i];
30
+ file_t file;
31
+
32
+ if (!file_open_from_params(&file, params)) {
33
+ buffer_dispose(&reading_buffer);
34
+ return 0;
35
+ }
36
+
37
+ if (!read_from_file(&file, &reading_buffer)){
38
+ buffer_dispose(&reading_buffer);
39
+ file_close(&file);
40
+ return 0;
41
+ }
42
+
43
+ if (!process_buffer(&file, &reading_buffer, map)){
44
+ buffer_dispose(&reading_buffer);
45
+ file_close(&file);
46
+ return 0;
47
+ }
48
+
49
+ if (!file_close(&file)){
50
+ buffer_dispose(&reading_buffer);
51
+ return 0;
52
+ }
114
53
  }
115
54
 
116
- save_used(i_mm, NUM2UINT(value));
117
- return value;
55
+ buffer_dispose(&reading_buffer);
56
+ return 1;
118
57
  }
119
58
 
120
- VALUE method_add_entry(VALUE self, VALUE positions, VALUE key, VALUE value) {
121
- Check_Type(positions, T_HASH);
122
- Check_Type(key, T_STRING);
59
+ VALUE method_to_metrics(VALUE UNUSED(self), VALUE file_list){
60
+ struct hashmap map;
61
+ hashmap_setup(&map);
123
62
 
124
- VALUE position = rb_hash_lookup(positions, key);
125
- if (position != Qnil){
126
- return position;
63
+ if (!aggregate_files(&map, file_list)){ // all entries in map are now copies that need to be disposed
64
+ hashmap_destroy(&map);
65
+ raise_last_exception();
66
+ return Qnil;
127
67
  }
128
68
 
129
- mm_ipc *i_mm;
130
- GET_MMAP(self, i_mm, MM_MODIFY);
69
+ entry_struct **sorted_entries;
131
70
 
132
- if (i_mm->t->flag & MM_FROZEN) {
133
- rb_error_frozen("mmap");
134
- }
71
+ if (!sort_map_entries(&map, &sorted_entries)){
72
+ entries_destroy(&map);
73
+ hashmap_destroy(&map);
135
74
 
136
- if (RSTRING_LEN(key) > INT32_MAX) {
137
- rb_raise(rb_eArgError, "string length gt %d", INT32_MAX);
75
+ raise_last_exception();
76
+ return Qnil;
138
77
  }
139
78
 
140
- uint32_t key_length = (uint32_t)RSTRING_LEN(key);
141
- uint32_t value_offset = sizeof(uint32_t) + key_length + padding_length(key_length);
142
- uint32_t entry_length = value_offset + sizeof(double);
143
-
144
- uint32_t used = load_used(i_mm);
145
- while (i_mm->t->len < (used + entry_length)) {
146
- expand(i_mm, i_mm->t->len * 2);
147
- }
79
+ VALUE rv = entries_to_string(sorted_entries, hashmap_size(&map));
148
80
 
149
- save_entry(i_mm, used, key, value);
150
- save_used(i_mm, used + entry_length);
151
- return rb_hash_aset(positions, key, INT2NUM(used + value_offset));
152
- }
153
-
154
- VALUE method_get_double(VALUE self, VALUE index) {
155
- mm_ipc *i_mm;
156
- GET_MMAP(self, i_mm, MM_MODIFY);
157
-
158
- Check_Type(index, T_FIXNUM);
159
- size_t idx = NUM2UINT(index);
160
-
161
- if ((i_mm->t->real + sizeof(double)) <= idx) {
162
- rb_raise(rb_eIndexError, "index %zu out of string", idx);
163
- }
164
-
165
- double tmp;
166
-
167
- memcpy(&tmp, (char *)i_mm->t->addr + idx, sizeof(double));
168
- return DBL2NUM(tmp);
81
+ free(sorted_entries);
82
+ entries_destroy(&map);
83
+ hashmap_destroy(&map);
84
+ return rv;
169
85
  }
170
86
 
171
87
  void Init_fast_mmaped_file() {
88
+ sym_gauge = rb_intern("gauge");
89
+ sym_min = rb_intern("min");
90
+ sym_max = rb_intern("max");
91
+ sym_livesum = rb_intern("livesum");
92
+ sym_pid = rb_intern("pid");
93
+ sym_samples = rb_intern("samples");
94
+ sym_key_name = rb_intern("__key_name");
95
+
172
96
  MMAPED_FILE = rb_define_module("FastMmapedFile");
97
+ rb_define_singleton_method(MMAPED_FILE, "to_metrics", method_to_metrics, 1);
98
+
173
99
  rb_define_method(MMAPED_FILE, "get_double", method_get_double, 1);
174
100
  rb_define_method(MMAPED_FILE, "used", method_load_used, 0);
175
101
  rb_define_method(MMAPED_FILE, "used=", method_save_used, 1);
File without changes
@@ -0,0 +1,13 @@
1
+ #ifndef FILE_FORMAT_H
2
+ #define FILE_FORMAT_H
3
+
4
+ #include <stdint.h>
5
+
6
+ #define START_POSITION 8
7
+ #define INITIAL_SIZE (2 * sizeof(int32_t))
8
+
9
+ inline uint32_t padding_length(uint32_t key_length) {
10
+ return 8 - (sizeof(uint32_t) + key_length) % 8; // padding | 8 byte aligned
11
+ }
12
+
13
+ #endif
@@ -0,0 +1,222 @@
1
+ #include <hashmap.h>
2
+ #include <file_format.h>
3
+ #include <globals.h>
4
+ #include <utils.h>
5
+ #include <jsmn.h>
6
+ #include "file_parsing.h"
7
+
8
+ //ID sym_gauge;
9
+ //ID sym_min;
10
+ //ID sym_max;
11
+ //ID sym_livesum;
12
+
13
+ HASHMAP_FUNCS_CREATE(entry, const entry_struct, entry_struct)
14
+
15
+ typedef int (*compare_fn) (const void *a, const void *b);
16
+
17
+ inline int is_pid_significant(const entry_struct *a){
18
+ ID mp = a->multiprocess_mode;
19
+ return a->type == sym_gauge && !(mp == sym_min || mp == sym_max || mp == sym_livesum);
20
+ }
21
+
22
+ size_t hashmap_hash_entry(const entry_struct *entry){
23
+ size_t hash = 0;
24
+
25
+ for (size_t i = 0; i < entry->json_size; i++) {
26
+ hash += *(const char *)(entry->json + i);
27
+ hash += (hash << 10);
28
+ hash ^= (hash >> 6);
29
+ }
30
+ hash += (hash << 3);
31
+ hash ^= (hash >> 11);
32
+ hash += (hash << 15);
33
+ return hash;
34
+ }
35
+
36
+ int hashmap_compare_entry(const entry_struct *a, const entry_struct *b)
37
+ {
38
+ if (a->json_size != b->json_size){
39
+ return -1;
40
+ }
41
+
42
+ if (is_pid_significant(a) && (rb_str_equal(a->pid, b->pid) == Qfalse)){ //OPTIONAL TODO: optimize rb out
43
+ return -1;
44
+ }
45
+
46
+ return strncmp(a->json, b->json, a->json_size);
47
+ }
48
+
49
+ entry_struct *copy_entry(const entry_struct *entry){
50
+ entry_struct *copied = (entry_struct *)malloc(sizeof(entry_struct));
51
+ if (copied == NULL) {
52
+ return NULL;
53
+ }
54
+ memcpy(copied, entry, sizeof(entry_struct));
55
+
56
+ copied->json = malloc(entry->json_size);
57
+ if (copied->json == NULL){
58
+ free(copied);
59
+ return NULL;
60
+ }
61
+
62
+ memcpy(copied->json, entry->json, entry->json_size);
63
+
64
+ return copied;
65
+ }
66
+
67
+ void entry_free(entry_struct *entry){
68
+ free(entry->json);
69
+ free(entry);
70
+ }
71
+
72
+ void merge_entry(entry_struct *found, const entry_struct *entry){
73
+ if (entry->type == sym_gauge){
74
+ if (entry->multiprocess_mode == sym_min){
75
+ found->value = min(found->value, entry->value);
76
+ } else if (entry->multiprocess_mode == sym_max) {
77
+ found->value = max(found->value, entry->value);
78
+ } else if (entry->multiprocess_mode == sym_livesum) {
79
+ found->value += entry->value;
80
+ } else {
81
+ found->value += entry->value; //TODO: this shouldn't happen
82
+ }
83
+ } else {
84
+ found->value += entry->value;
85
+ }
86
+ }
87
+
88
+ int process_entry(struct hashmap *map, const entry_struct *entry){
89
+ entry_struct *found = entry_hashmap_get(map, entry);
90
+ if (found){
91
+ merge_entry(found, entry);
92
+ } else {
93
+ entry_struct *copy = copy_entry(entry);
94
+ if (copy == NULL) {
95
+ save_exception(rb_eNoMemError, "Failed copying metrics entry");
96
+ return 0;
97
+ }
98
+ entry_hashmap_put(map, copy, copy); // use the hashmap like hashset actually
99
+ }
100
+ return 1;
101
+ }
102
+
103
+ inline entry_struct entry_new(char* json, size_t json_size, double value, uint32_t pid){
104
+ return (entry_struct) { .json = json, .json_size = json_size, .pid = pid, .value = value, .name_len = 0 };
105
+ }
106
+
107
+ void add_parsed_name(entry_struct *entry){
108
+ jsmn_parser parser;
109
+ jsmn_init(&parser);
110
+
111
+ jsmntok_t t[2];
112
+ int r = jsmn_parse(&parser, entry->json, entry->json_size, t, 2);
113
+
114
+ if (r < 1) {
115
+ //TODO: better handle this case
116
+ }
117
+
118
+ entry->name = entry->json + t[1].start;
119
+ entry->name_len = t[1].end - t[1].start;
120
+ }
121
+
122
+ int entry_lexical_comparator(const entry_struct **a, const entry_struct **b){
123
+ size_t min_length = min((*a)->json_size, (*b)->json_size);
124
+ return strncmp((*a)->json, (*b)->json, min_length);
125
+ }
126
+
127
+ // public functions
128
+
129
+ void hashmap_setup(struct hashmap *map){
130
+ hashmap_init(map, (size_t (*)(const void *))hashmap_hash_entry, (int (*)(const void *, const void *))hashmap_compare_entry, 1000);
131
+ }
132
+
133
+ void entries_destroy(struct hashmap *map){
134
+ struct hashmap_iter *iter;
135
+ for (iter = hashmap_iter(map); iter; iter = hashmap_iter_next(map, iter)) {
136
+ entry_struct *entry = (entry_struct *)entry_hashmap_iter_get_key(iter);
137
+ entry_free(entry);
138
+ }
139
+ }
140
+
141
+ int process_buffer(file_t *file_info, buffer_t *source, struct hashmap *map){
142
+ if (source->size < START_POSITION) {
143
+ // nothing to read
144
+ return 1;
145
+ }
146
+ uint32_t used;
147
+ memcpy(&used, source->buffer, sizeof(uint32_t));
148
+
149
+ if (used > source->size){
150
+ //TODO: add custom parsing error
151
+ save_exception(rb_eRuntimeError, "source file %s corrupted, used %u > file size %u",
152
+ file_info->path, used, source->size);
153
+ return 0;
154
+ }
155
+
156
+ uint32_t pos = START_POSITION;
157
+ while (pos + sizeof(uint32_t) < used) {
158
+ uint32_t encoded_len;
159
+ memcpy(&encoded_len, source->buffer + pos, sizeof(uint32_t));
160
+ pos += sizeof(uint32_t);
161
+
162
+ uint32_t value_offset = encoded_len + padding_length(encoded_len);
163
+
164
+ if (pos + value_offset + sizeof(double) > used) {
165
+ //TODO: add custom parsing error
166
+ save_exception(rb_eRuntimeError, "source file %s corrupted, used %u < stored data length %u",
167
+ file_info->path, used, pos + value_offset + sizeof(double));
168
+ return 0;
169
+ }
170
+
171
+ entry_struct entry = entry_new(source->buffer + pos, encoded_len, 0, 0.0);
172
+
173
+ entry.multiprocess_mode = file_info->multiprocess_mode;
174
+ entry.pid = file_info->pid;
175
+ entry.type = file_info->type;
176
+
177
+ *(entry.json + encoded_len) = '\0'; // TODO: NONO
178
+
179
+ pos += value_offset;
180
+ memcpy(&entry.value, source->buffer + pos, sizeof(double)); //too
181
+
182
+ if (!process_entry(map, &entry)) {
183
+ entries_destroy(map);
184
+ return 0;
185
+ }
186
+
187
+ pos += sizeof(double);
188
+ }
189
+ return 1;
190
+ }
191
+
192
+ int sort_map_entries(const struct hashmap *map, entry_struct ***sorted_entries){
193
+ size_t num = hashmap_size(map);
194
+
195
+ size_t list_size = num * sizeof(entry_struct *);
196
+ entry_struct **list = malloc(list_size);
197
+
198
+ if (list == NULL){
199
+ save_exception(rb_eNoMemError, "Couldn't allocate %zu memory", list_size);
200
+ return 0;
201
+ }
202
+
203
+ size_t cnt = 0;
204
+ struct hashmap_iter *iter;
205
+ for (iter = hashmap_iter(map); iter; iter = hashmap_iter_next(map, iter)) {
206
+ entry_struct *entry = (entry_struct *)entry_hashmap_iter_get_key(iter);
207
+ add_parsed_name(entry);
208
+
209
+ list[cnt] = entry;
210
+ cnt++;
211
+ }
212
+ if (cnt != num){
213
+ save_exception(rb_eRuntimeError, "Processed entries %zu != map entries %zu", cnt, num);
214
+ free(list);
215
+ return 0;
216
+ }
217
+
218
+ qsort(list, cnt, sizeof(entry_struct *), (compare_fn)&entry_lexical_comparator);
219
+ *sorted_entries = list;
220
+ return 1;
221
+ }
222
+