fluent-plugin-droonga 0.9.9 → 1.0.0

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.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.dir-locals.el +3 -0
  3. data/.travis.yml +6 -2
  4. data/README.md +6 -7
  5. data/Rakefile +23 -6
  6. data/fluent-plugin-droonga.gemspec +2 -2
  7. data/lib/droonga/adapter.rb +12 -3
  8. data/lib/droonga/adapter_runner.rb +28 -23
  9. data/lib/droonga/catalog/base.rb +7 -111
  10. data/lib/droonga/catalog/dataset.rb +13 -25
  11. data/lib/droonga/catalog/errors.rb +94 -0
  12. data/lib/droonga/catalog/schema.rb +277 -0
  13. data/lib/droonga/catalog/version1.rb +404 -0
  14. data/lib/droonga/catalog/version2.rb +160 -0
  15. data/lib/droonga/catalog_loader.rb +27 -4
  16. data/lib/droonga/catalog_observer.rb +44 -6
  17. data/lib/droonga/collector.rb +12 -10
  18. data/lib/droonga/{handler_plugin.rb → collector_message.rb} +47 -20
  19. data/lib/droonga/collector_runner.rb +64 -0
  20. data/lib/droonga/collectors.rb +18 -0
  21. data/lib/droonga/{catalog.rb → collectors/add.rb} +9 -7
  22. data/lib/droonga/{command_repository.rb → collectors/and.rb} +7 -14
  23. data/lib/droonga/collectors/sum.rb +26 -0
  24. data/lib/droonga/dispatcher.rb +74 -41
  25. data/lib/droonga/distributed_command_planner.rb +2 -2
  26. data/lib/droonga/engine.rb +13 -5
  27. data/lib/droonga/{message_processing_error.rb → error.rb} +33 -12
  28. data/lib/droonga/{plugin/planner/search.rb → error_messages.rb} +12 -10
  29. data/lib/droonga/farm.rb +15 -14
  30. data/lib/droonga/fluent_message_sender.rb +15 -11
  31. data/lib/droonga/forwarder.rb +22 -18
  32. data/lib/droonga/handler.rb +8 -2
  33. data/lib/droonga/handler_runner.rb +47 -26
  34. data/lib/droonga/input_message.rb +6 -6
  35. data/lib/droonga/{command.rb → loggable.rb} +7 -14
  36. data/lib/droonga/logger.rb +56 -15
  37. data/lib/droonga/message_matcher.rb +12 -7
  38. data/lib/droonga/message_pusher.rb +8 -4
  39. data/lib/droonga/message_receiver.rb +11 -9
  40. data/lib/droonga/output_message.rb +2 -0
  41. data/lib/droonga/planner.rb +21 -10
  42. data/lib/droonga/plugin.rb +15 -0
  43. data/lib/droonga/plugin/metadata/{adapter_message.rb → adapter_input_message.rb} +6 -14
  44. data/lib/droonga/plugin/metadata/adapter_output_message.rb +39 -0
  45. data/lib/droonga/plugin/metadata/collector_message.rb +39 -0
  46. data/lib/droonga/plugin/metadata/input_message.rb +15 -0
  47. data/lib/droonga/plugin_loader.rb +33 -25
  48. data/lib/droonga/plugin_registry.rb +9 -1
  49. data/lib/droonga/plugins/basic.rb +54 -0
  50. data/lib/droonga/plugins/crud.rb +36 -15
  51. data/lib/droonga/plugins/error.rb +5 -4
  52. data/lib/droonga/plugins/groonga.rb +9 -6
  53. data/lib/droonga/plugins/groonga/column_create.rb +10 -5
  54. data/lib/droonga/plugins/groonga/generic_command.rb +2 -8
  55. data/lib/droonga/plugins/groonga/generic_response.rb +2 -2
  56. data/lib/droonga/plugins/groonga/select.rb +2 -2
  57. data/lib/droonga/plugins/groonga/table_create.rb +9 -4
  58. data/lib/droonga/plugins/groonga/table_remove.rb +10 -5
  59. data/lib/droonga/plugins/search.rb +106 -5
  60. data/lib/droonga/plugins/search/distributed_search_planner.rb +398 -0
  61. data/lib/droonga/plugins/watch.rb +41 -20
  62. data/lib/droonga/processor.rb +12 -9
  63. data/lib/droonga/{plugin/collector/basic.rb → reducer.rb} +36 -50
  64. data/lib/droonga/replier.rb +7 -4
  65. data/lib/droonga/searcher.rb +40 -37
  66. data/lib/droonga/server.rb +8 -6
  67. data/lib/droonga/session.rb +17 -7
  68. data/lib/droonga/single_step.rb +53 -0
  69. data/lib/droonga/{plugin/planner/watch.rb → single_step_definition.rb} +27 -26
  70. data/lib/droonga/{partition.rb → slice.rb} +23 -12
  71. data/lib/droonga/status_code.rb +25 -0
  72. data/lib/droonga/step_runner.rb +63 -0
  73. data/lib/droonga/watch_schema.rb +7 -3
  74. data/lib/droonga/watcher.rb +4 -4
  75. data/lib/droonga/worker.rb +6 -6
  76. data/lib/fluent/plugin/out_droonga.rb +27 -2
  77. data/sample/cluster/catalog.json +33 -32
  78. data/test/command/config/default/catalog.json +72 -45
  79. data/test/command/config/version1/catalog.json +68 -0
  80. data/test/command/config/version1/fluentd.conf +11 -0
  81. data/test/command/suite/message/error/missing-dataset.expected +1 -1
  82. data/test/command/suite/message/error/unknown-dataset.expected +1 -1
  83. data/test/command/suite/message/error/unknown-type.expected +13 -0
  84. data/test/command/suite/message/error/{unknown-command.test → unknown-type.test} +1 -1
  85. data/test/command/suite/search/error/missing-source-parameter.expected +1 -1
  86. data/test/command/suite/search/error/unknown-source.expected +15 -3
  87. data/test/command/suite/watch/subscribe.expected +1 -3
  88. data/test/command/suite/watch/unsubscribe.expected +1 -3
  89. data/test/performance/watch/catalog.json +1 -0
  90. data/test/unit/catalog/test_dataset.rb +16 -358
  91. data/test/unit/catalog/test_schema.rb +285 -0
  92. data/test/unit/catalog/test_version1.rb +222 -28
  93. data/test/unit/catalog/test_version2.rb +155 -0
  94. data/test/unit/fixtures/catalog/version2.json +62 -0
  95. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  96. data/test/unit/plugins/crud/test_add.rb +13 -13
  97. data/test/unit/plugins/groonga/test_column_create.rb +14 -11
  98. data/test/unit/plugins/groonga/test_table_create.rb +4 -9
  99. data/test/unit/plugins/groonga/test_table_remove.rb +4 -9
  100. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_basic.rb +0 -0
  101. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_group_by.rb +0 -0
  102. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_output.rb +0 -0
  103. data/test/unit/{plugin/planner/search_planner → plugins/search/planner}/test_sort_by.rb +0 -0
  104. data/test/unit/{plugin/collector/test_search.rb → plugins/search/test_collector.rb} +40 -39
  105. data/test/unit/plugins/{test_search.rb → search/test_handler.rb} +6 -5
  106. data/test/unit/{plugin/planner/test_search.rb → plugins/search/test_planner.rb} +3 -3
  107. data/test/unit/{plugin/collector → plugins}/test_basic.rb +68 -50
  108. data/test/unit/plugins/test_groonga.rb +2 -15
  109. data/test/unit/plugins/test_watch.rb +25 -22
  110. data/test/unit/test_message_matcher.rb +29 -6
  111. data/test/unit/test_output.rb +4 -0
  112. metadata +58 -50
  113. data/lib/droonga/collector_plugin.rb +0 -50
  114. data/lib/droonga/legacy_pluggable.rb +0 -66
  115. data/lib/droonga/legacy_plugin.rb +0 -57
  116. data/lib/droonga/legacy_plugin_repository.rb +0 -54
  117. data/lib/droonga/planner_plugin.rb +0 -54
  118. data/lib/droonga/plugin/collector/search.rb +0 -98
  119. data/lib/droonga/plugin/planner/crud.rb +0 -49
  120. data/lib/droonga/plugin/planner/distributed_search_planner.rb +0 -393
  121. data/lib/droonga/plugin/planner/groonga.rb +0 -54
  122. data/lib/droonga/plugin_registerable.rb +0 -75
  123. data/test/command/suite/message/error/unknown-command.expected +0 -13
  124. data/test/unit/test_command_repository.rb +0 -39
  125. data/test/unit/test_legacy_plugin.rb +0 -50
  126. data/test/unit/test_legacy_plugin_repository.rb +0 -89
