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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49ac78e6bb20f940989a545386f5a8340dd3a046
4
- data.tar.gz: e11aeb1946d4c4afa0f09e5037bbb7b7e5c23a6e
3
+ metadata.gz: e546160d5f4baf942cd59595ba9f4738f5bb112a
4
+ data.tar.gz: d2369f52a14a938fec91c09d372396c031992234
5
5
  SHA512:
6
- metadata.gz: 961b21816d5e183e2ea030512481b9627671d66b632ed2be9644eda9ed512a933a4f96a6fef06163ea21998675c6a226e6571f3bda4a10b97c83189d066f489c
7
- data.tar.gz: 2351c759ee985a918c5aecaa752cb4071fb0686f4185944ea13559b9bc3cb1fd7b8b8c2e1a166be689f0a960a02204d6a277243c331ddde97814f1a393f632c5
6
+ metadata.gz: c02fd8414f65779692b0aac43e89f53a87492843bae04891924838320533f495de9977ba2c99c72d34553d937268fa0ee6b5859861f1f13a86a5969c74b4320f
7
+ data.tar.gz: e9bf20cc0e44dd7307b429dd088d82702a25073bbd72ff0cc9315d4e2580e7438042b98032c21f7ddb0f668afd6bf42c0018e3f4bd81dfb40c30b79d0ecab9b4
@@ -1,7 +1,22 @@
1
1
  require 'mkmf'
2
+ require 'fileutils'
3
+
2
4
  $CFLAGS << ' -std=c99 -D_POSIX_C_SOURCE=200809L -Wall -Wextra -Werror'
3
5
 
6
+ if enable_config('address-sanitizer')
7
+ $CFLAGS << ' -O -fsanitize=address -fno-omit-frame-pointer -g'
8
+ end
9
+
4
10
  CONFIG['warnflags'].slice!(/ -Wdeclaration-after-statement/)
5
11
 
