statsrb 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/ext/statsrb/statsrb.c +64 -11
  2. data/test/test_statsrb.rb +89 -0
  3. metadata +10 -6
@@ -3,6 +3,52 @@
3
3
  #include <string.h>
4
4
  #include <stdlib.h>
5
5
 
6
+ /**
7
+ * Retrieves internal data based on specified filters.
8
+ * @param namespace [String]
9
+ * @param limit [Number]
10
+ * @param start_time [Number]
11
+ * @param end_time [Number]
12
+ * @return [Array] An array of data hashes.
13
+ */
14
+ static VALUE statsrb_get(VALUE self, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
15
+ VALUE statsrb_data = rb_iv_get(self, "@data");
16
+ VALUE statsrb_event = rb_hash_new();
17
+ int data_length = RARRAY_LEN(statsrb_data);
18
+ int i = 0;
19
+ int count = 0;
20
+ int tmp_ts;
21
+
22
+ VALUE filtered_data = rb_ary_new();
23
+ VALUE tmp_ns;
24
+
25
+ // @data hash key symbols.
26
+ VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
27
+ VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
28
+ VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
29
+
30
+ // Convert into an int that ruby understands.
31
+ int limit = NUM2INT(query_limit);
32
+ int qstart = NUM2INT(query_start);
33
+ int qend = NUM2INT(query_end);
34
+
35
+ for (i = 0; i < data_length; i++) {
36
+ tmp_ts = NUM2INT(rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ts));
37
+ tmp_ns = rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns);
38
+ if (rb_str_equal(query_ns, tmp_ns)
39
+ && (qstart == 0 || tmp_ts >= qstart)
40
+ && (qend == 0 || tmp_ts <= qend)) {
41
+ rb_hash_aset(statsrb_event, statsrb_key_ts, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ts));
42
+ rb_hash_aset(statsrb_event, statsrb_key_ns, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns));
43
+ rb_hash_aset(statsrb_event, statsrb_key_v, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_v));
44
+ rb_ary_push(filtered_data, statsrb_event);
45
+ count++;
46
+ }
47
+ }
48
+
49
+ return filtered_data;
50
+ }
51
+
6
52
  /**
7
53
  * Locates data from a specified file and loads into @data.
8
54
  * @param filepath [String]
@@ -12,7 +58,7 @@
12
58
  * @param end_time [Number]
13
59
  * @return [Statsrb] A reference to the object.
14
60
  */
