droonga-engine 1.0.9 → 1.1.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/benchmark/timer-watcher/benchmark.rb +44 -0
  4. data/bin/droonga-engine-absorb-data +246 -187
  5. data/bin/droonga-engine-catalog-generate +12 -12
  6. data/bin/droonga-engine-catalog-modify +4 -4
  7. data/bin/droonga-engine-join +352 -171
  8. data/bin/droonga-engine-set-role +54 -0
  9. data/bin/droonga-engine-unjoin +107 -112
  10. data/droonga-engine.gemspec +3 -3
  11. data/install.sh +55 -36
  12. data/install/centos/functions.sh +2 -2
  13. data/install/debian/functions.sh +2 -2
  14. data/lib/droonga/address.rb +26 -24
  15. data/lib/droonga/buffered_tcp_socket.rb +65 -10
  16. data/lib/droonga/catalog/base.rb +9 -6
  17. data/lib/droonga/catalog/dataset.rb +17 -41
  18. data/lib/droonga/catalog/fetcher.rb +64 -0
  19. data/lib/droonga/catalog/generator.rb +245 -0
  20. data/lib/droonga/catalog/loader.rb +66 -0
  21. data/lib/droonga/{catalog_modifier.rb → catalog/modifier.rb} +11 -18
  22. data/lib/droonga/catalog/replicas_volume.rb +123 -0
  23. data/lib/droonga/catalog/schema.rb +37 -37
  24. data/lib/droonga/catalog/single_volume.rb +11 -3
  25. data/lib/droonga/catalog/slice.rb +10 -6
  26. data/lib/droonga/catalog/{collection_volume.rb → slices_volume.rb} +47 -11
  27. data/lib/droonga/catalog/version1.rb +47 -19
  28. data/lib/droonga/catalog/version2.rb +11 -10
  29. data/lib/droonga/catalog/version2_validator.rb +4 -4
  30. data/lib/droonga/catalog/volume.rb +17 -5
  31. data/lib/droonga/changable.rb +25 -0
  32. data/lib/droonga/cluster.rb +237 -0
  33. data/lib/droonga/collector_runner.rb +4 -0
  34. data/lib/droonga/collectors.rb +2 -1
  35. data/lib/droonga/collectors/recursive_sum.rb +26 -0
  36. data/lib/droonga/command/droonga_engine.rb +404 -127
  37. data/lib/droonga/command/droonga_engine_service.rb +47 -11
  38. data/lib/droonga/command/droonga_engine_worker.rb +21 -1
  39. data/lib/droonga/command/remote_command_base.rb +78 -0
  40. data/lib/droonga/command/serf_event_handler.rb +29 -20
  41. data/lib/droonga/data_absorber_client.rb +222 -0
  42. data/lib/droonga/database_scanner.rb +106 -0
  43. data/lib/droonga/{live_nodes_list_loader.rb → deferrable.rb} +11 -24
  44. data/lib/droonga/differ.rb +58 -0
  45. data/lib/droonga/dispatcher.rb +155 -32
  46. data/lib/droonga/distributed_command_planner.rb +9 -11
  47. data/lib/droonga/engine.rb +83 -78
  48. data/lib/droonga/engine/version.rb +1 -1
  49. data/lib/droonga/engine_node.rb +301 -0
  50. data/lib/droonga/engine_state.rb +62 -40
  51. data/lib/droonga/farm.rb +44 -5
  52. data/lib/droonga/file_observer.rb +16 -12
  53. data/lib/droonga/fluent_message_receiver.rb +98 -29
  54. data/lib/droonga/fluent_message_sender.rb +30 -23
  55. data/lib/droonga/forward_buffer.rb +160 -0
  56. data/lib/droonga/forwarder.rb +73 -40
  57. data/lib/droonga/handler.rb +7 -6
  58. data/lib/droonga/handler_messenger.rb +15 -6
  59. data/lib/droonga/handler_runner.rb +6 -1
  60. data/lib/droonga/internal_fluent_message_receiver.rb +28 -8
  61. data/lib/droonga/job_pusher.rb +10 -7
  62. data/lib/droonga/job_receiver.rb +6 -4
  63. data/lib/droonga/logger.rb +7 -1
  64. data/lib/droonga/node_name.rb +90 -0
  65. data/lib/droonga/node_role.rb +72 -0
  66. data/lib/droonga/path.rb +34 -9
  67. data/lib/droonga/planner.rb +73 -7
  68. data/lib/droonga/plugin/async_command.rb +154 -0
  69. data/lib/droonga/plugins/catalog.rb +1 -0
  70. data/lib/droonga/plugins/crud.rb +22 -6
  71. data/lib/droonga/plugins/dump.rb +66 -135
  72. data/lib/droonga/plugins/groonga/delete.rb +13 -0
  73. data/lib/droonga/plugins/search/distributed_search_planner.rb +4 -4
  74. data/lib/droonga/plugins/system.rb +5 -26
  75. data/lib/droonga/plugins/system/absorb_data.rb +405 -0
  76. data/lib/droonga/plugins/system/statistics.rb +71 -0
  77. data/lib/droonga/plugins/system/status.rb +53 -0
  78. data/lib/droonga/process_control_protocol.rb +3 -1
  79. data/lib/droonga/process_supervisor.rb +32 -15
  80. data/lib/droonga/reducer.rb +69 -0
  81. data/lib/droonga/safe_file_writer.rb +1 -1
  82. data/lib/droonga/serf.rb +207 -276
  83. data/lib/droonga/serf/agent.rb +228 -0
  84. data/lib/droonga/serf/command.rb +94 -0
  85. data/lib/droonga/serf/downloader.rb +120 -0
  86. data/lib/droonga/serf/remote_command.rb +348 -0
  87. data/lib/droonga/serf/tag.rb +56 -0
  88. data/lib/droonga/service_installation.rb +2 -2
  89. data/lib/droonga/session.rb +49 -1
  90. data/lib/droonga/single_step.rb +6 -11
  91. data/lib/droonga/single_step_definition.rb +32 -1
  92. data/lib/droonga/slice.rb +14 -9
  93. data/lib/droonga/supervisor.rb +27 -20
  94. data/lib/droonga/test/stub_handler_messenger.rb +2 -1
  95. data/lib/droonga/timestamp.rb +69 -0
  96. data/lib/droonga/worker_process_agent.rb +33 -15
  97. data/sample/cluster-state.json +8 -0
  98. data/sample/cluster/Rakefile +30 -6
  99. data/test/command/fixture/integer-key-table.jsons +11 -0
  100. data/test/command/fixture/string-key-table.jsons +11 -0
  101. data/test/command/run-test.rb +4 -0
  102. data/test/command/suite/add/error/invalid-integer.expected +3 -3
  103. data/test/command/suite/add/error/invalid-time.expected +3 -3
  104. data/test/command/suite/add/{minimum.expected → key-integer.expected} +0 -0
  105. data/test/command/suite/add/{minimum.test → key-integer.test} +0 -0
  106. data/test/command/suite/add/key-string.expected +6 -0
  107. data/test/command/suite/add/key-string.test +9 -0
  108. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.expected +6 -0
  109. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.test +9 -0
  110. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.expected +6 -0
  111. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.test +9 -0
  112. data/test/command/suite/add/without-values.expected +6 -0
  113. data/test/command/suite/add/without-values.test +11 -0
  114. data/test/command/suite/dump/column/index.expected +33 -1
  115. data/test/command/suite/dump/column/index.test +1 -0
  116. data/test/command/suite/dump/column/scalar.expected +29 -1
  117. data/test/command/suite/dump/column/scalar.test +1 -0
  118. data/test/command/suite/dump/column/vector.expected +29 -1
  119. data/test/command/suite/dump/column/vector.test +1 -0
  120. data/test/command/suite/dump/record/scalar.catalog.json +12 -0
  121. data/test/command/suite/dump/record/scalar.expected +84 -0
  122. data/test/command/suite/dump/record/scalar.test +16 -0
  123. data/test/command/suite/dump/record/vector/reference.expected +83 -1
  124. data/test/command/suite/dump/record/vector/reference.test +1 -0
  125. data/test/command/suite/dump/table/array.expected +27 -1
  126. data/test/command/suite/dump/table/array.test +1 -0
  127. data/test/command/suite/dump/table/double_array_trie.expected +27 -1
  128. data/test/command/suite/dump/table/double_array_trie.test +1 -0
  129. data/test/command/suite/dump/table/hash.expected +27 -1
  130. data/test/command/suite/dump/table/hash.test +1 -0
  131. data/test/command/suite/dump/table/patricia_trie.expected +27 -1
  132. data/test/command/suite/dump/table/patricia_trie.test +1 -0
  133. data/test/command/suite/groonga/delete/{success.expected → key-integer.expected} +0 -0
  134. data/test/command/suite/groonga/delete/key-integer.test +17 -0
  135. data/test/command/suite/groonga/delete/key-string.expected +19 -0
  136. data/test/command/suite/groonga/delete/{success.test → key-string.test} +4 -6
  137. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.expected +19 -0
  138. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.test +17 -0
  139. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.expected +19 -0
  140. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.test +17 -0
  141. data/test/command/suite/message/error/missing-dataset.test +1 -0
  142. data/test/command/suite/system/absorb-data/records.catalog.json +58 -0
  143. data/test/command/suite/system/absorb-data/records.expected +32 -0
  144. data/test/command/suite/system/absorb-data/records.test +24 -0
  145. data/test/command/suite/system/statistics/object/count/empty.expected +11 -0
  146. data/test/command/suite/system/statistics/object/count/empty.test +12 -0
  147. data/test/command/suite/system/statistics/object/count/per-volume/empty.catalog.json +36 -0
  148. data/test/command/suite/system/statistics/object/count/per-volume/empty.expected +19 -0
  149. data/test/command/suite/system/statistics/object/count/per-volume/empty.test +12 -0
  150. data/test/command/suite/system/statistics/object/count/per-volume/record.catalog.json +40 -0
  151. data/test/command/suite/system/statistics/object/count/per-volume/record.expected +19 -0
  152. data/test/command/suite/system/statistics/object/count/per-volume/record.test +23 -0
  153. data/test/command/suite/system/statistics/object/count/per-volume/schema.catalog.json +40 -0
  154. data/test/command/suite/system/statistics/object/count/per-volume/schema.expected +19 -0
  155. data/test/command/suite/system/statistics/object/count/per-volume/schema.test +13 -0
  156. data/test/command/suite/system/statistics/object/count/record.catalog.json +12 -0
  157. data/test/command/suite/system/statistics/object/count/record.expected +11 -0
  158. data/test/command/suite/system/statistics/object/count/record.test +23 -0
  159. data/test/command/suite/system/statistics/object/count/schema.catalog.json +12 -0
  160. data/test/command/suite/system/statistics/object/count/schema.expected +11 -0
  161. data/test/command/suite/system/statistics/object/count/schema.test +13 -0
  162. data/test/command/suite/system/status.expected +3 -2
  163. data/test/unit/catalog/test_dataset.rb +4 -1
  164. data/test/unit/{test_catalog_generator.rb → catalog/test_generator.rb} +2 -2
  165. data/test/unit/catalog/test_replicas_volume.rb +79 -0
  166. data/test/unit/catalog/test_single_volume.rb +2 -2
  167. data/test/unit/catalog/test_slice.rb +33 -1
  168. data/test/unit/catalog/{test_collection_volume.rb → test_slices_volume.rb} +72 -11
  169. data/test/unit/catalog/test_version2.rb +3 -0
  170. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  171. data/test/unit/plugins/catalog/test_fetch.rb +4 -4
  172. data/test/unit/plugins/crud/test_add.rb +44 -4
  173. data/test/unit/plugins/groonga/test_column_create.rb +4 -4
  174. data/test/unit/plugins/groonga/test_column_list.rb +4 -4
  175. data/test/unit/plugins/groonga/test_column_remove.rb +4 -4
  176. data/test/unit/plugins/groonga/test_column_rename.rb +4 -4
  177. data/test/unit/plugins/groonga/test_delete.rb +73 -10
  178. data/test/unit/plugins/groonga/test_table_create.rb +4 -4
  179. data/test/unit/plugins/groonga/test_table_list.rb +4 -4
  180. data/test/unit/plugins/groonga/test_table_remove.rb +4 -4
  181. data/test/unit/plugins/search/test_handler.rb +4 -4
  182. data/test/unit/plugins/search/test_planner.rb +4 -2
  183. data/test/unit/plugins/system/test_status.rb +31 -15
  184. data/test/unit/plugins/test_watch.rb +16 -16
  185. data/test/unit/test_address.rb +4 -4
  186. metadata +134 -35
  187. data/lib/droonga/catalog/volume_collection.rb +0 -79
  188. data/lib/droonga/catalog_fetcher.rb +0 -53
  189. data/lib/droonga/catalog_generator.rb +0 -243
  190. data/lib/droonga/catalog_loader.rb +0 -56
  191. data/lib/droonga/command/remote.rb +0 -404
  192. data/lib/droonga/data_absorber.rb +0 -264
  193. data/lib/droonga/node_status.rb +0 -71
  194. data/lib/droonga/serf_downloader.rb +0 -115
  195. data/test/unit/catalog/test_volume_collection.rb +0 -78
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f2574dab76722981c14a23373e838f1e01d18220
4
- data.tar.gz: 9776825164dda315f20af0f0d610d2391cce93fd
3
+ metadata.gz: bd5aad47933f58aee93072477c535d458556b183
4
+ data.tar.gz: fc6e82289c99cc3ef4cdc269d0153ca6588dec7f
5
5
  SHA512:
