fluent-plugin-droonga 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.travis.yml +1 -1
  2. data/Gemfile +1 -1
  3. data/fluent-plugin-droonga.gemspec +1 -1
  4. data/lib/droonga/catalog/collection_volume.rb +97 -0
  5. data/lib/droonga/catalog/dataset.rb +28 -1
  6. data/lib/droonga/catalog/errors.rb +28 -9
  7. data/lib/droonga/catalog/schema.rb +23 -2
  8. data/lib/droonga/catalog/single_volume.rb +28 -0
  9. data/lib/droonga/catalog/slice.rb +43 -0
  10. data/lib/droonga/catalog/version1.rb +3 -3
  11. data/lib/droonga/catalog/version2.rb +17 -81
  12. data/lib/droonga/catalog/version2_validator.rb +63 -0
  13. data/lib/droonga/catalog/volume.rb +33 -0
  14. data/lib/droonga/catalog/volume_collection.rb +56 -0
  15. data/lib/droonga/catalog_observer.rb +7 -19
  16. data/lib/droonga/collectors.rb +1 -1
  17. data/lib/droonga/collectors/{add.rb → or.rb} +1 -1
  18. data/lib/droonga/dispatcher.rb +24 -18
  19. data/lib/droonga/distributed_command_planner.rb +7 -11
  20. data/lib/droonga/distributor.rb +29 -17
  21. data/lib/droonga/event_loop.rb +2 -11
  22. data/lib/droonga/fluent_message_sender.rb +51 -5
  23. data/lib/droonga/handler_runner.rb +1 -1
  24. data/lib/droonga/job_protocol.rb +20 -0
  25. data/lib/droonga/job_pusher.rb +178 -0
  26. data/lib/droonga/{message_receiver.rb → job_receiver.rb} +13 -6
  27. data/lib/droonga/message_matcher.rb +18 -15
  28. data/lib/droonga/planner.rb +2 -3
  29. data/lib/droonga/plugins/crud.rb +1 -1
  30. data/lib/droonga/plugins/groonga/column_create.rb +4 -1
  31. data/lib/droonga/plugins/groonga/table_create.rb +1 -1
  32. data/lib/droonga/plugins/groonga/table_remove.rb +1 -1
  33. data/lib/droonga/plugins/search/distributed_search_planner.rb +9 -0
  34. data/lib/droonga/processor.rb +3 -3
  35. data/lib/droonga/reducer.rb +15 -12
  36. data/lib/droonga/searcher.rb +49 -4
  37. data/lib/droonga/server.rb +2 -0
  38. data/lib/droonga/single_step.rb +22 -7
  39. data/lib/droonga/slice.rb +7 -7
  40. data/lib/droonga/step_runner.rb +3 -2
  41. data/lib/droonga/worker.rb +10 -8
  42. data/test/command/suite/add/dimension/column.catalog.json +27 -0
  43. data/test/command/suite/add/dimension/column.expected +57 -0
  44. data/test/command/suite/add/dimension/column.test +51 -0
  45. data/test/command/suite/search/adjusters/multiple.catalog.json +38 -0
  46. data/test/command/suite/search/adjusters/multiple.expected +23 -0
  47. data/test/command/suite/search/adjusters/multiple.test +75 -0
  48. data/test/command/suite/search/adjusters/one.catalog.json +38 -0
  49. data/test/command/suite/search/adjusters/one.expected +23 -0
  50. data/test/command/suite/search/adjusters/one.test +66 -0
  51. data/test/command/suite/search/attributes/array.test +0 -2
  52. data/test/command/suite/search/attributes/hash.test +0 -2
  53. data/test/command/suite/search/complex.test +0 -2
  54. data/test/command/suite/search/condition/nested.test +0 -2
  55. data/test/command/suite/search/condition/query.test +0 -2
  56. data/test/command/suite/search/condition/script.test +0 -2
  57. data/test/command/suite/search/group/string.test +0 -4
  58. data/test/command/suite/search/group/subrecord/with-sort.catalog.json +33 -0
  59. data/test/command/suite/search/group/subrecord/with-sort.expected +34 -0
  60. data/test/command/suite/search/group/subrecord/with-sort.test +81 -0
  61. data/test/command/suite/search/multiple/chained.test +0 -4
  62. data/test/command/suite/search/multiple/parallel.test +0 -4
  63. data/test/command/suite/search/range/only-output.test +0 -2
  64. data/test/command/suite/search/range/only-sort.test +0 -2
  65. data/test/command/suite/search/range/sort-and-output.test +0 -2
  66. data/test/command/suite/search/range/too-large-output-offset.test +0 -2
  67. data/test/command/suite/search/range/too-large-sort-offset.test +0 -2
  68. data/test/command/suite/search/response/elapsed_time.catalog.json +13 -0
  69. data/test/command/suite/search/response/elapsed_time.expected +15 -0
  70. data/test/command/suite/search/response/elapsed_time.test +26 -0
  71. data/test/command/suite/search/response/records/value/time.test +0 -2
  72. data/test/command/suite/search/simple.test +0 -2
  73. data/test/command/suite/search/sort/default-offset-limit.test +0 -2
  74. data/test/command/suite/search/sort/invisible-column.test +0 -2
  75. data/test/unit/catalog/test_collection_volume.rb +103 -0
  76. data/test/unit/catalog/test_dataset.rb +69 -8
  77. data/test/unit/catalog/test_schema.rb +63 -23
  78. data/test/unit/catalog/test_single_volume.rb +31 -0
  79. data/test/unit/catalog/test_slice.rb +92 -0
  80. data/test/unit/catalog/test_version1.rb +1 -1
  81. data/test/unit/catalog/test_version2.rb +1 -32
  82. data/test/unit/catalog/test_version2_validator.rb +66 -0
  83. data/test/unit/catalog/test_volume_collection.rb +50 -0
  84. data/test/unit/plugins/groonga/test_column_create.rb +4 -1
  85. data/test/unit/plugins/groonga/test_table_create.rb +1 -1
  86. data/test/unit/test_message_matcher.rb +15 -15
  87. data/test/unit/test_watch_schema.rb +1 -1
  88. metadata +107 -94
  89. checksums.yaml +0 -7
  90. data/lib/droonga/message_pusher.rb +0 -64
@@ -69,6 +69,9 @@ module Droonga
69
69
  options[:type] = :scalar
70
70
  elsif @command.column_vector?
71
71
  options[:type] = :vector
72
+ if @command.with_weight?
73
+ options[:with_weight] = true
74
+ end
72
75
  end
73
76
  options
74
77
  end
@@ -120,7 +123,7 @@ module Droonga
120
123
  step.name = "column_create"
121
124
  step.write = true
122
125
  step.handler = Handler
123
- step.collector = Collectors::Add
126
+ step.collector = Collectors::Or
124
127
  end
125
128
  end
126
129
  end
@@ -103,7 +103,7 @@ module Droonga
103
103
  step.name = "table_create"
104
104
  step.write = true
105
105
  step.handler = Handler
106
- step.collector = Collectors::Add
106
+ step.collector = Collectors::Or
107
107
  end
108
108
  end
109
109
  end
@@ -54,7 +54,7 @@ module Droonga
54
54
  step.name = "table_remove"
55
55
  step.write = true
56
56
  step.handler = Handler
57
- step.collector = Collectors::Add
57
+ step.collector = Collectors::Or
58
58
  end
59
59
  end
60
60
  end
@@ -122,6 +122,7 @@ module Droonga
122
122
 
123
123
  calculate_offset_and_limit!
124
124
  build_count_mapper_and_reducer!
125
+ build_elapsed_time_mapper_and_reducer!
125
126
  build_records_mapper_and_reducer!
126
127
  end
127
128
 
@@ -256,6 +257,14 @@ module Droonga
256
257
  end
257
258
  end
258
259
 
260
+ def build_elapsed_time_mapper_and_reducer!
261
+ return unless @output["elements"].include?("elapsedTime")
262
+
263
+ @reducers["elapsedTime"] = {
264
+ "type" => "sum",
265
+ }
266
+ end
267
+
259
268
  def build_records_mapper_and_reducer!
260
269
  # Skip reducing phase for a result with no record output.
261
270
  return if !@output["elements"].include?("records") || @records_limit.zero?
@@ -20,9 +20,9 @@ module Droonga
20
20
  class Processor
21
21
  include Loggable
22
22
 
23
- def initialize(loop, message_pusher, options={})
23
+ def initialize(loop, job_pusher, options={})
24
24
  @loop = loop
25
- @message_pusher = message_pusher
25
+ @job_pusher = job_pusher
26
26
  @options = options
27
27
  @n_workers = @options[:n_workers] || 0
28
28
  end
@@ -47,7 +47,7 @@ module Droonga
47
47
  if @n_workers.zero? or synchronous
48
48
  @handler_runner.process(message)
49
49
  else
50
- @message_pusher.push(message)
50
+ @job_pusher.push(message)
51
51
  end
52
52
  else
53
53
  logger.trace("process: ignore #{type}")
@@ -134,25 +134,28 @@ module Droonga
134
134
  base_items, unified_items = unified_items, base_items
135
135
  end
136
136
 
137
- rest_unified_items = unified_items.dup
137
+ unified_key_map = {}
138
+ unified_items.each do |unified_item|
139
+ unified_key_map[unified_item[key_column_index]] = unified_item
140
+ end
138
141
 
142
+ unified = false
139
143
  base_items.reject! do |base_item|
140
144
  key = base_item[key_column_index]
141
- rest_unified_items.any? do |unified_item|
142
- if unified_item[key_column_index] == key
143
- base_item.each_with_index do |value, column|
144
- next if column == key_column_index
145
- unified_item[column] += value
146
- end
147
- rest_unified_items -= [unified_item]
148
- true
149
- else
150
- false
145
+ unified_item = unified_key_map[key]
146
+ if unified_item
147
+ base_item.each_with_index do |value, column_index|
148
+ next if column_index == key_column_index
149
+ unified_item[column_index] += value
151
150
  end
151
+ unified = true
152
+ true
153
+ else
154
+ false
152
155
  end
153
156
  end
154
157
 
155
- unless rest_unified_items.size == unified_items.size
158
+ if unified
156
159
  unified_items.sort! do |a, b|
157
160
  if compare(a, b, options[:operators])
158
161
  -1
@@ -61,14 +61,26 @@ module Droonga
61
61
  def search(queries)
62
62
  outputs = nil
63
63
  logger.trace("search: start", :queries => queries)
64
- @context.push_memory_pool do
65
- outputs = process_queries(queries)
64
+ # TODO: THIS IS JUST A WORKAROUND! We should remove it ASAP!
65
+ disable_gc do
66
+ @context.push_memory_pool do
67
+ outputs = process_queries(queries)
68
+ end
66
69
  end
67
70
  logger.trace("search: done")
68
71
  return outputs
69
72
  end
70
73
 
71
74
  private
75
+ def disable_gc
76
+ GC.disable
77
+ begin
78
+ yield
79
+ ensure
80
+ GC.enable
81
+ end
82
+ end
83
+
72
84
  def process_queries(queries)
73
85
  logger.trace("process_queries: start")
74
86
  if queries.nil? or queries.empty?
@@ -302,7 +314,12 @@ module Droonga
302
314
  @records = @request.source
303
315
 
304
316
  condition = @request.query["condition"]
305
- apply_condition!(condition) if condition
317
+ if condition
318
+ apply_condition!(condition)
319
+
320
+ adjusters = @request.query["adjusters"]
321
+ apply_adjusters!(adjusters) if adjusters
322
+ end
306
323
 
307
324
  group_by = @request.query["groupBy"]
308
325
  apply_group_by!(group_by) if group_by
@@ -328,6 +345,29 @@ module Droonga
328
345
  @result.condition = expression
329
346
  end
330
347
 
348
+ def apply_adjusters!(adjusters)
349
+ logger.trace("search_query: adjusters: start")
350
+ adjusters.each do |adjuster|
351
+ column_name = adjuster["column"]
352
+ value = adjuster["value"]
353
+ factor = adjuster["factor"] || 1
354
+ logger.trace("search_query: adjusters: adjuster: start",
355
+ :column_name => column_name,
356
+ :value => value,
357
+ :factor => factor)
358
+ column = @request.source.column(column_name)
359
+ index, = column.indexes(:match)
360
+ # TODO: add index.nil? check
361
+ # TODO: add value.nil? check
362
+ index.search(value,
363
+ :result => @records,
364
+ :operator => :adjust,
365
+ :weight => factor)
366
+ logger.trace("search_query: adjusters: adjuster: done")
367
+ end
368
+ logger.trace("search_query: adjusters: done")
369
+ end
370
+
331
371
  def apply_group_by!(group_by)
332
372
  logger.trace("search_query: group: start",
333
373
  :by => group_by)
@@ -449,7 +489,12 @@ module Droonga
449
489
  module RecordsFormattable
450
490
  def record_value(record, attribute)
451
491
  if attribute[:source] == "_subrecs"
452
- record.sub_records.collect do |sub_record|
492
+ if record.table.is_a?(Groonga::Array)
493
+ target_record = record.value
494
+ else
495
+ target_record = record
496
+ end
497
+ target_record.sub_records.collect do |sub_record|
453
498
  sub_attributes = attribute[:attributes]
454
499
  format_record(sub_attributes, sub_record)
455
500
  end
@@ -21,6 +21,8 @@ module Droonga
21
21
  module Server
22
22
  def before_run
23
23
  Droonga.logger.trace("#{log_tag}: before_run: start")
24
+ config[:job_pusher].close
25
+ config.delete(:job_pusher)
24
26
  Droonga.logger.trace("#{log_tag}: before_run: done")
25
27
  end
26
28
 
@@ -18,7 +18,8 @@ require "droonga/collectors"
18
18
 
19
19
  module Droonga
20
20
  class SingleStep
21
- def initialize(definition)
21
+ def initialize(dataset, definition)
22
+ @dataset = dataset
22
23
  @definition = definition
23
24
  end
24
25
 
@@ -40,14 +41,28 @@ module Droonga
40
41
  reduce_key => collector_class.operator,
41
42
  }
42
43
  end
43
- inputs = @definition.inputs
44
- if inputs.empty?
45
- planner.send(:broadcast, message, options)
44
+
45
+ body = message["body"]
46
+ fact_input = find_fact_input(@definition.inputs, @dataset.fact, body)
47
+ if fact_input
48
+ record = body[fact_input[:filter]]
49
+ planner.send(:scatter, message, record, options)
46
50
  else
47
- input = inputs.values.first
48
- options[:key] = message["body"][input[:filter]]["key"]
49
- planner.send(:scatter, message, options)
51
+ planner.send(:broadcast, message, options)
52
+ end
53
+ end
54
+
55
+ def find_fact_input(inputs, fact, body)
56
+ inputs.each do |key, input|
57
+ if input[:type] == :table
58
+ # for backward compatibility. We can remove the following code
59
+ # when all our catalog.json specify "fact" parameter.
60
+ return input if fact.nil?
61
+
62
+ return input if body[key] == fact
63
+ end
50
64
  end
65
+ nil
51
66
  end
52
67
  end
53
68
  end
@@ -19,7 +19,7 @@ require "droonga/loggable"
19
19
  require "droonga/server"
20
20
  require "droonga/worker"
21
21
  require "droonga/event_loop"
22
- require "droonga/message_pusher"
22
+ require "droonga/job_pusher"
23
23
  require "droonga/processor"
24
24
 
25
25
  module Droonga
@@ -30,23 +30,22 @@ module Droonga
30
30
  @options = options
31
31
  @n_workers = @options[:n_workers] || 0
32
32
  @loop = loop
33
- @message_pusher = MessagePusher.new(@loop)
34
- @processor = Processor.new(@loop, @message_pusher, @options)
33
+ @job_pusher = JobPusher.new(@loop, @options[:database])
34
+ @processor = Processor.new(@loop, @job_pusher, @options)
35
35
  @supervisor = nil
36
36
  end
37
37
 
38
38
  def start
39
39
  ensure_database
40
40
  @processor.start
41
- base_path = @options[:database]
42
- @message_pusher.start(base_path)
41
+ @job_pusher.start
43
42
  start_supervisor if @n_workers > 0
44
43
  end
45
44
 
46
45
  def shutdown
47
46
  logger.trace("shutdown: start")
48
47
  shutdown_supervisor if @supervisor
49
- @message_pusher.shutdown
48
+ @job_pusher.shutdown
50
49
  @processor.shutdown
51
50
  logger.trace("shutdown: done")
52
51
  end
@@ -84,7 +83,8 @@ module Droonga
84
83
  :log_level => logger.level,
85
84
  :server_process_name => "Server[#{@options[:database]}] #$0",
86
85
  :worker_process_name => "Worker[#{@options[:database]}] #$0",
87
- :message_receiver => @message_pusher.raw_receiver,
86
+ :job_receive_socket_path => @job_pusher.socket_path,
87
+ :job_pusher => @job_pusher,
88
88
  }
89
89
  @options.merge(force_options)
90
90
  end
@@ -21,7 +21,8 @@ module Droonga
21
21
  class StepRunner
22
22
  include Loggable
23
23
 
24
- def initialize(plugins)
24
+ def initialize(dataset, plugins)
25
+ @dataset = dataset
25
26
  @definitions = {}
26
27
  plugins.each do |name|
27
28
  plugin = Plugin.registry[name]
@@ -43,7 +44,7 @@ module Droonga
43
44
  if definition.nil?
44
45
  raise UnsupportedMessageError.new(:planner, message)
45
46
  end
46
- step = SingleStep.new(definition)
47
+ step = SingleStep.new(@dataset, definition)
47
48
  plan = step.plan(message)
48
49
  logger.trace("plan: done",
49
50
  :dataset => message["dataset"],
@@ -15,16 +15,17 @@
15
15
 
16
16
  require "droonga/event_loop"
17
17
  require "droonga/handler_runner"
18
- require "droonga/message_receiver"
18
+ require "droonga/job_receiver"
19
19
 
20
20
  module Droonga
21
21
  module Worker
22
22
  def initialize
23
- @loop = EventLoop.new
23
+ @raw_loop = Coolio::Loop.new
24
+ @loop = EventLoop.new(@raw_loop)
24
25
  @handler_runner = HandlerRunner.new(@loop,
25
26
  config.merge(:dispatcher => nil))
26
- receiver_socket = config[:message_receiver]
27
- @message_receiver = MessageReceiver.new(@loop, receiver_socket) do |message|
27
+ receive_socket_path = config[:job_receive_socket_path]
28
+ @job_receiver = JobReceiver.new(@loop, receive_socket_path) do |message|
28
29
  process(message)
29
30
  end
30
31
  end
@@ -32,16 +33,17 @@ module Droonga
32
33
  def run
33
34
  Droonga.logger.trace("#{log_tag}: run: start")
34
35
  @handler_runner.start
35
- @message_receiver.start
36
- @loop.run
36
+ @job_receiver.start
37
+ @raw_loop.run
37
38
  @handler_runner.shutdown
38
39
  Droonga.logger.trace("#{log_tag}: run: done")
39
40
  end
40
41
 
41
42
  def stop
42
43
  Droonga.logger.trace("#{log_tag}: stop: start")
43
- @message_receiver.shutdown
44
- @loop.stop
44
+ @job_receiver.shutdown
45
+ @raw_loop.stop
46
+ @loop.break_current_loop
45
47
  Droonga.logger.trace("#{log_tag}: stop: done")
46
48
  end
47
49
 
@@ -0,0 +1,27 @@
1
+ {
2
+ "datasets": {
3
+ "Droonga": {
4
+ "schema": {
5
+ "Products": {
6
+ "type": "Hash",
7
+ "keyType": "ShortText",
8
+ "columns": {
9
+ "category": {
10
+ "type": "Scalar",
11
+ "valueType": "ShortText"
12
+ }
13
+ }
14
+ }
15
+ },
16
+ "replicas": [
17
+ {
18
+ "dimension": "category"
19
+ },
20
+ {
21
+ "dimension": "category"
22
+ }
23
+ ]
24
+ }
25
+ }
26
+ }
27
+
@@ -0,0 +1,57 @@
1
+ [
2
+ "droonga.message",
3
+ 0,
4
+ {
5
+ "inReplyTo": "request-id",
6
+ "statusCode": 200,
7
+ "type": "add.result",
8
+ "body": true
9
+ }
10
+ ]
11
+ [
12
+ "droonga.message",
13
+ 0,
14
+ {
15
+ "inReplyTo": "request-id",
16
+ "statusCode": 200,
17
+ "type": "add.result",
18
+ "body": true
19
+ }
20
+ ]
21
+ [
22
+ "droonga.message",
23
+ 0,
24
+ {
25
+ "inReplyTo": "request-id",
26
+ "statusCode": 200,
27
+ "type": "add.result",
28
+ "body": true
29
+ }
30
+ ]
31
+ [
32
+ "droonga.message",
33
+ 0,
34
+ {
35
+ "inReplyTo": "request-id",
36
+ "statusCode": 200,
37
+ "type": "search.result",
38
+ "body": {
39
+ "products": {
40
+ "records": [
41
+ [
42
+ "Groonga",
43
+ "groonga"
44
+ ],
45
+ [
46
+ "Rroonga",
47
+ "groonga"
48
+ ],
49
+ [
50
+ "Ruby",
51
+ "ruby"
52
+ ]
53
+ ]
54
+ }
55
+ }
56
+ }
57
+ ]