rroonga 0.9.4-x86-mingw32 → 0.9.5-x86-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. data/NEWS.ja.rdoc +29 -0
  2. data/NEWS.rdoc +29 -0
  3. data/Rakefile +6 -6
  4. data/ext/groonga/rb-grn-array.c +1 -1
  5. data/ext/groonga/rb-grn-context.c +15 -28
  6. data/ext/groonga/rb-grn-exception.c +46 -1
  7. data/ext/groonga/rb-grn-expression.c +22 -13
  8. data/ext/groonga/rb-grn-fix-size-column.c +2 -8
  9. data/ext/groonga/rb-grn-hash.c +8 -1
  10. data/ext/groonga/rb-grn-object.c +1 -1
  11. data/ext/groonga/rb-grn-patricia-trie.c +23 -1
  12. data/ext/groonga/rb-grn-table-key-support.c +22 -0
  13. data/ext/groonga/rb-grn-table.c +37 -5
  14. data/ext/groonga/rb-grn-utils.c +20 -2
  15. data/ext/groonga/rb-grn.h +1 -1
  16. data/ext/groonga/rb-groonga.c +76 -38
  17. data/extconf.rb +17 -1
  18. data/html/developer.html +32 -7
  19. data/html/footer.html.erb +5 -0
  20. data/html/heading-mark.svg +393 -0
  21. data/html/index.html +33 -3
  22. data/lib/1.8/groonga.so +0 -0
  23. data/lib/1.9/groonga.so +0 -0
  24. data/lib/groonga.rb +3 -7
  25. data/lib/groonga/context.rb +2 -13
  26. data/lib/groonga/expression-builder.rb +273 -67
  27. data/lib/groonga/pagination.rb +143 -0
  28. data/lib/groonga/record.rb +2 -0
  29. data/lib/groonga/schema.rb +140 -29
  30. data/pkg/rroonga-0.9.5/NEWS.ja.rdoc +156 -0
  31. data/pkg/rroonga-0.9.5/NEWS.rdoc +158 -0
  32. data/pkg/rroonga-0.9.5/README.ja.rdoc +65 -0
  33. data/pkg/rroonga-0.9.5/README.rdoc +66 -0
  34. data/pkg/rroonga-0.9.5/text/TUTORIAL.ja.rdoc +394 -0
  35. data/pkg/rroonga-0.9.5/text/expression.rdoc +285 -0
  36. data/rroonga-build.rb +2 -2
  37. data/test-unit/Rakefile +40 -0
  38. data/test-unit/TODO +5 -0
  39. data/test-unit/bin/testrb +5 -0
  40. data/test-unit/html/classic.html +15 -0
  41. data/test-unit/html/index.html +25 -0
  42. data/test-unit/html/index.html.ja +27 -0
  43. data/test-unit/lib/test/unit.rb +323 -0
  44. data/test-unit/lib/test/unit/assertionfailederror.rb +25 -0
  45. data/test-unit/lib/test/unit/assertions.rb +1230 -0
  46. data/test-unit/lib/test/unit/attribute.rb +125 -0
  47. data/test-unit/lib/test/unit/autorunner.rb +360 -0
  48. data/test-unit/lib/test/unit/collector.rb +36 -0
  49. data/test-unit/lib/test/unit/collector/descendant.rb +23 -0
  50. data/test-unit/lib/test/unit/collector/dir.rb +108 -0
  51. data/test-unit/lib/test/unit/collector/load.rb +144 -0
  52. data/test-unit/lib/test/unit/collector/objectspace.rb +34 -0
  53. data/test-unit/lib/test/unit/color-scheme.rb +102 -0
  54. data/test-unit/lib/test/unit/color.rb +96 -0
  55. data/test-unit/lib/test/unit/diff.rb +724 -0
  56. data/test-unit/lib/test/unit/error.rb +130 -0
  57. data/test-unit/lib/test/unit/exceptionhandler.rb +39 -0
  58. data/test-unit/lib/test/unit/failure.rb +136 -0
  59. data/test-unit/lib/test/unit/fixture.rb +176 -0
  60. data/test-unit/lib/test/unit/notification.rb +129 -0
  61. data/test-unit/lib/test/unit/omission.rb +191 -0
  62. data/test-unit/lib/test/unit/pending.rb +150 -0
  63. data/test-unit/lib/test/unit/priority.rb +180 -0
  64. data/test-unit/lib/test/unit/runner/console.rb +52 -0
  65. data/test-unit/lib/test/unit/runner/emacs.rb +8 -0
  66. data/test-unit/lib/test/unit/runner/tap.rb +8 -0
  67. data/test-unit/lib/test/unit/testcase.rb +476 -0
  68. data/test-unit/lib/test/unit/testresult.rb +89 -0
  69. data/test-unit/lib/test/unit/testsuite.rb +110 -0
  70. data/test-unit/lib/test/unit/ui/console/outputlevel.rb +14 -0
  71. data/test-unit/lib/test/unit/ui/console/testrunner.rb +466 -0
  72. data/test-unit/lib/test/unit/ui/emacs/testrunner.rb +63 -0
  73. data/test-unit/lib/test/unit/ui/tap/testrunner.rb +92 -0
  74. data/test-unit/lib/test/unit/ui/testrunner.rb +28 -0
  75. data/test-unit/lib/test/unit/ui/testrunnermediator.rb +77 -0
  76. data/test-unit/lib/test/unit/ui/testrunnerutilities.rb +41 -0
  77. data/test-unit/lib/test/unit/util/backtracefilter.rb +41 -0
  78. data/test-unit/lib/test/unit/util/method-owner-finder.rb +28 -0
  79. data/test-unit/lib/test/unit/util/observable.rb +90 -0
  80. data/test-unit/lib/test/unit/util/procwrapper.rb +48 -0
  81. data/test-unit/lib/test/unit/version.rb +7 -0
  82. data/test-unit/sample/adder.rb +13 -0
  83. data/test-unit/sample/subtracter.rb +12 -0
  84. data/test-unit/sample/test_adder.rb +20 -0
  85. data/test-unit/sample/test_subtracter.rb +20 -0
  86. data/test-unit/sample/test_user.rb +23 -0
  87. data/test-unit/test/collector/test-descendant.rb +133 -0
  88. data/test-unit/test/collector/test-load.rb +442 -0
  89. data/test-unit/test/collector/test_dir.rb +406 -0
  90. data/test-unit/test/collector/test_objectspace.rb +100 -0
  91. data/test-unit/test/run-test.rb +15 -0
  92. data/test-unit/test/test-attribute.rb +86 -0
  93. data/test-unit/test/test-color-scheme.rb +67 -0
  94. data/test-unit/test/test-color.rb +47 -0
  95. data/test-unit/test/test-diff.rb +518 -0
  96. data/test-unit/test/test-emacs-runner.rb +60 -0
  97. data/test-unit/test/test-fixture.rb +287 -0
  98. data/test-unit/test/test-notification.rb +33 -0
  99. data/test-unit/test/test-omission.rb +81 -0
  100. data/test-unit/test/test-pending.rb +70 -0
  101. data/test-unit/test/test-priority.rb +119 -0
  102. data/test-unit/test/test-testcase.rb +544 -0
  103. data/test-unit/test/test_assertions.rb +1151 -0
  104. data/test-unit/test/test_error.rb +26 -0
  105. data/test-unit/test/test_failure.rb +33 -0
  106. data/test-unit/test/test_testresult.rb +113 -0
  107. data/test-unit/test/test_testsuite.rb +129 -0
  108. data/test-unit/test/testunit-test-util.rb +14 -0
  109. data/test-unit/test/ui/test_testrunmediator.rb +20 -0
  110. data/test-unit/test/util/test-method-owner-finder.rb +38 -0
  111. data/test-unit/test/util/test_backtracefilter.rb +41 -0
  112. data/test-unit/test/util/test_observable.rb +102 -0
  113. data/test-unit/test/util/test_procwrapper.rb +36 -0
  114. data/test/groonga-test-utils.rb +3 -2
  115. data/test/run-test.rb +14 -2
  116. data/test/test-column.rb +7 -7
  117. data/test/test-context-select.rb +34 -11
  118. data/test/test-exception.rb +3 -0
  119. data/test/test-expression-builder.rb +11 -0
  120. data/test/test-expression.rb +3 -6
  121. data/test/test-gqtp.rb +3 -5
  122. data/test/test-pagination.rb +249 -0
  123. data/test/test-record.rb +36 -8
  124. data/test/test-remote.rb +11 -4
  125. data/test/test-schema-create-table.rb +251 -0
  126. data/test/test-schema.rb +4 -24
  127. data/test/test-table-offset-and-limit.rb +3 -5
  128. data/test/test-table-select-mecab.rb +80 -0
  129. data/test/test-table-select-weight.rb +104 -0
  130. data/test/test-table.rb +22 -4
  131. data/test/test-version.rb +1 -1
  132. data/text/TUTORIAL.ja.rdoc +2 -0
  133. data/text/expression.rdoc +1 -0
  134. data/vendor/local/bin/grntest.exe +0 -0
  135. data/vendor/local/bin/groonga.exe +0 -0
  136. data/vendor/local/bin/libgroonga-0.dll +0 -0
  137. data/vendor/local/include/{groonga.h → groonga/groonga.h} +93 -32
  138. data/vendor/local/lib/groonga/modules/functions/cast.dll +0 -0
  139. data/vendor/local/lib/groonga/modules/functions/cast.la +41 -0
  140. data/vendor/local/lib/pkgconfig/groonga.pc +12 -0
  141. data/vendor/local/share/groonga/admin_html/css/admin.css +104 -0
  142. data/vendor/local/share/groonga/admin_html/css/ui-lightness/jquery-ui-1.8.1.custom.css +486 -0
  143. data/vendor/local/share/groonga/admin_html/index.html +1355 -0
  144. data/vendor/local/share/groonga/admin_html/js/jquery-1.4.2.min.js +154 -0
  145. data/vendor/local/share/groonga/admin_html/js/jquery-ui-1.8.1.custom.min.js +756 -0
  146. data/vendor/local/share/groonga/munin/plugins/groonga_cpu_load +47 -0
  147. data/vendor/local/share/groonga/munin/plugins/groonga_cpu_time +57 -0
  148. data/vendor/local/share/groonga/munin/plugins/groonga_disk +162 -0
  149. data/vendor/local/share/groonga/munin/plugins/groonga_memory +51 -0
  150. data/vendor/local/share/groonga/munin/plugins/groonga_n_records +110 -0
  151. data/vendor/local/share/groonga/munin/plugins/groonga_query_performance +133 -0
  152. data/vendor/local/share/groonga/munin/plugins/groonga_status +84 -0
  153. metadata +126 -36