6
- metadata.gz: 55b359cab3e5ca1bd0b7008233c54bbf413d27b97ee8d179ca09be701fa4f2749935cb37eaf743bfb0099600794c80d319edce22bedde28b69f685d944c8f193
7
- data.tar.gz: 09add0504d2886e51065af0c09a4d350db98c8fe07e9a6de6f317ca08af34971016f57c2ac3706d4317df110d125077045c8973c996f4bda382a187cd903ffa0
6
+ metadata.gz: 08909575ab516f97f404396904a53a0920bdc7a6ad7ab8673e7065d681698dee2f7029c71cb74731824892df0eeb87b8de4383d4aa9d0107823e7a00f363a7dc
7
+ data.tar.gz: fc2acfa0c8c133bc70ebad99f7d326e96fcc316fdedfb45347431e5ec3a96a751d4f00db03b9c21c4c44d03d26b8da5b0263615926e9321d50f44c60277f0cf9
@@ -9,6 +9,7 @@ rvm:
9
9
  - 1.9.3
10
10
  - 2.0.0
11
11
  - 2.1
12
+ - 2.2
12
13
  # - ruby-head
13
14
  before_install:
14
15
  # - GROONGA_MASTER=yes curl --silent --location https://raw.github.com/groonga/groonga/master/data/travis/setup.sh | sh
@@ -0,0 +1,44 @@
1
+ require "coolio"
2
+
3
+ $times = 100000
4
+
5
+ def add_timeout_timer(loop)
6
+ timeout_timer = Coolio::TimerWatcher.new(60)
7
+ timeout_timer.on_timer do
8
+ timeout_timer.detach
9
+ timeout_timer = nil
10
+ end
11
+ loop.attach(timeout_timer)
12
+ timeout_timer
13
+ end
14
+
15
+ puts "start."
16
+
17
+ $start = Time.now
18
+ $timers = []
19
+ $loop = Cool.io::Loop.default
20
+ $times.times do
21
+ $timers << add_timeout_timer($loop)
22
+ end
23
+
24
+ $timeout_before = Time.now
25
+ timeout_timer = Coolio::TimerWatcher.new(1)
26
+ timeout_timer.on_timer do
27
+ $timeout_after = Time.now
28
+
29
+ timeout_timer.detach
30
+ $timers.each do |timer|
31
+ timer.detach
32
+ end
33
+
34
+ $finish = Time.now
35
+ delta = $finish - $start
36
+ delta -= $timeout_after - $timeout_before
37
+ puts "done."
38
+ puts "overhead: #{delta} seconds for #{$times} timers."
39
+ end
40
+ $loop.attach(timeout_timer)
41
+
42
+ $loop.run
43
+
44
+
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # Copyright (C) 2014 Droonga Project
3
+ # Copyright (C) 2014-2015 Droonga Project
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
@@ -17,230 +17,289 @@
17
17
 
18
18
  require "ostruct"
19
19
  require "optparse"
20
- require "open3"
21
20
  require "socket"
21
+ require "coolio"
22
22
 
23
23
  require "droonga/engine/version"
24
- require "droonga/catalog_generator"
25
24
  require "droonga/path"
26
- require "droonga/data_absorber"
25
+ require "droonga/node_name"
26
+ require "droonga/data_absorber_client"
27
27
  require "droonga/serf"
28
28
  require "droonga/client"
29
29
 
30
- class AbsorbDataCommand
31
- def run
32
- parse_options
33
- assert_valid_options
34
- trap_signals
35
-
36
- puts "Start to absorb data from #{@options.source_host}"
37
- puts " to #{@options.destination_host}"
38
- puts " via #{@options.receiver_host} (this host)"
39
- puts " dataset = #{@options.dataset}"
40
- puts " port = #{@options.port}"
41
- puts " tag = #{@options.tag}"
42
- puts ""
43
- puts "Absorbing..."
44
-
45
- if @options.remote
46
- absorb_on_remote
47
- else
48
- absorb_on_local
49
- end
30
+ module Droonga
31
+ module Command
32
+ class AbsorbData
33
+ def run
34
+ @loop = Coolio::Loop.default
50
35
 
51
- puts "Done."
52
- exit(true)
53
- end
36
+ parse_options
37
+ assert_valid_options
38
+ trap_signals
54
39
 
55
- private
56
- def parse_options
57
- options = OpenStruct.new
58
- options.port = Droonga::CatalogGenerator::DEFAULT_PORT
59
- options.tag = Droonga::CatalogGenerator::DEFAULT_TAG
60
- options.dataset = Droonga::CatalogGenerator::DEFAULT_DATASET
61
- options.remote = true
62
- options.receiver_host = Socket.gethostname
63
- options.messages_per_second = Droonga::DataAbsorber::DEFAULT_MESSAGES_PER_SECOND
64
- parser = OptionParser.new
65
- parser.version = Droonga::Engine::VERSION
66
-
67
- parser.separator("")
68
- parser.separator("Connection:")
69
- parser.on("--source-host=HOST",
70
- "Host name of the source cluster to be connected.") do |host|
71
- options.source_host = host
72
- end
73
- parser.on("--destination-host=HOST",
74
- "Host name of this cluster to be connected.") do |host|
75
- options.destination_host = host
76
- end
77
- parser.on("--receiver-host=HOST",
78
- "Host name of this computer.",
79
- "(#{options.receiver_host})") do |host|
80
- options.receiver_host = host
81
- end
82
- parser.on("--port=PORT", Integer,
83
- "Port number of the source cluster to be connected.",
84
- "(#{options.port})") do |port|
85
- options.port = port
40
+ puts "Start to absorb data from #{@options.source_dataset} at #{source_node.to_s}"
41
+ puts " to #{@options.dataset} at #{destination_node.to_s}"
42
+ puts " via #{@options.receiver_host} (this host)"
43
+ puts ""
44
+ puts "Absorbing..."
45
+
46
+ #XXX If any command is received by the source node after changing of its role,
47
+ # the timestamp of last processed mesasge is unexpectedly updated by them.
48
+ # Be careful to not send any command to the source node on this timing!!
49
+ update_accept_messages_newer_than_timestamp
50
+
51
+ succeeded = absorb
52
+
53
+ if succeeded
54
+ puts "Done."
55
+ else
56
+ do_cancel
57
+ end
58
+ succeeded
86
59
  end
87
- parser.on("--[no-]remote",
88
- "Run command in remote node or not.",
89
- "(#{options.remote})") do |remote|
90
- options.remote = remote
60
+
61
+ private
62
+ def parse_options
63
+ options = OpenStruct.new
64
+
65
+ options.host = Socket.gethostname
66
+ options.port = DataAbsorberClient::DEFAULT_PORT
67
+ options.tag = DataAbsorberClient::DEFAULT_TAG
68
+ options.dataset = DataAbsorberClient::DEFAULT_DATASET
69
+
70
+ options.source_host = DataAbsorberClient::DEFAULT_HOST
71
+ options.source_port = DataAbsorberClient::DEFAULT_PORT
72
+ options.source_tag = DataAbsorberClient::DEFAULT_TAG
73
+ options.source_dataset = DataAbsorberClient::DEFAULT_DATASET
74
+
75
+ options.receiver_host = Socket.gethostname
76
+
77
+ options.messages_per_second = DataAbsorberClient::DEFAULT_MESSAGES_PER_SECOND
78
+ options.progress_interval_seconds = DataAbsorberClient::DEFAULT_PROGRESS_INTERVAL_SECONDS
79
+
80
+ options.verbose = false
81
+
82
+ parser = OptionParser.new
83
+ parser.version = Engine::VERSION
84
+
85
+ parser.separator("")
86
+ parser.separator("Destination node:")
87
+ parser.on("--host=HOST",
88
+ "Host name of the destination node.") do |host|
89
+ options.host = host
90
+ end
91
+ parser.on("--port=PORT", Integer,
92
+ "Port number of the destination node.",
93
+ "(#{options.port})") do |port|
94
+ options.port = port
95
+ end
96
+ parser.on("--tag=TAG", Integer,
97
+ "Tag name of the destination node.",
98
+ "(#{options.tag})") do |tag|
99
+ options.tag = tag
100
+ end
101
+ parser.on("--dataset=DATASET",
102
+ "Name of the destination dataset.",
103
+ "(#{options.dataset})") do |dataset|
104
+ options.dataset = dataset
105
+ end
106
+
107
+ parser.separator("")
108
+ parser.separator("Source node:")
109
+ parser.on("--source-host=HOST",
110
+ "Host name of the source node.",
111
+ "(#{options.source_host})") do |host|
112
+ options.source_host = host
113
+ end
114
+ parser.on("--source-port=PORT", Integer,
115
+ "Port number of the source node.",
116
+ "(#{options.source_port})") do |host|
117
+ options.source_host = host
118
+ end
119
+ parser.on("--source-tag=TAG",
120
+ "Tag name of the source node.",
121
+ "(#{options.source_tag})") do |tag|
122
+ options.source_tag = tag
123
+ end
124
+ parser.on("--source-dataset=DATASET",
125
+ "Name of the source dataset.",
126
+ "(#{options.source_dataset})") do |dataset|
127
+ options.source_dataset = dataset
128
+ end
129
+
130
+ parser.separator("")
131
+ parser.separator("Connection:")
132
+ parser.on("--receiver-host=HOST",
133
+ "Host name of this computer.",
134
+ "(#{options.receiver_host})") do |host|
135
+ options.receiver_host = host
136
+ end
137
+
138
+ parser.separator("")
139
+ parser.separator("Miscellaneous:")
140
+ parser.on("--records-per-second=N", Integer,
141
+ "Maximum number of records per second to be absorbed.",
142
+ "'#{Client::RateLimiter::NO_LIMIT}' means no limit.",
143
+ "(#{options.messages_per_second})") do |n|
144
+ options.messages_per_second = n
145
+ end
146
+ parser.on("--progress-interval-seconds=N", Integer,
147
+ "Interval seconds to report progress.",
148
+ "(#{options.progress_interval_seconds})") do |n|
149
+ options.progress_interval_seconds = n
150
+ end
151
+ parser.on("--[no-]verbose",
152
+ "Output details for internal operations.",
153
+ "(#{options.verbose})") do |verbose|
154
+ options.verbose = verbose
155
+ end
156
+
157
+ parser.separator("")
158
+ parser.separator("For backward compatibility:")
159
+ parser.on("--destination-host=HOST",
160
+ "Alias to \"--host\".") do |host|
161
+ options.host = host
162
+ end
163
+
164
+ parser.parse!(ARGV)
165
+ @options = options
91
166
  end
92
167
 
93
- parser.separator("")
94
- parser.separator("Data:")
95
- parser.on("--tag=TAG",
96
- "Tag name to be used to communicate with Droonga system.",
97
- "(#{options.tag})") do |tag|
98
- options.tag = tag
168
+ def assert_valid_options
169
+ unless @options.source_host
170
+ raise "You must specify the source host via --source-host option."
171
+ end
172
+ unless @options.host
173
+ raise "You must specify the destination host via --host option."
174
+ end
99
175
  end
100
- parser.on("--dataset=DATASET",
101
- "Dataset to be absorbed.",
102
- "(#{options.dataset})") do |dataset|
103
- options.dataset = dataset
176
+
177
+ def source_node
178
+ @source_node ||= NodeName.new(:host => @options.source_host,
179
+ :port => @options.source_port,
180
+ :tag => @options.source_tag)
104
181
  end