12
+ cwd = File.expand_path(File.dirname(__FILE__))
13
+ vendor_dir = File.join(cwd, '../../vendor/c')
14
+ src_dir = File.join(cwd, '../../ext/fast_mmaped_file')
15
+
16
+ src_files = %W[#{vendor_dir}/jsmn/jsmn.c #{vendor_dir}/hashmap/src/hashmap.c]
17
+ FileUtils.cp(src_files, src_dir)
18
+
19
+ $INCFLAGS << " -I#{vendor_dir}/jsmn -I#{vendor_dir}/hashmap/src"
20
+
6
21
  dir_config('fast_mmaped_file')
7
22
  create_makefile('fast_mmaped_file')
@@ -1,16 +1,20 @@
1
+ #include <errno.h>
1
2
  #include <ruby.h>
2
3
  #include <ruby/intern.h>
3
- #include <errno.h>
4
4
 
5
- #include <utils.h>
6
- #include <value_access.h>
7
- #include <globals.h>
5
+ #include <sys/mman.h>
8
6
 
9
- #include <jsmn.h>
10
7
  #include <hashmap.h>
11
- #include <file_reading.h>
12
- #include <file_parsing.h>
13
- #include <rendering.h>
8
+ #include <jsmn.h>
9
+
10
+ #include "globals.h"
11
+ #include "utils.h"
12
+ #include "value_access.h"
13
+
14
+ #include "file_parsing.h"
15
+ #include "file_reading.h"
16
+ #include "mmap.h"
17
+ #include "rendering.h"
14
18
 
15
19
  VALUE MMAPED_FILE = Qnil;
16
20
 
@@ -21,9 +25,13 @@ ID sym_gauge;
21
25
  ID sym_pid;
22
26
  ID sym_samples;
23
27
 
24
- int aggregate_files(struct hashmap *map, VALUE list_of_files){
25
- buffer_t reading_buffer = (buffer_t) { .buffer = NULL };
26
- for(int i =0; i< RARRAY_LEN(list_of_files); i++){
28
+ VALUE prom_eParsingError;
29
+
30
+ int aggregate_files(struct hashmap *map, VALUE list_of_files) {
31
+ buffer_t reading_buffer;
32
+ memset(&reading_buffer, 0, sizeof(buffer_t));
33
+
34
+ for (int i = 0; i < RARRAY_LEN(list_of_files); i++) {
27
35
  VALUE params = RARRAY_PTR(list_of_files)[i];
28
36
  file_t file;
29
37
 
@@ -32,19 +40,19 @@ int aggregate_files(struct hashmap *map, VALUE list_of_files){
32
40
  return 0;
33
41
  }
34
42
 
35
- if (!read_from_file(&file, &reading_buffer)){
43
+ if (!read_from_file(&file, &reading_buffer)) {
36
44
  buffer_dispose(&reading_buffer);
37
45
  file_close(&file);
38
46
  return 0;
39
47
  }
40
48
 
41
- if (!process_buffer(&file, &reading_buffer, map)){
49
+ if (!process_buffer(&file, &reading_buffer, map)) {
42
50
  buffer_dispose(&reading_buffer);
43
51
  file_close(&file);
44
52
  return 0;
45
53
  }
46
54
 
47
- if (!file_close(&file)){
55
+ if (!file_close(&file)) {
48
56
  buffer_dispose(&reading_buffer);
49
57
  return 0;
50
58
  }
@@ -54,30 +62,36 @@ int aggregate_files(struct hashmap *map, VALUE list_of_files){
54
62
  return 1;
55
63
  }
56
64
 
57
- VALUE method_to_metrics(VALUE UNUSED(self), VALUE file_list){
65
+ VALUE method_to_metrics(VALUE UNUSED(self), VALUE file_list) {
58
66
  struct hashmap map;
59
67
  hashmap_setup(&map);
60
68
 
61
- if (!aggregate_files(&map, file_list)){ // all entries in map are now copies that need to be disposed
69
+ if (!aggregate_files(&map, file_list)) { // all entries in map are now copies that need to be disposed
62
70
  hashmap_destroy(&map);
63
71
  raise_last_exception();
64
72
  return Qnil;
65
73
  }
66
74
 
67
- entry_struct **sorted_entries;
75
+ entry_t **sorted_entries;
68
76
 
69
- if (!sort_map_entries(&map, &sorted_entries)){
70
- entries_destroy(&map);
77
+ if (!sort_map_entries(&map, &sorted_entries)) {
71
78
  hashmap_destroy(&map);
72
79
 
73
80
  raise_last_exception();
74
81
  return Qnil;
75
82
  }
76
83
 
77
- VALUE rv = entries_to_string(sorted_entries, hashmap_size(&map));
84
+ VALUE rv = rb_str_new("", 0);
85
+ if (!entries_to_string(rv, sorted_entries, hashmap_size(&map))) {
86
+ free(sorted_entries);
87
+ hashmap_destroy(&map);
88
+
89
+ raise_last_exception();
90
+ return Qnil;
91
+ }
78
92
 
93
+ RB_GC_GUARD(file_list); // ensure file list is not GCed before this point
79
94
  free(sorted_entries);
80
- entries_destroy(&map);
81
95
  hashmap_destroy(&map);
82
96
  return rv;
83
97
  }
@@ -90,11 +104,22 @@ void Init_fast_mmaped_file() {
90
104
  sym_pid = rb_intern("pid");
91
105
  sym_samples = rb_intern("samples");
92
106
 
93
- MMAPED_FILE = rb_define_module("FastMmapedFile");
107
+ prom_eParsingError = rb_define_class("PrometheusParsingError", rb_eRuntimeError);
108
+
109
+ MMAPED_FILE = rb_define_class("FastMmapedFile", rb_cObject);
110
+ rb_define_const(MMAPED_FILE, "MAP_SHARED", INT2FIX(MAP_SHARED));
111
+
94
112
  rb_define_singleton_method(MMAPED_FILE, "to_metrics", method_to_metrics, 1);
95
113
 
96
- rb_define_method(MMAPED_FILE, "get_double", method_get_double, 1);
114
+ rb_define_alloc_func(MMAPED_FILE, mm_s_alloc);
115
+ rb_define_singleton_method(MMAPED_FILE, "new", mm_s_new, -1);
116
+ rb_define_method(MMAPED_FILE, "initialize", mm_init, 1);
117
+ rb_define_method(MMAPED_FILE, "slice", mm_aref_m, -1);
118
+ rb_define_method(MMAPED_FILE, "sync", mm_msync, -1);
119
+ rb_define_method(MMAPED_FILE, "munmap", mm_unmap, 0);
120
+
97
121
  rb_define_method(MMAPED_FILE, "used", method_load_used, 0);
98
122
  rb_define_method(MMAPED_FILE, "used=", method_save_used, 1);
99
- rb_define_method(MMAPED_FILE, "add_entry", method_add_entry, 3);
123
+ rb_define_method(MMAPED_FILE, "fetch_entry", method_fetch_entry, 3);
124
+ rb_define_method(MMAPED_FILE, "upsert_entry", method_upsert_entry, 3);
100
125
  }
@@ -1,67 +1,38 @@
1
1
  #include <hashmap.h>
2
- #include <file_format.h>
3
- #include <globals.h>
4
- #include <utils.h>
5
2
  #include <jsmn.h>
6
- #include "file_parsing.h"
3
+ #include <ruby.h>
7
4
 
8
- HASHMAP_FUNCS_CREATE(entry, const entry_struct, entry_struct)
5
+ #include "file_format.h"
6
+ #include "file_parsing.h"
7
+ #include "globals.h"
8
+ #include "utils.h"
9
9
 
10
- typedef int (*compare_fn) (const void *a, const void *b);
10
+ HASHMAP_FUNCS_CREATE(entry, const entry_t, entry_t)
11
11
 
12
- size_t hashmap_hash_entry(const entry_struct *entry){
13
- size_t hash = 0;
12
+ typedef int (*compare_fn)(const void *a, const void *b);
14
13
 
15
- for (size_t i = 0; i < entry->json_size; i++) {
16
- hash += *(const char *)(entry->json + i);
17
- hash += (hash << 10);
18
- hash ^= (hash >> 6);
19
- }
20
- hash += (hash << 3);
21
- hash ^= (hash >> 11);
22
- hash += (hash << 15);
23
- return hash;
24
- }
14
+ static size_t hashmap_hash_entry(const entry_t *entry) { return hashmap_hash_string(entry->json); }
25
15
 
26
- int hashmap_compare_entry(const entry_struct *a, const entry_struct *b)
27
- {
28
- if (a->json_size != b->json_size){
16
+ static int hashmap_compare_entry(const entry_t *a, const entry_t *b) {
17
+ if (a->json_size != b->json_size) {
29
18
  return -1;
30
19
  }
31
20
 
32
- if (is_pid_significant(a) && (rb_str_equal(a->pid, b->pid) == Qfalse)){ //OPTIONAL TODO: optimize rb out
21
+ if (is_pid_significant(a) && (rb_str_equal(a->pid, b->pid) == Qfalse)) {
33
22
  return -1;
34
23
  }
35
24
 
36
- return strncmp(a->json, b->json, a->json_size);
25
+ return strncmp(a->json, b->json, a->json_size);
37
26
  }
38
27
 
39
- entry_struct *copy_entry(const entry_struct *entry){
40
- entry_struct *copied = (entry_struct *)malloc(sizeof(entry_struct));
41
- if (copied == NULL) {
42
- return NULL;
43
- }
44
- memcpy(copied, entry, sizeof(entry_struct));
45
-
46
- copied->json = malloc(entry->json_size);
47
- if (copied->json == NULL){
48
- free(copied);
49
- return NULL;
50
- }
51
-
52
- memcpy(copied->json, entry->json, entry->json_size);
53
-
54
- return copied;
55
- }
56
-
57
- void entry_free(entry_struct *entry){
28
+ static void entry_free(entry_t *entry) {
58
29
  free(entry->json);
59
30
  free(entry);
60
31
  }
61
32
 
62
- void merge_entry(entry_struct *found, const entry_struct *entry){
63
- if (entry->type == sym_gauge){
64
- if (entry->multiprocess_mode == sym_min){
33
+ static void merge_entry(entry_t *found, const entry_t *entry) {
34
+ if (entry->type == sym_gauge) {
35
+ if (entry->multiprocess_mode == sym_min) {
65
36
  found->value = min(found->value, entry->value);
66
37
  } else if (entry->multiprocess_mode == sym_max) {
67
38
  found->value = max(found->value, entry->value);
@@ -75,60 +46,72 @@ void merge_entry(entry_struct *found, const entry_struct *entry){
75
46
  }
76
47
  }
77
48
 
78
- int process_entry(struct hashmap *map, const entry_struct *entry){
79
- entry_struct *found = entry_hashmap_get(map, entry);
80
- if (found){
49
+ void merge_or_store(struct hashmap *map, entry_t *entry) {
50
+ entry_t *found = entry_hashmap_get(map, entry);
51
+ if (found) {
81
52
  merge_entry(found, entry);
53
+ entry_free(entry);
82
54
  } else {
83
- entry_struct *copy = copy_entry(entry);
84
- if (copy == NULL) {
85
- save_exception(rb_eNoMemError, "Failed copying metrics entry");
86
- return 0;
87
- }
88
- entry_hashmap_put(map, copy, copy); // use the hashmap like hashset actually
55
+ entry_hashmap_put(map, entry, entry); // use the hashmap like hashset actually
89
56
  }
90
- return 1;
91
57
  }
92
58
 
93
- inline entry_struct entry_new(char* json, size_t json_size, double value, uint32_t pid){
94
- return (entry_struct) { .json = json, .json_size = json_size, .pid = pid, .value = value, .name_len = 0 };
59
+ inline entry_t *entry_new(buffer_t *source, uint32_t pos, uint32_t encoded_len, file_t *file_info) {
60
+ entry_t *entry = calloc(1, sizeof(entry_t));
61
+ if (entry == NULL) {
62
+ return NULL;
63
+ }
64
+
65
+ entry->json = malloc(encoded_len + 1);
66
+ if (entry->json == NULL) {
67
+ free(entry);
68
+ return NULL;
69
+ }
70
+
71
+ memcpy(entry->json, source->buffer + pos, encoded_len);
72
+ entry->json[encoded_len] = '\0';
73
+ entry->json_size = encoded_len;
74
+
75
+ entry->pid = file_info->pid;
76
+ entry->multiprocess_mode = file_info->multiprocess_mode;
77
+ entry->type = file_info->type;
78
+
79
+ char *value_ptr = source->buffer + pos + encoded_len + padding_length(encoded_len);
80
+ memcpy(&(entry->value), value_ptr, sizeof(double));
81
+
82
+ return entry;
95
83
  }
96
84
 
97
- void add_parsed_name(entry_struct *entry){
85
+ static int add_parsed_name(entry_t *entry) {
98
86
  jsmn_parser parser;
99
87
  jsmn_init(&parser);
100
88
 
101
- jsmntok_t t[2];
102
- int r = jsmn_parse(&parser, entry->json, entry->json_size, t, 2);
89
+ jsmntok_t tokens[2];
90
+ memset(&tokens, 0, sizeof(tokens));
103
91
 
104
- if (r < 1) {
105
- //TODO: better handle this case
106
- }
92
+ jsmn_parse(&parser, entry->json, entry->json_size, tokens, 2);
93
+ jsmntok_t *name_token = &tokens[1];
107
94
 
108
- entry->name = entry->json + t[1].start;
109
- entry->name_len = t[1].end - t[1].start;
95
+ if (name_token->start < name_token->end && name_token->start > 0) {
96
+ entry->name = entry->json + name_token->start;
97
+ entry->name_len = name_token->end - name_token->start;
98
+ return 1;
99
+ }
100
+ return 0;
110
101
  }
111
102
 
112
- int entry_lexical_comparator(const entry_struct **a, const entry_struct **b){
103
+ static int entry_lexical_comparator(const entry_t **a, const entry_t **b) {
113
104
  size_t min_length = min((*a)->json_size, (*b)->json_size);
114
105
  return strncmp((*a)->json, (*b)->json, min_length);
115
106
  }
116
107
 
117
- // public functions
118
-
119
- void hashmap_setup(struct hashmap *map){
120
- hashmap_init(map, (size_t (*)(const void *))hashmap_hash_entry, (int (*)(const void *, const void *))hashmap_compare_entry, 1000);
121
- }
122
-
123
- void entries_destroy(struct hashmap *map){
124
- struct hashmap_iter *iter;
125
- for (iter = hashmap_iter(map); iter; iter = hashmap_iter_next(map, iter)) {
126
- entry_struct *entry = (entry_struct *)entry_hashmap_iter_get_key(iter);
127
- entry_free(entry);
128
- }
108
+ void hashmap_setup(struct hashmap *map) {
109
+ hashmap_init(map, (size_t(*)(const void *))hashmap_hash_entry,
110
+ (int (*)(const void *, const void *))hashmap_compare_entry, 1000);
111
+ hashmap_set_key_alloc_funcs(map, NULL, (void (*)(void *))entry_free);
129
112
  }
130
113
 
131
- int process_buffer(file_t *file_info, buffer_t *source, struct hashmap *map){
114
+ int process_buffer(file_t *file_info, buffer_t *source, struct hashmap *map) {
132
115
  if (source->size < START_POSITION) {
133
116
  // nothing to read
134
117
  return 1;
@@ -136,10 +119,9 @@ int process_buffer(file_t *file_info, buffer_t *source, struct hashmap *map){
136
119
  uint32_t used;
137
120
  memcpy(&used, source->buffer, sizeof(uint32_t));
138
121
 
139
- if (used > source->size){
140
- //TODO: add custom parsing error
141
- save_exception(rb_eRuntimeError, "source file %s corrupted, used %u > file size %u",
142
- file_info->path, used, source->size);
122
+ if (used > source->size) {
123
+ save_exception(prom_eParsingError, "source file %s corrupted, used %u > file size %u", file_info->path, used,
124
+ source->size);
143
125
  return 0;
144
126
  }
145
127
 
@@ -152,62 +134,55 @@ int process_buffer(file_t *file_info, buffer_t *source, struct hashmap *map){
152
134
  uint32_t value_offset = encoded_len + padding_length(encoded_len);
153
135
 
154
136
  if (pos + value_offset + sizeof(double) > used) {
155
- //TODO: add custom parsing error
156
- save_exception(rb_eRuntimeError, "source file %s corrupted, used %u < stored data length %u",
157
- file_info->path, used, pos + value_offset + sizeof(double));
137
+ save_exception(prom_eParsingError, "source file %s corrupted, used %u < stored data length %u",
138
+ file_info->path, used, pos + value_offset + sizeof(double));
158
139
  return 0;
159
140
  }
160
141
 
161
- entry_struct entry = entry_new(source->buffer + pos, encoded_len, 0, 0.0);
162
-
163
- entry.multiprocess_mode = file_info->multiprocess_mode;
164
- entry.pid = file_info->pid;
165
- entry.type = file_info->type;
166
-
167
- memcpy(&entry.value, entry.json + value_offset, sizeof(double));
168
-
169
- if (!process_entry(map, &entry)) {
170
- entries_destroy(map);
142
+ entry_t *entry = entry_new(source, pos, encoded_len, file_info);
143
+ if (entry == NULL) {
144
+ save_exception(rb_eNoMemError, "Failed creating metrics entry");
171
145
  return 0;
172
146
  }
173
147
 
148
+ merge_or_store(map, entry);
149
+
174
150
  pos += value_offset + sizeof(double);
175
151
  }
176
152
  return 1;
177
153
  }
178
154
 
179
- int sort_map_entries(const struct hashmap *map, entry_struct ***sorted_entries){
155
+ int sort_map_entries(const struct hashmap *map, entry_t ***sorted_entries) {
180
156
  size_t num = hashmap_size(map);
181
157
 
182
- size_t list_size = num * sizeof(entry_struct *);
183
- entry_struct **list = malloc(list_size);
158
+ entry_t **list = calloc(num, sizeof(entry_t *));
184
159
 
185
- if (list == NULL){
186
- save_exception(rb_eNoMemError, "Couldn't allocate %zu memory", list_size);
160
+ if (list == NULL) {
161
+ save_exception(rb_eNoMemError, "Couldn't allocate for %zu memory", num * sizeof(entry_t *));
187
162
  return 0;
188
163
  }
189
164
 
190
165
  size_t cnt = 0;
191
166
  struct hashmap_iter *iter;
192
167
  for (iter = hashmap_iter(map); iter; iter = hashmap_iter_next(map, iter)) {
193
- entry_struct *entry = (entry_struct *)entry_hashmap_iter_get_key(iter);
194
- add_parsed_name(entry);
195
-
196
- list[cnt] = entry;
197
- cnt++;
168
+ entry_t *entry = (entry_t *)entry_hashmap_iter_get_key(iter);
169
+ if (add_parsed_name(entry)) {
170
+ list[cnt] = entry;
171
+ cnt++;
172
+ }
198
173
  }
199
- if (cnt != num){
174
+ if (cnt != num) {
200
175
  save_exception(rb_eRuntimeError, "Processed entries %zu != map entries %zu", cnt, num);
201
176
  free(list);
202
177
  return 0;
203
178
  }
204
179
 
205
- qsort(list, cnt, sizeof(entry_struct *), (compare_fn)&entry_lexical_comparator);
180
+ qsort(list, cnt, sizeof(entry_t *), (compare_fn)&entry_lexical_comparator);
206
181
  *sorted_entries = list;
207
182
  return 1;
208
183
  }
209
184
 
210
- int is_pid_significant(const entry_struct *e){
185
+ int is_pid_significant(const entry_t *e) {
211
186
  ID mp = e->multiprocess_mode;
212
187
  return e->type == sym_gauge && !(mp == sym_min || mp == sym_max || mp == sym_livesum);
213
188
  }