@@ -0,0 +1,47 @@
1
+ #!/bin/sh
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ case "$1" in
7
+ autoconf|detect)
8
+ if [ -z "${pid_file}" ]; then
9
+ echo "no (PID file isn't specified by env.pid_file)"
10
+ exit 1
11
+ elif [ -f "${pid_file}" ]; then
12
+ echo "yes"
13
+ exit 0
14
+ else
15
+ echo "no (PID file doesn't exist: ${pid_file})"
16
+ exit 1
17
+ fi
18
+ ;;
19
+ config)
20
+ if [ -z "${label}" ]; then
21
+ title="groonga: CPU load"
22
+ else
23
+ title="groonga: ${label}: CPU load"
24
+ fi
25
+ cat <<EOF
26
+ graph_title ${title}
27
+ graph_vlabel CPU load (%)
28
+ graph_category groonga
29
+ graph_info groonga CPU load
30
+
31
+ cpu_load.label CPU load
32
+ cpu_load.type GAUGE
33
+ EOF
34
+ exit 0
35
+ ;;
36
+ *)
37
+ esac
38
+
39
+ if [ -z "${pid_file}" ]; then
40
+ echo "PID file isn't specified by env.pid_file"
41
+ exit 1
42
+ fi
43
+
44
+ groonga_pid=$(cat ${pid_file})
45
+ top_for_groonga=$(top -b -n 1 -p ${groonga_pid} | tail -2 | head -1)
46
+ load_in_percent=$(echo ${top_for_groonga} | sed -r -e 's/ +/ /g' | cut -d' ' -f 9)
47
+ echo "cpu_load.value ${load_in_percent}"
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ label = ENV["label"]
7
+ pid_file = ENV["pid_file"]
8
+
9
+ command = ARGV.shift
10
+
11
+ case command
12
+ when "autoconf", "detect"
13
+ if pid_file.nil?
14
+ puts "no (PID file isn't specified by env.pid_file)"
15
+ exit(false)
16
+ elsif File.exist?(pid_file)
17
+ puts "yes"
18
+ exit(true)
19
+ else
20
+ puts "no (PID file doesn't exist: #{pid_file})"
21
+ exit(false)
22
+ end
23
+ when "config"
24
+ if label
25
+ title = "groonga: #{label}: CPU time"
26
+ else
27
+ title = "groonga: CPU time"
28
+ end
29
+ puts <<EOF
30
+ graph_title #{title}
31
+ graph_vlabel CPU time (days)
32
+ graph_category groonga
33
+ graph_info groonga CPU time
34
+
35
+ cpu_time.label CPU time
36
+ cpu_time.type GAUGE
37
+ EOF
38
+ exit(true)
39
+ end
40
+
41
+ groonga_pid = File.read(pid_file).strip
42
+ time = `ps h -o time -p #{groonga_pid}`.chomp
43
+ if /\A(?:(\d+)-)?(\d+):(\d+):(\d+)\z/ =~ time
44
+ day, hours, minutes, seconds, = $1, $2, $3, $4
45
+ day = (day || 0).to_i
46
+ hours = hours.to_i
47
+ minutes = minutes.to_i
48
+ seconds = seconds.to_i
49
+ time_in_seconds = seconds + minutes * 60 + hours * 60 * 60
50
+ day_in_seconds = 60 * 60 * 24
51
+ fraction_in_day = time_in_seconds.to_f / day_in_seconds.to_f
52
+ cpu_time_in_day = day + fraction_in_day
53
+ puts "cpu_time.value #{cpu_time_in_day}"
54
+ else
55
+ puts "invalid time format: <#{time}>"
56
+ exit(false)
57
+ end
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ require 'shellwords'
7
+ require 'json'
8
+ require 'English'
9
+
10
+ label = ENV["label"]
11
+ @groonga = ENV["groonga"] || "groonga"
12
+ @du = ENV["du"] || "du"
13
+ @path = ENV["path"]
14
+
15
+ command = ARGV.shift
16
+
17
+ def parse(success, result)
18
+ if success
19
+ begin
20
+ status, body = JSON.parse(result)
21
+ return_code, start_time, elapsed, error_message = status
22
+ if return_code.zero?
23
+ [success, body]
24
+ else
25
+ [false, error_message]
26
+ end
27
+ rescue JSON::ParserError
28
+ [false, $!.message]
29
+ end
30
+ else
31
+ [success, result]
32
+ end
33
+ end
34
+
35
+ def run(command, *args)
36
+ path = Shellwords.shellescape(@path)
37
+ result = `#{@groonga} #{path} #{command} #{args.join(' ')} 2>&1`
38
+ parse($?.success?, result)
39
+ end
40
+
41
+ def parse_list(header, list)
42
+ list.collect do |item|
43
+ parsed_item = {}
44
+ header.each_with_index do |(name, type), i|
45
+ parsed_item[name] = item[i]
46
+ end
47
+ parsed_item
48
+ end
49
+ end
50
+
51
+ def schema
52
+ tables = []
53
+ success, table_list_body = run("table_list")
54
+ unless success
55
+ puts "error: #{table_list_body}"
56
+ exit(false)
57
+ end
58
+ parse_list(table_list_body[0], table_list_body[1..-1]).each do |table|
59
+ table_name = table["name"]
60
+ table["key"] = "table_#{table_name}"
61
+ success, column_list_body = run("column_list", table_name)
62
+ unless success
63
+ puts "error: #{column_list_body}"
64
+ exit(false)
65
+ end
66
+ table["columns"] = parse_list(column_list_body[0], column_list_body[1..-1])
67
+ table["columns"].each do |column|
68
+ column["key"] = "column_#{table_name}_#{column['name']}"
69
+ column["full_name"] = "#{table_name}.#{column['name']}"
70
+ end
71
+ tables << table
72
+ end
73
+ tables
74
+ end
75
+
76
+ def parse_du_result(result)
77
+ usages = {}
78
+ result.each_line do |line|
79
+ if /\A(\d+)\s+/ =~ line
80
+ usage = $1
81
+ path = $POSTMATCH.strip
82
+ usages[path] = usage.to_i
83
+ end
84
+ end
85
+ usages
86
+ end
87
+
88
+ case command
89
+ when "autoconf", "detect"
90
+ success, body = run("status")
91
+ if success
92
+ puts "yes"
93
+ exit(true)
94
+ else
95
+ puts "no (#{body})"
96
+ exit(false)
97
+ end
98
+ when "config"
99
+ if label.nil?
100
+ title = "groonga: disk usage"
101
+ else
102
+ title = "groonga: #{label}: disk usage"
103
+ end
104
+ puts <<EOF
105
+ graph_title #{title}
106
+ graph_vlabel Bytes
107
+ graph_category groonga
108
+ graph_info disk usage in groonga tables and columns
109
+ graph_args --base 1024
110
+ graph_total Total
111
+
112
+ database.label Database
113
+ database.draw AREA
114
+ EOF
115
+ schema.each do |table|
116
+ table_key = table["key"]
117
+ table_name = table["name"]
118
+ puts <<EOF
119
+
120
+ #{table_key}.label #{table_name}
121
+ #{table_key}.draw STACK
122
+ EOF
123
+ table["columns"].each do |column|
124
+ column_key = column["key"]
125
+ column_name = column["full_name"]
126
+ puts <<EOF
127
+
128
+ #{column_key}.label #{column_name}
129
+ #{column_key}.draw STACK
130
+ EOF
131
+ end
132
+ end
133
+ exit(true)
134
+ end
135
+
136
+ path = Shellwords.shellescape(@path)
137
+ du_result = `#{@du} -B1 #{path}*`
138
+ unless $?.success?
139
+ puts("error: #{du_result}")
140
+ exit(false)
141
+ end
142
+ usages = parse_du_result(du_result)
143
+ usage = usages[@path] || 0
144
+ puts <<EOF
145
+ database.value #{usage}
146
+ EOF
147
+ schema.each do |table|
148
+ table_key = table["key"]
149
+ table_name = table["name"]
150
+ usage = usages[table["path"]] || 0
151
+ puts <<EOF
152
+ #{table_key}.value #{usage}
153
+ EOF
154
+ table["columns"].each do |column|
155
+ column_key = column["key"]
156
+ usage = usages[column["path"]] || 0
157
+ usage += usages["#{column['path']}.c"] || 0
158
+ puts <<EOF
159
+ #{column_key}.value #{usage}
160
+ EOF
161
+ end
162
+ end
@@ -0,0 +1,51 @@
1
+ #!/bin/sh
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ case "$1" in
7
+ autoconf|detect)
8
+ if [ -z "${pid_file}" ]; then
9
+ echo "no (PID file isn't specified by env.pid_file)"
10
+ exit 1
11
+ elif [ -f "${pid_file}" ]; then
12
+ echo "yes"
13
+ exit 0
14
+ else
15
+ echo "no (PID file doesn't exist: ${pid_file})"
16
+ exit 1
17
+ fi
18
+ ;;
19
+ config)
20
+ if [ -z "${label}" ]; then
21
+ title="groonga: memory usage"
22
+ else
23
+ title="groonga: ${label}: memory usage"
24
+ fi
25
+ cat <<EOF
26
+ graph_title ${title}
27
+ graph_vlabel memory usage
28
+ graph_category groonga
29
+ graph_info groonga memory usage
30
+
31
+ rss.label resident set size
32
+ rss.type GAUGE
33
+ vsz.label virtual memory size
34
+ vsz.type GAUGE
35
+ EOF
36
+ exit 0
37
+ ;;
38
+ *)
39
+ esac
40
+
41
+ if [ -z "${pid_file}" ]; then
42
+ echo "PID file isn't specified by env.pid_file"
43
+ exit 1
44
+ fi
45
+
46
+ groonga_pid=$(cat ${pid_file})
47
+ read rss_in_kb vsz_in_kb <<EOC
48
+ $(ps h -o rss,vsz -p ${groonga_pid})
49
+ EOC
50
+ echo "rss.value ${rss_in_kb}000"
51
+ echo "vsz.value ${vsz_in_kb}000"
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ require 'shellwords'
7
+ require 'json'
8
+
9
+ label = ENV["label"]
10
+ @groonga = ENV["groonga"] || "groonga"
11
+ @host = ENV["host"] || "localhost"
12
+ @port = ENV["port"] || 10041
13
+ @path = ENV["path"]
14
+
15
+ command = ARGV.shift
16
+
17
+ def parse(success, result)
18
+ if success
19
+ begin
20
+ status, body = JSON.parse(result)
21
+ return_code, start_time, elapsed, error_message = status
22
+ if return_code.zero?
23
+ [success, body]
24
+ else
25
+ [false, error_message]
26
+ end
27
+ rescue JSON::ParserError
28
+ [false, $!.message]
29
+ end
30
+ else
31
+ [success, result]
32
+ end
33
+ end
34
+
35
+ def run(command, *args)
36
+ if @path
37
+ path = Shellwords.shellescape(@path)
38
+ result = `#{@groonga} #{path} #{command} #{args.join(' ')} 2>&1`
39
+ else
40
+ groonga = "#{@groonga} -p #{@port} -c #{@host}"
41
+ result = `#{groonga} #{command} #{args.join(' ')} 2>&1`
42
+ end
43
+ parse($?.success?, result)
44
+ end
45
+
46
+ def parse_list(header, list)
47
+ list.collect do |item|
48
+ parsed_item = {}
49
+ header.each_with_index do |(name, type), i|
50
+ parsed_item[name] = item[i]
51
+ end
52
+ parsed_item
53
+ end
54
+ end
55
+
56
+ case command
57
+ when "autoconf", "detect"
58
+ success, body = run("status")
59
+ if success
60
+ puts "yes"
61
+ exit(true)
62
+ else
63
+ puts "no (#{body})"
64
+ exit(false)
65
+ end
66
+ when "config"
67
+ if label.nil?
68
+ title = "groonga: number of records"
69
+ else
70
+ title = "groonga: #{label}: number of records"
71
+ end
72
+ puts <<EOF
73
+ graph_title #{title}
74
+ graph_vlabel records
75
+ graph_category groonga
76
+ graph_info number of records in groonga table
77
+ EOF
78
+ success, body = run("table_list")
79
+ unless success
80
+ puts "error: #{body}"
81
+ exit(false)
82
+ end
83
+ parse_list(body[0], body[1..-1]).each do |table|
84
+ name = table["name"]
85
+ puts <<EOF
86
+
87
+ #{name}.label #{name}
88
+ #{name}.type GAUGE
89
+ EOF
90
+ end
91
+ exit(true)
92
+ end
93
+
94
+ success, body = run("table_list")
95
+ unless success
96
+ puts("error: #{body}")
97
+ exit(false)
98
+ end
99
+ parse_list(body[0], body[1..-1]).each do |table|
100
+ name = table["name"]
101
+ success, body = run("select", "#{name} --limit 0")
102
+ unless success
103
+ puts("error: #{body}")
104
+ exit(false)
105
+ end
106
+ n_records = body[0][0][0]
107
+ puts <<EOF
108
+ #{name}.value #{n_records}
109
+ EOF
110
+ end
@@ -0,0 +1,133 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #%# family=auto
4
+ #%# capabilities=autoconf
5
+
6
+ require 'English'
7
+ require 'strscan'
8
+
9
+ label = ENV["label"]
10
+
11
+ @log_path = ENV["log_path"]
12
+
13
+ command = ARGV.shift
14
+
15
+ case command
16
+ when "autoconf", "detect"
17
+ if @log_path.nil?
18
+ puts "no (query log file path isn't specified by env.log_path)"
19
+ exit(false)
20
+ end
21
+ unless File.readable?(@log_path)
22
+ puts "no (query log file isn't readable: <#{@log_path}>)"
23
+ exit(false)
24
+ end
25
+ puts "yes"
26
+ exit(true)
27
+ when "config"
28
+ if label.nil?
29
+ title = "groonga: query performance"
30
+ else
31
+ title = "groonga: #{label}: query performance"
32
+ end
33
+ puts <<EOF
34
+ graph_title #{title}
35
+ graph_vlabel seconds
36
+ graph_category groonga
37
+ graph_info groonga query performance
38
+
39
+ longest.label Longest
40
+ average.label Average
41
+ median.label Median
42
+ EOF
43
+ exit(true)
44
+ end
45
+
46
+ class ReverseLineReader
47
+ def initialize(io)
48
+ @io = io
49
+ @io.seek(0, IO::SEEK_END)
50
+ @buffer = ""
51
+ @data = ""
52
+ end
53
+
54
+ def each
55
+ separator = $/
56
+ separator_length = separator.length
57
+ while read_to_buffer
58
+ loop do
59
+ index = @buffer.rindex(separator, @buffer.length - 1 - separator_length)
60
+ break if index.nil? or index.zero?
61
+ last_line = @buffer.slice!((index + separator_length)..-1)
62
+ yield(last_line)
63
+ end
64
+ end
65
+ yield(@buffer) unless @buffer.empty?
66
+ end
67
+
68
+ private
69
+ BYTES_PER_READ = 4096
70
+ def read
71
+ position = @io.pos
72
+ if position < BYTES_PER_READ
73
+ bytes_per_read = position
74
+ else
75
+ bytes_per_read = BYTES_PER_READ
76
+ end
77
+
78
+ if bytes_per_read.zero?
79
+ @data.replace("")
80
+ else
81
+ @io.seek(-bytes_per_read, IO::SEEK_CUR)
82
+ @io.read(bytes_per_read, @data)
83
+ @io.seek(-bytes_per_read, IO::SEEK_CUR)
84
+ end
85
+
86
+ @data
87
+ end
88
+
89
+ def read_to_buffer
90
+ data = read
91
+ if data.empty?
92
+ false
93
+ else
94
+ @buffer.insert(0, data)
95
+ true
96
+ end
97
+ end
98
+ end
99
+
100
+ span = 60 * 5 # 5min
101
+ mega = 1_000_000.0
102
+ now = Time.now
103
+ elapsed_times = []
104
+ File.open(@log_path) do |log_file|
105
+ ReverseLineReader.new(log_file).each do |line|
106
+ case line
107
+ when /\A(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)\.(\d+)\|([\da-f])+\|<(\d+) rc=0$/
108
+ _, year, month, day, hour, minutes, seconds, milliseconds,
109
+ context, elapsed = $LAST_MATCH_INFO.to_a
110
+ time_stamp = Time.local(year, month, day,
111
+ hour, minutes, seconds, milliseconds)
112
+ difference = now - time_stamp
113
+ break if difference > span
114
+ elapsed_in_micro_seconds = elapsed.to_i / mega
115
+ elapsed_times << elapsed_in_micro_seconds
116
+ end
117
+ end
118
+ end
119
+
120
+ sorted_elapsed_times = elapsed_times.sort
121
+ if sorted_elapsed_times.empty?
122
+ longest = 0
123
+ average = 0
124
+ median = 0
125
+ else
126
+ longest = sorted_elapsed_times.last
127
+ average = sorted_elapsed_times.inject(&:+) / sorted_elapsed_times.size.to_f
128
+ median = sorted_elapsed_times[sorted_elapsed_times.size / 2]
129
+ end
130
+
131
+ puts "longest.value #{longest}"
132
+ puts "average.value #{average}"
133
+ puts "median.value #{median}"