105
- parser.on("--records-per-second=N", Integer,
106
- "Maximum number of records per second to be absorbed.",
107
- "'#{Droonga::Client::RateLimiter::NO_LIMIT}' means no limit.",
108
- "(#{options.messages_per_second})") do |n|
109
- options.messages_per_second = n
182
+
183
+ def destination_node
184
+ @destination_node ||= NodeName.new(:host => @options.host,
185
+ :port => @options.port,
186
+ :tag => @options.tag)
110
187
  end
111
188
 
112
- parser.parse!(ARGV)
113
- @options = options
114
- end
189
+ def source_node_serf
190
+ @source_node_serf ||= Serf.new(source_node.to_s,
191
+ :verbose => @options.verbose)
192
+ end
115
193
 
116
- def assert_valid_options
117
- unless @options.source_host
118
- raise "You must specify the source host via --source-host option."
194
+ def destination_node_serf
195
+ @destination_node_serf ||= Serf.new(destination_node.to_s,
196
+ :verbose => @options.verbose)
119
197
  end
120
- unless @options.destination_host
121
- raise "You must specify the destination host via --destination-host option."
198
+
199
+ def absorber
200
+ @absorber ||= prepare_absorber
122
201
  end
123
- end
124
202
 
125
- def source_node
126
- "#{@options.source_host}:#{@options.port}/#{@options.tag}"
127
- end
203
+ def prepare_absorber
204
+ absorber_options = {
205
+ :host => @options.host,
206
+ :port => @options.port,
207
+ :tag => @options.tag,
208
+ :dataset => @options.dataset,
128
209
 
129
- def destination_node
130
- "#{@options.destination_host}:#{@options.port}/#{@options.tag}"
131
- end
210
+ :source_host => @options.source_host,
211
+ :source_port => @options.source_port,
212
+ :source_tag => @options.source_tag,
213
+ :source_dataset => @options.source_dataset,
132
214
 
133
- def run_remote_command(target, command, options)
134
- serf = Droonga::Serf.new(nil, target)
135
- result = serf.send_query(command, options)
136
- #puts result[:result]
137
- puts result[:error] unless result[:error].empty?
138
- result[:response]
139
- end
215
+ :receiver_host => @options.receiver_host,
140
216
 
141
- def absorber
142
- @absorber ||= prepare_absorber
143
- end
217
+ :messages_per_second => @options.messages_per_second,
218
+ :progress_interval_seconds => @options.progress_interval_seconds,
144
219
 
145
- def prepare_absorber
146
- absorber_options = {
147
- :dataset => @options.dataset,
148
- :source_host => @options.source_host,
149
- :destination_host => @options.destination_host,
150
- :receiver_host => @options.receiver_host,
151
- :port => @options.port,
152
- :tag => @options.tag,
153
- :messages_per_second => @options.messages_per_second,
154
- }
155
- Droonga::DataAbsorber.new(absorber_options)
156
- end
220
+ :client_options => {
221
+ :backend => :coolio,
222
+ :loop => @loop,
223
+ },
224
+ }
225
+ DataAbsorberClient.new(absorber_options)
226
+ end
157
227
 
158
- def absorb_on_remote
159
- start_time_in_seconds = Time.new.to_i
160
- run_remote_command(destination_node, "absorb_data",
161
- "node" => destination_node,
162
- "source" => @options.source_host,
163
- "port" => @options.port,
164
- "tag" => @options.tag,
165
- "dataset" => @options.dataset,
166
- "messages_per_second" => @options.messages_per_second)
167
- last_progress = ""
168
- while true
169
- sleep(3)
170
- response = run_remote_command(destination_node, "report_status",
171
- "node" => destination_node,
172
- "key" => "absorbing")
173
- if response
174
- absorbing = response["value"]
175
- break unless absorbing
176
- end
177
-
178
- progress = absorber.report_progress(start_time_in_seconds)
179
- if progress
180
- printf("%s", "#{" " * last_progress.size}\r")
181
- printf("%s", "#{progress}\r")
228
+ def absorb
229
+ last_progress = nil
230
+ absorber.run do |progress|
231
+ if last_progress
232
+ printf("%s", "#{" " * last_progress[:message].size}\r")
233
+ end
234
+ printf("%s", "#{progress[:message]}\r")
182
235
  last_progress = progress
183
236
  end
237
+ @loop.run
238
+
239
+ if absorber.error_message
240
+ puts(absorber.error_message)
241
+ return false
242
+ end
243
+
244
+ puts ""
245
+ true
184
246
  end