15
- static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
61
+ static VALUE statsrb_read(VALUE self, VALUE logfile, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
16
62
  FILE * file;
17
63
  int line_size = 256;
18
64
  char *line = (char *) malloc(line_size);
@@ -39,13 +85,13 @@ static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE quer
39
85
  file = fopen(filepath, "r");
40
86
  if (file == NULL) {
41
87
  fprintf(stderr, "File error: could not open file %s for reading.", filepath);
42
- return;
88
+ return self;
43
89
  }
44
90
 
45
91
  int count = 0;
46
92
 
47
93
  while (NULL != fgets(line, line_size, file) && count < limit) {
48
- // strstr doesn't work with newline chars.
94
+ // strstr doesn't work with newline chars.
49
95
  size_t len = strlen(line) - 1;
50
96
  if (line[len] == '\n');
51
97
  line[len] = '\0';
@@ -66,7 +112,7 @@ static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE quer
66
112
  VALUE statsrb_str_ns = rb_str_new2(strtok(NULL, "\t"));
67
113
  //strtok(NULL, "\t");
68
114
  int statsrb_v = atoi(strtok(NULL, "\0"));
69
-
115
+
70
116
  // @TODO this should really query the namespace exactly instead of just relying on strstr.
71
117
  //if (rb_str_cmp(query_ns, statsrb_str_empty) == 0 || rb_str_cmp(query_ns, statsrb_str_ns) == 0) {
72
118
  if (statsrb_ts && (statsrb_v || statsrb_v == 0)) {
@@ -155,7 +201,7 @@ static VALUE statsrb_write(VALUE self, VALUE logfile, VALUE mode) {
155
201
  int line_size = 256;
156
202
  int tmp_ts, tmp_v;
157
203
  const char *tmp_ns = (char *) malloc(line_size);
158
-
204
+
159
205
  // @data hash key symbols.
160
206
  VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
161
207
  VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
@@ -164,7 +210,7 @@ static VALUE statsrb_write(VALUE self, VALUE logfile, VALUE mode) {
164
210
  file = fopen(filepath, filemode);
165
211
  if (file==NULL) {
166
212
  fprintf(stderr, "File error: could not open file %s mode %s.", filepath, filemode);
167
- return;
213
+ return self;
168
214
  }
169
215
 
170
216
  // Iterate through the data array, writing the data as we go.
@@ -222,7 +268,12 @@ static VALUE statsrb_split_write(VALUE self, VALUE logdir, VALUE mode) {
222
268
  //fputs (RSTRING_PTR(rb_obj_as_string(INT2NUM(RARRAY_LEN(tmp_data)))),stderr);
223
269
  rb_iv_set(tmp, "@data", tmp_data);
224
270
 
225
- // @todo, throw an exception if no trailing slash... or add one
271
+ // If there is no trailing slash on the log dir, add one.
272
+ const char *filepath = RSTRING_PTR(logdir);
273
+ size_t len = strlen(filepath);
274
+ if (filepath[len - 1] != '/') {
275
+ logdir = rb_str_plus(logdir, rb_str_new2("/"));
276
+ }
226
277
  statsrb_write(tmp, rb_str_plus(logdir, rb_ary_entry(ns_list, i)), mode);
227
278
  }
228
279
 
@@ -393,7 +444,7 @@ static VALUE statsrb_rack_call(VALUE self, VALUE env) {
393
444
  VALUE tmp = rb_obj_dup(self);
394
445
  VALUE tmp_data = rb_ary_new();
395
446
  rb_iv_set(tmp, "@data", tmp_data);
396
- statsrb_query(tmp, rb_str_plus(rb_iv_get(self, "@split_file_dir"), statsrb_ns), statsrb_ns, INT2NUM(query_limit), INT2NUM(query_start), INT2NUM(query_end));
447
+ statsrb_read(tmp, rb_str_plus(rb_iv_get(self, "@split_file_dir"), statsrb_ns), statsrb_ns, INT2NUM(query_limit), INT2NUM(query_start), INT2NUM(query_end));
397
448
  statsrb_sort(tmp);
398
449
 
399
450
  int i, data_length = RARRAY_LEN(tmp_data);
@@ -408,7 +459,7 @@ static VALUE statsrb_rack_call(VALUE self, VALUE env) {
408
459
  rb_ary_push(body, rb_str_new(",", 1));
409
460
  }
410
461
  rb_ary_push(body, rb_str_new("\n", 1));
411
- }
462
+ }
412
463
  rb_ary_resize(tmp_data, 0);
413
464
  }
414
465
  rb_ary_push(body, rb_str_new("]}", 2));
@@ -454,7 +505,7 @@ static VALUE statsrb_push(VALUE self, VALUE timestamp, VALUE namespace, VALUE va
454
505
 
455
506
  return self;
456
507
  }
457
-
508
+
458
509
  /**
459
510
  * Class constructor, sets up an instance variable.
460
511
  */
@@ -485,7 +536,9 @@ void Init_statsrb(void) {
485
536
 
486
537
  // Instance methods and properties.
487
538
  rb_define_method(klass, "initialize", statsrb_constructor, 0);
488
- rb_define_method(klass, "query", statsrb_query, 5);
539
+ rb_define_method(klass, "query", statsrb_read, 5);
540
+ rb_define_method(klass, "read", statsrb_read, 5);
541
+ rb_define_method(klass, "get", statsrb_get, 4);
489
542
  rb_define_method(klass, "sort", statsrb_sort, 0);
490
543
  rb_define_method(klass, "write", statsrb_write, 2);
491
544
  rb_define_method(klass, "split_write", statsrb_split_write, 2);
@@ -0,0 +1,89 @@
1
+ require 'minitest/autorun'
2
+ require 'statsrb'
3
+
4
+ class TestStatsrb < MiniTest::Test
5
+
6
+ attr_accessor :tmpfile
7
+
8
+ def setup
9
+ @s = Statsrb.new
10
+ @tmpfile = "/tmp/test.statsrb"
11
+ end
12
+
13
+ def teardown
14
+ File.delete @tmpfile unless !File.exists? @tmpfile
15
+ end
16
+
17
+ # Provides test data.
18
+ def get_data
19
+ [[123, "test1", 33],
20
+ [321, "test1", 34],
21
+ [222, "test1", 35],
22
+ [111, "test2", 36],
23
+ [432, "test2", 37]]
24
+ end
25
+
26
+ # Stores the data in the current object.
27
+ def push_data
28
+ get_data.each do |value|
29
+ @s.push value[0], value[1], value[2]
30
+ end
31
+ end
32
+
33
+ # Writes the data to a temp file.
34
+ def write_data
35
+ @s.write @tmpfile, "w+"
36
+ end
37
+
38
+ # Tests that the data was indeed pushed.
39
+ def test_push_data
40
+ push_data
41
+ assert_equal @s.data.length, get_data.length
42
+ end
43
+
44
+ # Tests that we can filter the in-memory data.
45
+ def test_get_data
46
+ push_data
47
+ t = @s.get "test2", 100, 0, 0
48
+ assert_equal(t.length, 2);
49
+ end
50
+
51
+ # Tests that we can sort the data.
52
+ def test_sort_data
53
+ current = 0
54
+ push_data
55
+ @s.sort
56
+ @s.data.each do |value|
57
+ assert value[:ts] > current
58
+ current = value[:ts]
59
+ end
60
+ end
61
+
62
+ # Tests that we can write the data to a file.
63
+ def test_write_data
64
+ push_data
65
+ write_data
66
+ data = get_data
67
+ file_data = File.read(@tmpfile).split "\n"
68
+
69
+ assert_equal file_data.length, data.length
70
+ count = 0
71
+ file_data.each do |value|
72
+ parts = value.split "\t"
73
+ assert_equal parts[0], data[count][0].to_s
74
+ assert_equal parts[1], data[count][1].to_s
75
+ assert_equal parts[2], data[count][2].to_s
76
+ count = count + 1
77
+ end
78
+ end
79
+
80
+ # Tests that we can read data from a file.
81
+ def test_read_data
82
+ push_data
83
+ write_data
84
+ @s.read @tmpfile, "test1", 100, 0, 0
85
+ assert_equal @s.data.length, 3
86
+ @s.read @tmpfile, "test2", 100, 0, 0
87
+ assert_equal @s.data.length, 2
88
+ end
89
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statsrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,8 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2013-06-08 00:00:00.000000000 Z
13
13
  dependencies: []
14
- description: A ruby stats repository.
14
+ description: A Ruby time series stats repository using flat file storage, providing
15
+ a Ruby API as well as a Rack compatible REST API.
15
16
  email: email@kevinhankens.com
16
17
  executables: []
17
18
  extensions:
@@ -21,9 +22,11 @@ files:
21
22
  - lib/statsrb.rb
22
23
  - ext/statsrb/statsrb.c
23
24
  - ext/statsrb/extconf.rb
25
+ - test/test_statsrb.rb
24
26
  homepage: https://github.com/kevinhankens/statsrb
25
- licenses: []
26
- post_install_message:
27
+ licenses:
28
+ - ! "MIT\t"
29
+ post_install_message: ! 'Please view documentation at: https://github.com/kevinhankens/statsrb'
27
30
  rdoc_options: []
28
31
  require_paths:
29
32
  - lib
@@ -44,6 +47,7 @@ rubyforge_project:
44
47
  rubygems_version: 1.8.25
45
48
  signing_key:
46
49
  specification_version: 3
47
- summary: Statsrb
48
- test_files: []
50
+ summary: A Ruby time series stats repository.
51
+ test_files:
52
+ - test/test_statsrb.rb
49
53
  has_rdoc: