rroonga 3.0.9 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Groonga
19
+ class Column
20
+ def disk_usage
21
+ measurer = StatisticMeasurer.new
22
+ measurer.measure_disk_usage(path)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,279 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Groonga
19
+ # It is a class that inspects database. You can know details metadata
20
+ # of the database.
21
+ class DatabaseInspector
22
+ # @param database [Database] The database to be inspected.
23
+ def initialize(database)
24
+ @database = database
25
+ end
26
+
27
+ # Report inspected result of the database.
28
+ #
29
+ # @param output [#write] (nil) The output of inspected result.
30
+ # If it is @nil@, @$stdout@ is used.
31
+ def report(output=nil)
32
+ output ||= $stdout
33
+ reporter = Reporter.new(@database, output)
34
+ reporter.report
35
+ end
36
+
37
+ # @private
38
+ class Reporter
39
+ def initialize(database, output)
40
+ @database = database
41
+ @context = @database.context
42
+ @output = output
43
+ @indent_width = 0
44
+ end
45
+
46
+ def report
47
+ write("Database\n")
48
+ indent do
49
+ write("Path: #{inspect_path(@database.path)}\n")
50
+ write("Total disk usage: " +
51
+ "#{inspect_disk_usage(total_disk_usage)}\n")
52
+ write("Disk usage: " +
53
+ "#{inspect_sub_disk_usage(@database.disk_usage)}\n")
54
+ write("N records: #{count_total_n_records}\n")
55
+ write("N tables: #{count_n_tables}\n")
56
+ write("N columns: #{count_total_n_columns}\n")
57
+ report_plugins
58
+ report_tables
59
+ end
60
+ end
61
+
62
+ private
63
+ def report_plugins
64
+ write("Plugins:\n")
65
+ indent do
66
+ plugin_paths = @database.plugin_paths
67
+ if plugin_paths.empty?
68
+ write("None\n")
69
+ return
70
+ end
71
+ plugin_paths.each do |path|
72
+ write("* #{path}\n")
73
+ end
74
+ end
75
+ end
76
+
77
+ def report_tables
78
+ write("Tables:\n")
79
+ indent do
80
+ tables = @database.tables
81
+ if tables.empty?
82
+ write("None\n")
83
+ return
84
+ end
85
+ tables.each do |table|
86
+ report_table(table)
87
+ end
88
+ end
89
+ end
90
+
91
+ def report_table(table)
92
+ write("#{table.name}:\n")
93
+ indent do
94
+ write("ID: #{table.id}\n")
95
+ write("Type: #{inspect_table_type(table)}\n")
96
+ write("Key type: #{inspect_key_type(table)}\n")
97
+ write("Tokenizer: #{inspect_tokenizer(table)}\n")
98
+ write("Normalizer: #{inspect_normalizer(table)}\n")
99
+ write("Path: #{inspect_path(table.path)}\n")
100
+ total_table_disk_usage = count_total_table_disk_usage(table)
101
+ write("Total disk usage: " +
102
+ "#{inspect_sub_disk_usage(total_table_disk_usage)}\n")
103
+ write("Disk usage: " +
104
+ "#{inspect_sub_disk_usage(table.disk_usage)}\n")
105
+ write("N records: #{table.size}\n")
106
+ write("N columns: #{table.columns.size}\n")
107
+ report_columns(table)
108
+ end
109
+ end
110
+
111
+ def report_columns(table)
112
+ write("Columns:\n")
113
+ indent do
114
+ columns = table.columns
115
+ if columns.empty?
116
+ write("None\n")
117
+ return
118
+ end
119
+ columns.each do |column|
120
+ report_column(column)
121
+ end
122
+ end
123
+ end
124
+
125
+ def report_column(column)
126
+ write("#{column.local_name}:\n")
127
+ indent do
128
+ write("ID: #{column.id}\n")
129
+ write("Type: #{inspect_column_type(column)}\n")
130
+ write("Value type: #{inspect_column_value_type(column)}\n")
131
+ write("Path: #{inspect_path(column.path)}\n")
132
+ write("Disk usage: #{inspect_sub_disk_usage(column.disk_usage)}\n")
133
+ end
134
+ end
135
+
136
+ def indent
137
+ indent_width = @indent_width
138
+ @indent_width += 2
139
+ yield
140
+ ensure
141
+ @indent_width = indent_width
142
+ end
143
+
144
+ def write(message)
145
+ indent = " " * @indent_width
146
+ @output.write("#{indent}#{message}")
147
+ end
148
+
149
+ def inspect_path(path)
150
+ if path.nil?
151
+ "(null)"
152
+ else
153
+ "<#{path}>"
154
+ end
155
+ end
156
+
157
+ KiB = (2 ** 10).to_f
158
+ MiB = (2 ** 20).to_f
159
+ GiB = (2 ** 30).to_f
160
+ TiB = (2 ** 40).to_f
161
+ PiB = (2 ** 50).to_f
162
+ def inspect_disk_usage(disk_usage)
163
+ if disk_usage < KiB
164
+ "%dB" % disk_usage
165
+ elsif disk_usage < MiB
166
+ "%.3fKiB" % (disk_usage / KiB)
167
+ elsif disk_usage < GiB
168
+ "%.3fMiB" % (disk_usage / MiB)
169
+ elsif disk_usage < TiB
170
+ "%.3fGiB" % (disk_usage / GiB)
171
+ elsif disk_usage < PiB
172
+ "%.3fTiB" % (disk_usage / TiB)
173
+ else
174
+ "%.3fPiB" % (disk_usage / PiB)
175
+ end
176
+ end
177
+
178
+ def inspect_sub_disk_usage(disk_usage)
179
+ percent = disk_usage / total_disk_usage.to_f * 100
180
+ "%s (%.3f%%)" % [inspect_disk_usage(disk_usage), percent]
181
+ end
182
+
183
+ def count_total_n_records
184
+ @database.tables.inject(0) do |previous, table|
185
+ previous + table.size
186
+ end
187
+ end
188
+
189
+ def count_n_tables
190
+ @database.tables.size
191
+ end
192
+
193
+ def count_total_n_columns
194
+ @database.tables.inject(0) do |previous, table|
195
+ previous + table.columns.size
196
+ end
197
+ end
198
+
199
+ def total_disk_usage
200
+ @total_disk_usage ||= count_total_disk_usage
201
+ end
202
+
203
+ def count_total_disk_usage
204
+ @database.tables.inject(@database.disk_usage) do |previous, table|
205
+ previous + count_total_table_disk_usage(table)
206
+ end
207
+ end
208
+
209
+ def count_total_table_disk_usage(table)
210
+ table.columns.inject(table.disk_usage) do |previous, column|
211
+ previous + column.disk_usage
212
+ end
213
+ end
214
+
215
+ def inspect_table_type(table)
216
+ case table
217
+ when Groonga::Array
218
+ "array"
219
+ when Groonga::Hash
220
+ "hash"
221
+ when Groonga::PatriciaTrie
222
+ "patricia trie"
223
+ when Groonga::DoubleArrayTrie
224
+ "double array trie"
225
+ else
226
+ "unknown (#{table.class})"
227
+ end
228
+ end
229
+
230
+ def inspect_key_type(table)
231
+ if table.support_key?
232
+ table.domain.name
233
+ else
234
+ "(no key)"
235
+ end
236
+ end
237
+
238
+ def inspect_tokenizer(table)
239
+ if table.support_key?
240
+ tokenizer = table.default_tokenizer
241
+ if tokenizer
242
+ tokenizer.name
243
+ else
244
+ "(no tokenizer)"
245
+ end
246
+ else
247
+ "(no key)"
248
+ end
249
+ end
250
+
251
+ def inspect_normalizer(table)
252
+ if table.support_key?
253
+ normalizer = table.normalizer
254
+ if normalizer
255
+ normalizer.name
256
+ else
257
+ "(no normalizer)"
258
+ end
259
+ else
260
+ "(no key)"
261
+ end
262
+ end
263
+
264
+ def inspect_column_type(column)
265
+ if column.index?
266
+ "index"
267
+ elsif column.vector?
268
+ "vector"
269
+ else
270
+ "scalar"
271
+ end
272
+ end
273
+
274
+ def inspect_column_value_type(column)
275
+ column.domain.name
276
+ end
277
+ end
278
+ end
279
+ end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -19,11 +19,41 @@ module Groonga
19
19
  class Database
20
20
  # @return [Array<Groonga::Table>] tables defined in the database.
21
21
  def tables
22
- find_all do |object|
22
+ options = {
23
+ :ignore_missing_object => true,
24
+ :order_by => :key,
25
+ }
26
+ each(options).find_all do |object|
23
27
  object.is_a?(Groonga::Table)
24
28
  end
25
29
  end
26
30
 
31
+ # @return [Array<String>] registered plugin paths.
32
+ def plugin_paths
33
+ processed_paths = {}
34
+ paths = []
35
+ each(:ignore_missing_object => true, :order_by => :id) do |object|
36
+ next unless object.is_a?(Groonga::Procedure)
37
+ next if object.builtin?
38
+ path = object.path
39
+ next if path.nil?
40
+ next if processed_paths.has_key?(path)
41
+ processed_paths[path] = true
42
+ paths << path
43
+ end
44
+ paths
45
+ end
46
+
47
+ def disk_usage
48
+ return 0 if path.nil?
49
+
50
+ usage = 0
51
+ measurer = StatisticMeasurer.new
52
+ usage += measurer.measure_disk_usage(path)
53
+ usage += measurer.measure_disk_usage("%s.%07X" % [path, 0])
54
+ usage
55
+ end
56
+
27
57
  def dump_index(output_directory)
28
58
  each do |object|
29
59
  next unless object.is_a?(Groonga::IndexColumn)
@@ -81,15 +81,9 @@ module Groonga
81
81
 
82
82
  private
83
83
  def dump_plugins(options)
84
- plugin_paths = {}
85
- options[:database].each(each_options(:order_by => :id)) do |object|
86
- next unless object.is_a?(Groonga::Procedure)
87
- next if object.builtin?
88
- path = object.path
89
- next if path.nil?
90
- next if plugin_paths.has_key?(path)
91
- plugin_paths[path] = true
92
- dump_plugin(object, options)
84
+ plugin_paths = options[:database].plugin_paths
85
+ plugin_paths.each do |path|
86
+ dump_plugin(path, options)
93
87
  end
94
88
  options[:output].write("\n") unless plugin_paths.empty?
95
89
  end
@@ -112,13 +106,13 @@ module Groonga
112
106
  TableDumper.new(table, options).dump
113
107
  end
114
108
 
115
- def dump_plugin(plugin, options)
109
+ def dump_plugin(path, options)
116
110
  output = options[:output]
117
111
  plugins_dir_re = Regexp.escape(Groonga::Plugin.system_plugins_dir)
118
112
  suffix_re = Regexp.escape(Groonga::Plugin.suffix)
119
- plugin_name = plugin.path.gsub(/(?:\A#{plugins_dir_re}\/|
120
- #{suffix_re}\z)/x,
121
- '')
113
+ plugin_name = path.gsub(/(?:\A#{plugins_dir_re}\/|
114
+ #{suffix_re}\z)/x,
115
+ '')
122
116
  output.write("register #{plugin_name}\n")
123
117
  end
124
118
 
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2012-2013 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -24,6 +24,16 @@ module Groonga
24
24
  dumper = IndexColumnDumper.new(self, output_directory)
25
25
  dumper.dump
26
26
  end
27
+
28
+ def disk_usage
29
+ return 0 if path.nil?
30
+
31
+ usage = super
32
+ chunk_path = "#{path}.c"
33
+ measurer = StatisticMeasurer.new
34
+ usage += measurer.measure_disk_usage(chunk_path)
35
+ usage
36
+ end
27
37
  end
28
38
 
29
39
  class IndexColumnDumper
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Groonga
19
+ # Measures statistic.
20
+ class StatisticMeasurer
21
+ MAX_N_ADDITIONAL_PATHS = 4096
22
+
23
+ # @param path [String, nil] Measures disk usage of the path.
24
+ # @return [Integer] 0 if path is @nil@, disk usage of the path otherwise.
25
+ def measure_disk_usage(path)
26
+ return 0 if path.nil?
27
+
28
+ usage = File.size(path)
29
+ 1.step(MAX_N_ADDITIONAL_PATHS) do |i|
30
+ additional_path = "%s.%03X" % [path, i]
31
+ break unless File.exist?(additional_path)
32
+ usage += File.size(additional_path)
33
+ end
34
+ usage
35
+ end
36
+ end
37
+ end