@@ -0,0 +1,160 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "droonga/catalog/base"
17
+ require "droonga/catalog/dataset"
18
+
19
+ module Droonga
20
+ module Catalog
21
+ class Version2 < Base
22
+ def initialize(data, path)
23
+ super
24
+ prepare_data
25
+ end
26
+
27
+ def datasets
28
+ @datasets
29
+ end
30
+
31
+ def slices(name)
32
+ device = "."
33
+ pattern = Regexp.new("^#{name}\.")
34
+ results = {}
35
+ @datasets.each do |dataset_name, dataset|
36
+ n_workers = dataset["nWorkers"]
37
+ plugins = dataset["plugins"]
38
+ dataset["replicas"].each do |replica|
39
+ replica["slices"].each do |slice|
40
+ volume_address = slice["volume"]["address"]
41
+ if pattern =~ volume_address
42
+ path = File.join([device, $POSTMATCH, "db"])
43
+ path = File.expand_path(path, base_path)
44
+ options = {
45
+ :dataset => dataset_name,
46
+ :database => path,
47
+ :n_workers => n_workers,
48
+ :plugins => plugins
49
+ }
50
+ results[volume_address] = options
51
+ end
52
+ end
53
+ end
54
+ end
55
+ results
56
+ end
57
+
58
+ def get_routes(name, args)
59
+ routes = []
60
+ dataset = dataset(name)
61
+ case args["type"]
62
+ when "broadcast"
63
+ replicas = select_replicas(dataset["replicas"], args["replica"])
64
+ replicas.each do |replica|
65
+ slices = select_slices(replica)
66
+ slices.each do |slice|
67
+ routes << slice["volume"]["address"]
68
+ end
69
+ end
70
+ when "scatter"
71
+ replicas = select_replicas(dataset["replicas"], args["replica"])
72
+ replicas.each do |replica|
73
+ slice = select_slice(replica, args["key"])
74
+ routes << slice["volume"]["address"]
75
+ end
76
+ end
77
+ routes
78
+ end
79
+
80
+ private
81
+ def validate
82
+ # TODO: Implement me.
83
+ end
84
+
85
+ def prepare_data
86
+ @datasets = {}
87
+ @data["datasets"].each do |name, dataset|
88
+ replicas = dataset["replicas"]
89
+ replicas.each do |replica|
90
+ total_weight = compute_total_weight(replica)
91
+ continuum = []
92
+ slices = replica["slices"]
93
+ n_slices = slices.size
94
+ slices.each do |slice|
95
+ weight = slice["weight"] || default_weight
96
+ points = n_slices * 160 * weight / total_weight
97
+ points.times do |point|
98
+ hash = Digest::SHA1.hexdigest("#{name}:#{point}")
99
+ continuum << [hash[0..7].to_i(16), slice]
100
+ end
101
+ end
102
+ replica["continuum"] = continuum.sort do |a, b|
103
+ a[0] - b[0]
104
+ end
105
+ end
106
+ @datasets[name] = Dataset.new(name, dataset)
107
+ end
108
+ end
109
+
110
+ def default_weight
111
+ 1
112
+ end
113
+
114
+ def compute_total_weight(replica)
115
+ slices = replica["slices"]
116
+ slices.reduce(0) do |result, slice|
117
+ result + (slice["weight"] || default_weight)
118
+ end
119
+ end
120
+
121
+ def select_replicas(replicas, how)
122
+ case how
123
+ when "top"
124
+ [replicas.first]
125
+ when "random"
126
+ [replicas.sample]
127
+ when "all"
128
+ replicas
129
+ end
130
+ end
131
+
132
+ def select_slices(replica, range=0..-1)
133
+ sorted_slices = replica["slices"].sort_by do |slice|
134
+ slice["label"]
135
+ end
136
+ sorted_slices[range]
137
+ end
138
+
139
+ def select_slice(replica, key)
140
+ continuum = replica["continuum"]
141
+ return replica["slices"].first unless continuum
142
+
143
+ hash = Zlib.crc32(key)
144
+ min = 0
145
+ max = continuum.size - 1
146
+ while (min < max) do
147
+ index = (min + max) / 2
148
+ value, key = continuum[index]
149
+ return key if value == hash
150
+ if value > hash
151
+ max = index
152
+ else
153
+ min = index + 1
154
+ end
155
+ end
156
+ continuum[max][1]
157
+ end
158
+ end
159
+ end
160
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013 Droonga Project
1
+ # Copyright (C) 2013-2014 Droonga Project
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -16,6 +16,7 @@
16
16
  require "json"
17
17
 
18
18
  require "droonga/catalog/version1"
19
+ require "droonga/catalog/version2"
19
20
 
20
21
  module Droonga
21
22
  class CatalogLoader
@@ -24,10 +25,32 @@ module Droonga
24
25
  end
25
26
 
26
27
  def load
27
- data = File.open(@path) do |file|
28
- JSON.parse(file.read)
28
+ data = nil
29
+ begin
30
+ data = File.open(@path) do |file|
31
+ JSON.parse(file.read)
32
+ end
33
+ rescue Errno::ENOENT => error
34
+ raise Error.new("Missing catalog file #{@path}")
35
+ rescue JSON::ParserError => error
36
+ raise Error.new("Syntax error in #{@path}:\n#{error.to_s}")
37
+ end
38
+
39
+ unless data.is_a?(Hash)
40
+ raise Error.new("Root element of catalog must be an object in #{@path}")
41
+ end
42
+
43
+ version = data["version"]
44
+ case version
45
+ when 1
46
+ Catalog::Version1.new(data, @path)
47
+ when 2
48
+ Catalog::Version2.new(data, @path)
49
+ when nil
50
+ raise Error.new("Catalog version must be specified in #{@path}")
51
+ else
52
+ raise Error.new("Unsupported catalog version <#{version}> is specified in #{@path}")
29
53
  end
30
- Catalog::Version1.new(data, File.dirname(@path))
31
54
  end
32
55
  end
33
56
  end
@@ -15,15 +15,42 @@
15
15
  # License along with this library; if not, write to the Free Software
16
16
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
 
18
+ require "droonga/loggable"
19
+ require "droonga/catalog_loader"
20
+
18
21
  module Droonga
19
22
  class CatalogObserver
23
+ include Loggable
24
+
20
25
  DEFAULT_CATALOG_PATH = "catalog.json"
21
26
  CHECK_INTERVAL = 1
22
27
 
23
- def initialize(loop)
28
+ attr_reader :catalog
29
+ attr_accessor :on_reload
30
+
31
+ def initialize
24
32
  @catalog_path = catalog_path
25
- load_catalog
33
+ load_catalog!
34
+ end
26
35
 
36
+ def start
37
+ @loop = Cool.io::Loop.new
38
+ attach(@loop)
39
+ @thread = Thread.new do
40
+ begin
41
+ @loop.run
42
+ rescue => error
43
+ logger.exception("error in catalog observing thread", error)
44
+ end
45
+ end
46
+ end
47
+
48
+ def stop
49
+ @loop.stop
50
+ @thread.join
51
+ end
52
+
53
+ def attach(loop)
27
54
  watcher = Cool.io::TimerWatcher.new(CHECK_INTERVAL, true)
28
55
  observer = self
29
56
  watcher.on_timer do
@@ -34,7 +61,12 @@ module Droonga
34
61
 
35
62
  def ensure_latest_catalog_loaded
36
63
  if catalog_updated?
37
- load_catalog
64
+ begin
65
+ load_catalog!
66
+ on_reload.call(catalog) if on_reload
67
+ rescue Droonga::Error => error
68
+ logger.warn("reload: fail", :path => @catalog_path, :error => error)
69
+ end
38
70
  end
39
71
  end
40
72
 
@@ -47,11 +79,17 @@ module Droonga
47
79
  File.mtime(catalog_path) > @catalog_mtime
48
80
  end
49
81
 
50
- def load_catalog
82
+ def load_catalog!
51
83
  loader = CatalogLoader.new(@catalog_path)
52
- Droonga.catalog = loader.load
84
+ @catalog = loader.load
85
+ logger.info("loaded", :path => @catalog_path, :mtime => @catalog_mtime)
86
+ ensure
53
87
  @catalog_mtime = File.mtime(@catalog_path)
54
- $log.info "catalog loaded", path: @catalog_path, mtime: @catalog_mtime
88
+ end
89
+
90
+ private
91
+ def log_tag
92
+ "catalog-observer"
55
93
  end
56
94
  end
57
95
  end
@@ -13,24 +13,26 @@
13
13
  # License along with this library; if not, write to the Free Software
14
14
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
15
 