185
- puts ""
186
-
187
- response = run_remote_command(source_node, "report_status",
188
- "node" => source_node,
189
- "key" => "last_processed_message_timestamp")
190
- timestamp = response["value"]
191
- if timestamp and not timestamp.empty?
192
- puts "The timestamp of the last processed message in the source node: #{timestamp}"
193
- puts "Setting effective message timestamp for the destination node..."
194
- response = run_remote_command(destination_node, "set_status",
195
- "node" => destination_node,
196
- "key" => "effective_message_timestamp",
197
- "value" => timestamp)
247
+
248
+ GETTING_LAST_MESSAGE_TIMESTAMP_MAX_RETRY_COUNT = 10
249
+ GETTING_LAST_MESSAGE_TIMESTAMP_RETRY_INTERVAL_SECONDS = 10
250
+
251
+ def try_get_last_message_timestamp(retry_count=0)
252
+ puts "Getting the timestamp of the last processed message in the source node..."
253
+ timestamp = source_node_serf.last_message_timestamp
254
+ unless timestamp
255
+ if retry_count < GETTING_LAST_MESSAGE_TIMESTAMP_MAX_RETRY_COUNT
256
+ puts "Failed. Retrying..."
257
+ sleep(GETTING_LAST_MESSAGE_TIMESTAMP_RETRY_INTERVAL_SECONDS)
258
+ timestamp = try_get_last_message_timestamp(retry_count + 1)
259
+ end
260
+ end
261
+ timestamp
198
262
  end
199
- end
200
263
 
201
- def absorb_on_local
202
- last_progress = ""
203
- absorber.absorb do |live_status|
204
- if live_status[:progress]
205
- progress = live_status[:progress]
264
+ def update_accept_messages_newer_than_timestamp
265
+ timestamp = try_get_last_message_timestamp
266
+ if timestamp and not timestamp.empty?
267
+ puts "The timestamp of the last processed message in the source node: #{timestamp}"
268
+ puts "Setting the destination node to ignore messages older than the timestamp..."
269
+ destination_node_serf.ensure_restarted do
270
+ destination_node_serf.send_query("accept_messages_newer_than",
271
+ "node" => destination_node.to_s,
272
+ "timestamp" => timestamp)
273
+ end
206
274
  else
207
- progress = live_status[:output]
275
+ $stderr.puts("WARNING: Couldn't get the time stamp of " +
276
+ "the last processed message from the source node. " +
277
+ "Any message will be forwarded to the destination node.")
208
278
  end
209
- printf("%s", "#{" " * last_progress.size}\r")
210
- printf("%s", "#{progress}\r")
211
- last_progress = progress
212
279
  end
213
- response = run_remote_command(source_node, "report_status",
214
- "node" => source_node,
215
- "key" => "last_processed_message_timestamp")
216
- timestamp = response["value"]
217
- puts "The timestamp of the last processed message in the source node: #{timestamp}"
218
- if timestamp and not timestamp.empty?
219
- status = NodeStatus.new
220
- status.set(:effective_message_timestamp, timestamp)
221
- end
222
- end
223
280
 
224
- def trap_signals
225
- trap(:TERM) do
226
- do_cancel
227
- trap(:TERM, "DEFAULT")
228
- end
281
+ def trap_signals
282
+ trap(:TERM) do
283
+ trap(:TERM, "DEFAULT")
284
+ do_cancel
285
+ end
229
286
 
230
- trap(:INT) do
231
- do_cancel
232
- trap(:INT, "DEFAULT")
233
- end
287
+ trap(:INT) do
288
+ trap(:INT, "DEFAULT")
289
+ do_cancel
290
+ end
234
291
 
235
- trap(:QUIT) do
236
- do_cancel
237
- trap(:QUIT, "DEFAULT")
292
+ trap(:QUIT) do
293
+ trap(:QUIT, "DEFAULT")
294
+ do_cancel
295
+ end
238
296
  end
239
- end
240
297
 
241
- def do_cancel
242
- #XXX we have to write more codes to cancel remote processes!
298
+ def do_cancel
299
+ #XXX we have to write more codes to cancel remote processes!
300
+ end
301
+ end
243
302
  end
244
303
  end
245
304
 
246
- AbsorbDataCommand.new.run
305
+ exit(Droonga::Command::AbsorbData.new.run)