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

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 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
+