16
- require "droonga/legacy_pluggable"
17
- require "droonga/collector_plugin"
16
+ require "droonga/pluggable"
17
+ require "droonga/plugin/metadata/collector_message"
18
+ require "droonga/error_messages"
18
19
 
19
20
  module Droonga
20
21
  class Collector
21
- include LegacyPluggable
22
+ extend Pluggable
23
+ include ErrorMessages
22
24
 
23
- def initialize(plugins)
24
- load_plugins(plugins)
25
+ class << self
26
+ def message
27
+ Plugin::Metadata::CollectorMessage.new(self)
28
+ end
25
29
  end
26
30
 
27
- private
28
- def instantiate_plugin(name)
29
- CollectorPlugin.repository.instantiate(name)
31
+ def initialize
30
32
  end
31
33
 
32
- def log_tag
33
- "collector"
34
+ def collect(message)
35
+ raise NotImplemented, "#{self.class.name}\##{__method__} must implement."
34
36
  end
35
37
  end
36
38
  end
@@ -1,6 +1,4 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2013 Droonga Project
1
+ # Copyright (C) 2014 Droonga Project
4
2
  #
5
3
  # This library is free software; you can redistribute it and/or
6
4
  # modify it under the terms of the GNU Lesser General Public
@@ -15,30 +13,59 @@
15
13
  # License along with this library; if not, write to the Free Software
16
14
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
15
 
18
- require "droonga/legacy_plugin"
19
- require "droonga/message_processing_error"
20
-
21
16
  module Droonga
22
- class HandlerPlugin < LegacyPlugin
23
- extend PluginRegisterable
17
+ class CollectorMessage
18
+ attr_reader :raw
19
+ def initialize(raw)
20
+ @raw = raw
21
+ end
22
+
23
+ def valid?
24
+ task and step and values
25
+ end
24
26
 
25
- def initialize(handler)
26
- super()
27
- @handler = handler
28
- @context = @handler.context
27
+ def [](key)
28
+ @raw[key]
29
29
  end
30
30
 
31
- def prefer_synchronous?(command)
32
- false
31
+ def task
32
+ @raw["task"]
33
33
  end
34
34
 
35
- private
36
- def run_command(command, message, messenger)
37
- begin
38
- super
39
- rescue MessageProcessingError => error
40
- messenger.error(error.status_code, error.response_body)
35
+ def step
36
+ task["step"]
37
+ end
38
+
39
+ def type
40
+ step["type"]
41
+ end
42
+
43
+ def values
44
+ task["values"]
45
+ end
46
+
47
+ def body
48
+ step["body"]
49
+ end
50
+
51
+ def input
52
+ if body
53
+ body[name]
54
+ else
55
+ nil
41
56
  end
42
57
  end
58
+
59
+ def outputs
60
+ step["outputs"]
61
+ end
62
+
63
+ def name
64
+ @raw["name"]
65
+ end
66
+
67
+ def value
68
+ @raw["value"]
69
+ end
43
70
  end
44
71
  end
@@ -0,0 +1,64 @@
1
+ # Copyright (C) 2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "droonga/loggable"
17
+ require "droonga/message_matcher"
18
+ require "droonga/collector"
19
+ require "droonga/collector_message"
20
+
21
+ module Droonga
22
+ class CollectorRunner
23
+ include Loggable
24
+
25
+ def initialize(plugins)
26
+ default_plugins = ["basic"]
27
+ plugins += (default_plugins - plugins)
28
+ @collector_classes = Collector.find_sub_classes(plugins)
29
+ end
30
+
31
+ def shutdown
32
+ end
33
+
34
+ def collect(message)
35
+ collector_message = CollectorMessage.new(message)
36
+ logger.trace("collect: start",
37
+ :type => collector_message.type)
38
+ collector_class = find_collector_class(message)
39
+ if collector_class.nil?
40
+ raise UnsupportedMessageError.new(:collector, message)
41
+ end
42
+ collector = collector_class.new
43
+ collector.collect(collector_message)
44
+ logger.trace("collector: done")
45
+ end
46
+
47
+ private
48
+ def find_collector_class(message)
49
+ @collector_classes.find do |collector_class|
50
+ pattern = collector_class.message.pattern
51
+ if pattern
52
+ matcher = MessageMatcher.new(pattern)
53
+ matcher.match?(message)
54
+ else
55
+ false
56
+ end
57
+ end
58
+ end
59
+
60
+ def log_tag
61
+ "collector-runner"
62
+ end
63
+ end
64
+ end