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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/benchmark/timer-watcher/benchmark.rb +44 -0
- data/bin/droonga-engine-absorb-data +246 -187
- data/bin/droonga-engine-catalog-generate +12 -12
- data/bin/droonga-engine-catalog-modify +4 -4
- data/bin/droonga-engine-join +352 -171
- data/bin/droonga-engine-set-role +54 -0
- data/bin/droonga-engine-unjoin +107 -112
- data/droonga-engine.gemspec +3 -3
- data/install.sh +55 -36
- data/install/centos/functions.sh +2 -2
- data/install/debian/functions.sh +2 -2
- data/lib/droonga/address.rb +26 -24
- data/lib/droonga/buffered_tcp_socket.rb +65 -10
- data/lib/droonga/catalog/base.rb +9 -6
- data/lib/droonga/catalog/dataset.rb +17 -41
- data/lib/droonga/catalog/fetcher.rb +64 -0
- data/lib/droonga/catalog/generator.rb +245 -0
- data/lib/droonga/catalog/loader.rb +66 -0
- data/lib/droonga/{catalog_modifier.rb → catalog/modifier.rb} +11 -18
- data/lib/droonga/catalog/replicas_volume.rb +123 -0
- data/lib/droonga/catalog/schema.rb +37 -37
- data/lib/droonga/catalog/single_volume.rb +11 -3
- data/lib/droonga/catalog/slice.rb +10 -6
- data/lib/droonga/catalog/{collection_volume.rb → slices_volume.rb} +47 -11
- data/lib/droonga/catalog/version1.rb +47 -19
- data/lib/droonga/catalog/version2.rb +11 -10
- data/lib/droonga/catalog/version2_validator.rb +4 -4
- data/lib/droonga/catalog/volume.rb +17 -5
- data/lib/droonga/changable.rb +25 -0
- data/lib/droonga/cluster.rb +237 -0
- data/lib/droonga/collector_runner.rb +4 -0
- data/lib/droonga/collectors.rb +2 -1
- data/lib/droonga/collectors/recursive_sum.rb +26 -0
- data/lib/droonga/command/droonga_engine.rb +404 -127
- data/lib/droonga/command/droonga_engine_service.rb +47 -11
- data/lib/droonga/command/droonga_engine_worker.rb +21 -1
- data/lib/droonga/command/remote_command_base.rb +78 -0
- data/lib/droonga/command/serf_event_handler.rb +29 -20
- data/lib/droonga/data_absorber_client.rb +222 -0
- data/lib/droonga/database_scanner.rb +106 -0
- data/lib/droonga/{live_nodes_list_loader.rb → deferrable.rb} +11 -24
- data/lib/droonga/differ.rb +58 -0
- data/lib/droonga/dispatcher.rb +155 -32
- data/lib/droonga/distributed_command_planner.rb +9 -11
- data/lib/droonga/engine.rb +83 -78
- data/lib/droonga/engine/version.rb +1 -1
- data/lib/droonga/engine_node.rb +301 -0
- data/lib/droonga/engine_state.rb +62 -40
- data/lib/droonga/farm.rb +44 -5
- data/lib/droonga/file_observer.rb +16 -12
- data/lib/droonga/fluent_message_receiver.rb +98 -29
- data/lib/droonga/fluent_message_sender.rb +30 -23
- data/lib/droonga/forward_buffer.rb +160 -0
- data/lib/droonga/forwarder.rb +73 -40
- data/lib/droonga/handler.rb +7 -6
- data/lib/droonga/handler_messenger.rb +15 -6
- data/lib/droonga/handler_runner.rb +6 -1
- data/lib/droonga/internal_fluent_message_receiver.rb +28 -8
- data/lib/droonga/job_pusher.rb +10 -7
- data/lib/droonga/job_receiver.rb +6 -4
- data/lib/droonga/logger.rb +7 -1
- data/lib/droonga/node_name.rb +90 -0
- data/lib/droonga/node_role.rb +72 -0
- data/lib/droonga/path.rb +34 -9
- data/lib/droonga/planner.rb +73 -7
- data/lib/droonga/plugin/async_command.rb +154 -0
- data/lib/droonga/plugins/catalog.rb +1 -0
- data/lib/droonga/plugins/crud.rb +22 -6
- data/lib/droonga/plugins/dump.rb +66 -135
- data/lib/droonga/plugins/groonga/delete.rb +13 -0
- data/lib/droonga/plugins/search/distributed_search_planner.rb +4 -4
- data/lib/droonga/plugins/system.rb +5 -26
- data/lib/droonga/plugins/system/absorb_data.rb +405 -0
- data/lib/droonga/plugins/system/statistics.rb +71 -0
- data/lib/droonga/plugins/system/status.rb +53 -0
- data/lib/droonga/process_control_protocol.rb +3 -1
- data/lib/droonga/process_supervisor.rb +32 -15
- data/lib/droonga/reducer.rb +69 -0
- data/lib/droonga/safe_file_writer.rb +1 -1
- data/lib/droonga/serf.rb +207 -276
- data/lib/droonga/serf/agent.rb +228 -0
- data/lib/droonga/serf/command.rb +94 -0
- data/lib/droonga/serf/downloader.rb +120 -0
- data/lib/droonga/serf/remote_command.rb +348 -0
- data/lib/droonga/serf/tag.rb +56 -0
- data/lib/droonga/service_installation.rb +2 -2
- data/lib/droonga/session.rb +49 -1
- data/lib/droonga/single_step.rb +6 -11
- data/lib/droonga/single_step_definition.rb +32 -1
- data/lib/droonga/slice.rb +14 -9
- data/lib/droonga/supervisor.rb +27 -20
- data/lib/droonga/test/stub_handler_messenger.rb +2 -1
- data/lib/droonga/timestamp.rb +69 -0
- data/lib/droonga/worker_process_agent.rb +33 -15
- data/sample/cluster-state.json +8 -0
- data/sample/cluster/Rakefile +30 -6
- data/test/command/fixture/integer-key-table.jsons +11 -0
- data/test/command/fixture/string-key-table.jsons +11 -0
- data/test/command/run-test.rb +4 -0
- data/test/command/suite/add/error/invalid-integer.expected +3 -3
- data/test/command/suite/add/error/invalid-time.expected +3 -3
- data/test/command/suite/add/{minimum.expected → key-integer.expected} +0 -0
- data/test/command/suite/add/{minimum.test → key-integer.test} +0 -0
- data/test/command/suite/add/key-string.expected +6 -0
- data/test/command/suite/add/key-string.test +9 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.expected +6 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.test +9 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.expected +6 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.test +9 -0
- data/test/command/suite/add/without-values.expected +6 -0
- data/test/command/suite/add/without-values.test +11 -0
- data/test/command/suite/dump/column/index.expected +33 -1
- data/test/command/suite/dump/column/index.test +1 -0
- data/test/command/suite/dump/column/scalar.expected +29 -1
- data/test/command/suite/dump/column/scalar.test +1 -0
- data/test/command/suite/dump/column/vector.expected +29 -1
- data/test/command/suite/dump/column/vector.test +1 -0
- data/test/command/suite/dump/record/scalar.catalog.json +12 -0
- data/test/command/suite/dump/record/scalar.expected +84 -0
- data/test/command/suite/dump/record/scalar.test +16 -0
- data/test/command/suite/dump/record/vector/reference.expected +83 -1
- data/test/command/suite/dump/record/vector/reference.test +1 -0
- data/test/command/suite/dump/table/array.expected +27 -1
- data/test/command/suite/dump/table/array.test +1 -0
- data/test/command/suite/dump/table/double_array_trie.expected +27 -1
- data/test/command/suite/dump/table/double_array_trie.test +1 -0
- data/test/command/suite/dump/table/hash.expected +27 -1
- data/test/command/suite/dump/table/hash.test +1 -0
- data/test/command/suite/dump/table/patricia_trie.expected +27 -1
- data/test/command/suite/dump/table/patricia_trie.test +1 -0
- data/test/command/suite/groonga/delete/{success.expected → key-integer.expected} +0 -0
- data/test/command/suite/groonga/delete/key-integer.test +17 -0
- data/test/command/suite/groonga/delete/key-string.expected +19 -0
- data/test/command/suite/groonga/delete/{success.test → key-string.test} +4 -6
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.expected +19 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.test +17 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.expected +19 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.test +17 -0
- data/test/command/suite/message/error/missing-dataset.test +1 -0
- data/test/command/suite/system/absorb-data/records.catalog.json +58 -0
- data/test/command/suite/system/absorb-data/records.expected +32 -0
- data/test/command/suite/system/absorb-data/records.test +24 -0
- data/test/command/suite/system/statistics/object/count/empty.expected +11 -0
- data/test/command/suite/system/statistics/object/count/empty.test +12 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.catalog.json +36 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.test +12 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.catalog.json +40 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.test +23 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.catalog.json +40 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.test +13 -0
- data/test/command/suite/system/statistics/object/count/record.catalog.json +12 -0
- data/test/command/suite/system/statistics/object/count/record.expected +11 -0
- data/test/command/suite/system/statistics/object/count/record.test +23 -0
- data/test/command/suite/system/statistics/object/count/schema.catalog.json +12 -0
- data/test/command/suite/system/statistics/object/count/schema.expected +11 -0
- data/test/command/suite/system/statistics/object/count/schema.test +13 -0
- data/test/command/suite/system/status.expected +3 -2
- data/test/unit/catalog/test_dataset.rb +4 -1
- data/test/unit/{test_catalog_generator.rb → catalog/test_generator.rb} +2 -2
- data/test/unit/catalog/test_replicas_volume.rb +79 -0
- data/test/unit/catalog/test_single_volume.rb +2 -2
- data/test/unit/catalog/test_slice.rb +33 -1
- data/test/unit/catalog/{test_collection_volume.rb → test_slices_volume.rb} +72 -11
- data/test/unit/catalog/test_version2.rb +3 -0
- data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
- data/test/unit/plugins/catalog/test_fetch.rb +4 -4
- data/test/unit/plugins/crud/test_add.rb +44 -4
- data/test/unit/plugins/groonga/test_column_create.rb +4 -4
- data/test/unit/plugins/groonga/test_column_list.rb +4 -4
- data/test/unit/plugins/groonga/test_column_remove.rb +4 -4
- data/test/unit/plugins/groonga/test_column_rename.rb +4 -4
- data/test/unit/plugins/groonga/test_delete.rb +73 -10
- data/test/unit/plugins/groonga/test_table_create.rb +4 -4
- data/test/unit/plugins/groonga/test_table_list.rb +4 -4
- data/test/unit/plugins/groonga/test_table_remove.rb +4 -4
- data/test/unit/plugins/search/test_handler.rb +4 -4
- data/test/unit/plugins/search/test_planner.rb +4 -2
- data/test/unit/plugins/system/test_status.rb +31 -15
- data/test/unit/plugins/test_watch.rb +16 -16
- data/test/unit/test_address.rb +4 -4
- metadata +134 -35
- data/lib/droonga/catalog/volume_collection.rb +0 -79
- data/lib/droonga/catalog_fetcher.rb +0 -53
- data/lib/droonga/catalog_generator.rb +0 -243
- data/lib/droonga/catalog_loader.rb +0 -56
- data/lib/droonga/command/remote.rb +0 -404
- data/lib/droonga/data_absorber.rb +0 -264
- data/lib/droonga/node_status.rb +0 -71
- data/lib/droonga/serf_downloader.rb +0 -115
- data/test/unit/catalog/test_volume_collection.rb +0 -78
data/lib/droonga/planner.rb
CHANGED
|
@@ -22,26 +22,92 @@ module Droonga
|
|
|
22
22
|
include Loggable
|
|
23
23
|
include ErrorMessages
|
|
24
24
|
|
|
25
|
+
attr_writer :write, :single_operation, :use_all_replicas, :collector_class
|
|
26
|
+
|
|
25
27
|
def initialize(dataset)
|
|
26
28
|
@dataset = dataset
|
|
29
|
+
@write = false
|
|
30
|
+
@single_operation = false
|
|
31
|
+
@use_all_replicas = false
|
|
32
|
+
@collector_class = nil
|
|
27
33
|
end
|
|
28
34
|
|
|
29
|
-
def plan(message)
|
|
30
|
-
|
|
35
|
+
def plan(message, params={})
|
|
36
|
+
options = {
|
|
37
|
+
:record => params[:record],
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#TODO: We don't have to reduce results of the message when
|
|
41
|
+
# the message doesn't have "replyTo" information, because:
|
|
42
|
+
#
|
|
43
|
+
# * Currently the "super step" mecahnism is not
|
|
44
|
+
# implemented yet.
|
|
45
|
+
# * So, reduced results won't be forwarded to other
|
|
46
|
+
# handlers directly. Results will be forwarded to
|
|
47
|
+
# the sender as the "response".
|
|
48
|
+
# * So, if "replyTo" information is not given, the
|
|
49
|
+
# reduced result will have no receiver.
|
|
50
|
+
#
|
|
51
|
+
# However, in the future after the "super step" mechanism
|
|
52
|
+
# is introduced, reduced results can be required even if
|
|
53
|
+
# the request message have no "replyTo" information.
|
|
54
|
+
# Then we must update this logic.
|
|
55
|
+
if @collector_class and message["replyTo"]
|
|
56
|
+
reduce_key = "result"
|
|
57
|
+
options[:reduce] = {
|
|
58
|
+
reduce_key => @collector_class.operator,
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if options[:record] or single_operation?
|
|
63
|
+
scatter(message, options)
|
|
64
|
+
else
|
|
65
|
+
broadcast(message, options)
|
|
66
|
+
end
|
|
31
67
|
end
|
|
32
68
|
|
|
33
69
|
private
|
|
34
|
-
def
|
|
70
|
+
def write?
|
|
71
|
+
@write
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def single_operation?
|
|
75
|
+
return false if write?
|
|
76
|
+
@single_operation
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def use_all_replicas?
|
|
80
|
+
write? or @use_all_replicas
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def scatter(message, options={})
|
|
35
84
|
planner = DistributedCommandPlanner.new(@dataset, message)
|
|
36
|
-
|
|
37
|
-
|
|
85
|
+
scatter_options = {
|
|
86
|
+
:write => write?,
|
|
87
|
+
:record => options[:record],
|
|
88
|
+
}
|
|
89
|
+
if single_operation?
|
|
90
|
+
scatter_options[:slice] = "random"
|
|
91
|
+
scatter_options[:replica] = "random"
|
|
92
|
+
end
|
|
93
|
+
planner.scatter(scatter_options)
|
|
94
|
+
planner.reduce(options[:reduce]) if options[:reduce]
|
|
38
95
|
planner.plan
|
|
39
96
|
end
|
|
40
97
|
|
|
41
98
|
def broadcast(message, options={})
|
|
42
99
|
planner = DistributedCommandPlanner.new(@dataset, message)
|
|
43
|
-
|
|
44
|
-
|
|
100
|
+
broadcast_options = {
|
|
101
|
+
:write => write?,
|
|
102
|
+
}
|
|
103
|
+
if use_all_replicas?
|
|
104
|
+
broadcast_options[:replica] = "all"
|
|
105
|
+
elsif single_operation?
|
|
106
|
+
broadcast_options[:slice] = "random"
|
|
107
|
+
broadcast_options[:replica] = "random"
|
|
108
|
+
end
|
|
109
|
+
planner.broadcast(broadcast_options)
|
|
110
|
+
planner.reduce(options[:reduce]) if options[:reduce]
|
|
45
111
|
planner.plan
|
|
46
112
|
end
|
|
47
113
|
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Copyright (C) 2014-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
15
|
+
|
|
16
|
+
require "coolio"
|
|
17
|
+
|
|
18
|
+
require "droonga/loggable"
|
|
19
|
+
require "droonga/handler"
|
|
20
|
+
require "droonga/error_messages"
|
|
21
|
+
|
|
22
|
+
module Droonga
|
|
23
|
+
module Plugins
|
|
24
|
+
module AsyncCommand
|
|
25
|
+
class Request
|
|
26
|
+
def initialize(message)
|
|
27
|
+
@message = message
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def need_start?
|
|
31
|
+
reply_to
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def id
|
|
35
|
+
@message["id"]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def dataset
|
|
39
|
+
@message.raw["dataset"]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def reply_to
|
|
43
|
+
(@message.raw["replyTo"] || {})["to"]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def request
|
|
47
|
+
@message.request
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Handler < Droonga::Handler
|
|
52
|
+
def handle(message)
|
|
53
|
+
request = request_class.new(message)
|
|
54
|
+
if request.need_start?
|
|
55
|
+
start(request)
|
|
56
|
+
{
|
|
57
|
+
"started" => true,
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
{
|
|
61
|
+
"started" => false,
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
def request_class
|
|
68
|
+
#XXX override me!
|
|
69
|
+
Request
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def start(request)
|
|
73
|
+
#XXX override me!
|
|
74
|
+
# handler = MyAsyncHandler.new(loop, messenger, request)
|
|
75
|
+
# handler.start
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
class AsyncHandler
|
|
80
|
+
include Loggable
|
|
81
|
+
|
|
82
|
+
def initialize(loop, messenger, request)
|
|
83
|
+
@loop = loop
|
|
84
|
+
@messenger = messenger
|
|
85
|
+
@request = request
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def start
|
|
89
|
+
#XXX override me!!
|
|
90
|
+
on_start
|
|
91
|
+
on_finish
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
def prefix
|
|
96
|
+
"" #XXX override me!!
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def on_start
|
|
100
|
+
setup_forward_data
|
|
101
|
+
forward("#{prefix}.start")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def on_finish
|
|
105
|
+
forward("#{prefix}.end")
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def setup_forward_data
|
|
109
|
+
@base_forward_message = {
|
|
110
|
+
"inReplyTo" => @request.id,
|
|
111
|
+
"dataset" => @request.dataset,
|
|
112
|
+
}
|
|
113
|
+
@forward_to = @request.reply_to
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def error_name
|
|
117
|
+
"Failure" #XXX override me!!
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def error_message
|
|
121
|
+
"failed to do" #XXX override me!!
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def error(name, message)
|
|
125
|
+
message = {
|
|
126
|
+
"statusCode" => ErrorMessages::InternalServerError::STATUS_CODE,
|
|
127
|
+
"body" => {
|
|
128
|
+
"name" => name,
|
|
129
|
+
"message" => message,
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
error_message = @base_forward_message.merge(message)
|
|
133
|
+
@messenger.forward(error_message,
|
|
134
|
+
"to" => @forward_to,
|
|
135
|
+
"type" => "#{prefix}.error")
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def forward(type, body=nil)
|
|
139
|
+
forward_message = @base_forward_message
|
|
140
|
+
if body
|
|
141
|
+
forward_message = forward_message.merge("body" => body)
|
|
142
|
+
end
|
|
143
|
+
@messenger.forward(forward_message,
|
|
144
|
+
"to" => @forward_to,
|
|
145
|
+
"type" => type)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def log_tag
|
|
149
|
+
"[#{Process.ppid}] async-handler"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
data/lib/droonga/plugins/crud.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (C) 2013-
|
|
1
|
+
# Copyright (C) 2013-2015 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
|
|
@@ -70,8 +70,8 @@ module Droonga
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
class InvalidValue < BadRequest
|
|
73
|
-
def initialize(column, value, request)
|
|
74
|
-
super("The column #{column.inspect} cannot store the value #{value.inspect}
|
|
73
|
+
def initialize(column, value, reason, request)
|
|
74
|
+
super("The column #{column.inspect} cannot store the value #{value.inspect}: #{reason}",
|
|
75
75
|
request)
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -107,7 +107,8 @@ module Droonga
|
|
|
107
107
|
def add_record(table, request)
|
|
108
108
|
record = nil
|
|
109
109
|
if table.support_key?
|
|
110
|
-
|
|
110
|
+
key = normalize_record_key(request["key"], table)
|
|
111
|
+
record = table.add(key)
|
|
111
112
|
else
|
|
112
113
|
record = table.add
|
|
113
114
|
end
|
|
@@ -116,16 +117,31 @@ module Droonga
|
|
|
116
117
|
record[column] = value
|
|
117
118
|
rescue ::Groonga::InvalidArgument => error
|
|
118
119
|
record.delete if record.added?
|
|
119
|
-
raise InvalidValue.new(column, value, request)
|
|
120
|
+
raise InvalidValue.new(column, value, error.message, request)
|
|
120
121
|
rescue ArgumentError => error
|
|
121
122
|
record.delete if record.added?
|
|
122
|
-
raise InvalidValue.new(column, value, request)
|
|
123
|
+
raise InvalidValue.new(column, value, error.message, request)
|
|
124
|
+
rescue TypeError => error
|
|
125
|
+
record.delete if record.added?
|
|
126
|
+
raise InvalidValue.new(column, value, error.message, request)
|
|
123
127
|
rescue ::Groonga::NoSuchColumn => error
|
|
124
128
|
record.delete if record.added?
|
|
125
129
|
raise UnknownColumn.new(column, request["table"], request)
|
|
126
130
|
end
|
|
127
131
|
end
|
|
128
132
|
end
|
|
133
|
+
|
|
134
|
+
def normalize_record_key(key, table)
|
|
135
|
+
case table.domain.name
|
|
136
|
+
when "Int8", "UInt8",
|
|
137
|
+
"Int16", "UInt16",
|
|
138
|
+
"Int32", "UInt32",
|
|
139
|
+
"Int64", "UInt64"
|
|
140
|
+
key.to_i
|
|
141
|
+
else
|
|
142
|
+
key.to_s
|
|
143
|
+
end
|
|
144
|
+
end
|
|
129
145
|
end
|
|
130
146
|
|
|
131
147
|
define_single_step do |step|
|
data/lib/droonga/plugins/dump.rb
CHANGED
|
@@ -13,10 +13,13 @@
|
|
|
13
13
|
# License along with this library; if not, write to the Free Software
|
|
14
14
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
15
15
|
|
|
16
|
+
require "fiber"
|
|
16
17
|
require "groonga"
|
|
17
18
|
|
|
18
19
|
require "droonga/plugin"
|
|
20
|
+
require "droonga/plugin/async_command"
|
|
19
21
|
require "droonga/error_messages"
|
|
22
|
+
require "droonga/database_scanner"
|
|
20
23
|
|
|
21
24
|
module Droonga
|
|
22
25
|
module Plugins
|
|
@@ -35,149 +38,99 @@ module Droonga
|
|
|
35
38
|
extend Plugin
|
|
36
39
|
register("dump")
|
|
37
40
|
|
|
38
|
-
class
|
|
39
|
-
|
|
40
|
-
request = Request.new(message)
|
|
41
|
-
if request.need_dump?
|
|
42
|
-
dumper = Dumper.new(@context, loop, messenger, request)
|
|
43
|
-
dumper.start_dump
|
|
44
|
-
true
|
|
45
|
-
else
|
|
46
|
-
false
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
class Request
|
|
52
|
-
def initialize(message)
|
|
53
|
-
@message = message
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def need_dump?
|
|
57
|
-
reply_to
|
|
58
|
-
end
|
|
41
|
+
class Request < AsyncCommand::Request
|
|
42
|
+
DEFAULT_MESSAGES_PER_SECOND = 10000
|
|
59
43
|
|
|
60
|
-
def
|
|
61
|
-
@message
|
|
44
|
+
def messages_per_second
|
|
45
|
+
request = (@message.request || {})
|
|
46
|
+
minimum_messages_per_second = 10
|
|
47
|
+
[
|
|
48
|
+
minimum_messages_per_second,
|
|
49
|
+
(request["messagesPerSecond"] || DEFAULT_MESSAGES_PER_SECOND).to_i,
|
|
50
|
+
].max
|
|
62
51
|
end
|
|
52
|
+
end
|
|
63
53
|
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
class Handler < AsyncCommand::Handler
|
|
55
|
+
private
|
|
56
|
+
def request_class
|
|
57
|
+
Request
|
|
66
58
|
end
|
|
67
59
|
|
|
68
|
-
def
|
|
69
|
-
(@
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def messages_per_seconds
|
|
73
|
-
request = (@message.request || {})
|
|
74
|
-
minimum_messages_per_seconds = 10
|
|
75
|
-
[
|
|
76
|
-
minimum_messages_per_seconds,
|
|
77
|
-
(request["messagesPerSecond"] || 10000).to_i,
|
|
78
|
-
].max
|
|
60
|
+
def start(request)
|
|
61
|
+
dumper = Dumper.new(@context, loop, messenger, request)
|
|
62
|
+
dumper.start
|
|
79
63
|
end
|
|
80
64
|
end
|
|
81
65
|
|
|
82
|
-
class Dumper
|
|
83
|
-
include
|
|
66
|
+
class Dumper < AsyncCommand::AsyncHandler
|
|
67
|
+
include DatabaseScanner
|
|
84
68
|
|
|
85
69
|
def initialize(context, loop, messenger, request)
|
|
86
70
|
@context = context
|
|
87
|
-
|
|
88
|
-
@messenger = messenger
|
|
89
|
-
@request = request
|
|
71
|
+
super(loop, messenger, request)
|
|
90
72
|
end
|
|
91
73
|
|
|
92
|
-
def
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
forward("dump.start")
|
|
74
|
+
def start
|
|
75
|
+
on_start
|
|
96
76
|
|
|
97
|
-
|
|
77
|
+
runner = Fiber.new do
|
|
78
|
+
forecast
|
|
98
79
|
dump_schema
|
|
99
80
|
dump_records
|
|
100
81
|
dump_indexes
|
|
101
|
-
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
on_error = lambda do |exception|
|
|
105
|
-
message = "failed to dump"
|
|
106
|
-
logger.exception(message, $!)
|
|
107
|
-
error("DumpFailure", message)
|
|
82
|
+
on_finish
|
|
108
83
|
end
|
|
109
84
|
|
|
110
85
|
timer = Coolio::TimerWatcher.new(0.1, true)
|
|
111
86
|
timer.on_timer do
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
87
|
+
if runner.alive?
|
|
88
|
+
begin
|
|
89
|
+
runner.resume
|
|
90
|
+
rescue
|
|
91
|
+
timer.detach
|
|
92
|
+
logger.trace("start: timer detached by unexpected exception",
|
|
93
|
+
:watcher => timer)
|
|
94
|
+
logger.exception(error_message, $!)
|
|
95
|
+
error(error_name, error_message)
|
|
96
|
+
end
|
|
97
|
+
else
|
|
117
98
|
timer.detach
|
|
118
|
-
|
|
99
|
+
logger.trace("start: timer detached by unexpected exception",
|
|
100
|
+
:watcher => timer)
|
|
119
101
|
end
|
|
120
102
|
end
|
|
121
103
|
|
|
122
104
|
@loop.attach(timer)
|
|
105
|
+
logger.trace("start: timer attached",
|
|
106
|
+
:watcher => timer)
|
|
123
107
|
end
|
|
124
108
|
|
|
125
109
|
private
|
|
126
|
-
def
|
|
127
|
-
|
|
128
|
-
"inReplyTo" => @request.id,
|
|
129
|
-
"dataset" => @request.dataset,
|
|
130
|
-
}
|
|
131
|
-
@forward_to = @request.reply_to
|
|
132
|
-
@n_forwarded_messages = 0
|
|
133
|
-
@messages_per_100msec = @request.messages_per_seconds / 10
|
|
110
|
+
def prefix
|
|
111
|
+
"dump"
|
|
134
112
|
end
|
|
135
113
|
|
|
136
|
-
def
|
|
137
|
-
|
|
138
|
-
"statusCode" => ErrorMessages::InternalServerError::STATUS_CODE,
|
|
139
|
-
"body" => {
|
|
140
|
-
"name" => name,
|
|
141
|
-
"message" => message,
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
error_message = @base_forward_message.merge(message)
|
|
145
|
-
@messenger.forward(error_message,
|
|
146
|
-
"to" => @forward_to,
|
|
147
|
-
"type" => "dump.error")
|
|
114
|
+
def error_name
|
|
115
|
+
"DumpFailure"
|
|
148
116
|
end
|
|
149
117
|
|
|
150
|
-
def
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
forward_message = forward_message.merge("body" => body)
|
|
154
|
-
end
|
|
155
|
-
@messenger.forward(forward_message,
|
|
156
|
-
"to" => @forward_to,
|
|
157
|
-
"type" => type)
|
|
118
|
+
def error_message
|
|
119
|
+
"failed to dump"
|
|
120
|
+
end
|
|
158
121
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
Fiber.yield if @n_forwarded_messages.zero?
|
|
122
|
+
def forecast
|
|
123
|
+
forward("#{prefix}.forecast", "nMessages" => total_n_objects)
|
|
162
124
|
end
|
|
163
125
|
|
|
164
126
|
def dump_schema
|
|
165
|
-
reference_tables = []
|
|
166
127
|
each_table do |table|
|
|
167
|
-
if reference_table?(table)
|
|
168
|
-
reference_tables << table
|
|
169
|
-
next
|
|
170
|
-
end
|
|
171
|
-
dump_table(table)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
reference_tables.each do |table|
|
|
175
128
|
dump_table(table)
|
|
176
129
|
end
|
|
177
130
|
end
|
|
178
131
|
|
|
179
132
|
def dump_table(table)
|
|
180
|
-
forward("
|
|
133
|
+
forward("#{prefix}.table", table_body(table))
|
|
181
134
|
|
|
182
135
|
columns = table.columns.sort_by(&:name)
|
|
183
136
|
columns.each do |column|
|
|
@@ -210,7 +163,7 @@ module Droonga
|
|
|
210
163
|
end
|
|
211
164
|
|
|
212
165
|
def dump_column(column)
|
|
213
|
-
forward("
|
|
166
|
+
forward("#{prefix}.column", column_body(column))
|
|
214
167
|
end
|
|
215
168
|
|
|
216
169
|
def column_body(column)
|
|
@@ -270,7 +223,7 @@ module Droonga
|
|
|
270
223
|
"key" => record.key,
|
|
271
224
|
"values" => values,
|
|
272
225
|
}
|
|
273
|
-
forward("
|
|
226
|
+
forward("#{prefix}.record", body)
|
|
274
227
|
end
|
|
275
228
|
end
|
|
276
229
|
end
|
|
@@ -286,6 +239,8 @@ module Droonga
|
|
|
286
239
|
element
|
|
287
240
|
end
|
|
288
241
|
end
|
|
242
|
+
when Hash
|
|
243
|
+
value["_key"]
|
|
289
244
|
else
|
|
290
245
|
value
|
|
291
246
|
end
|
|
@@ -297,41 +252,17 @@ module Droonga
|
|
|
297
252
|
end
|
|
298
253
|
end
|
|
299
254
|
|
|
300
|
-
def
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
@context.database.each(options) do |object|
|
|
306
|
-
next unless table?(object)
|
|
307
|
-
yield(object)
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def table?(object)
|
|
312
|
-
object.is_a?(::Groonga::Table)
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
def index_only_table?(table)
|
|
316
|
-
table.columns.all? do |column|
|
|
317
|
-
index_column?(column)
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
def reference_table?(table)
|
|
322
|
-
table.support_key? and table?(table.domain)
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
def index_column?(column)
|
|
326
|
-
column.is_a?(::Groonga::IndexColumn)
|
|
255
|
+
def setup_forward_data
|
|
256
|
+
super
|
|
257
|
+
@n_forwarded_messages = 0
|
|
258
|
+
@messages_per_100msec = @request.messages_per_second / 10
|
|
327
259
|
end
|
|
328
260
|
|
|
329
|
-
def
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
end
|
|
261
|
+
def forward(type, body=nil)
|
|
262
|
+
super
|
|
263
|
+
@n_forwarded_messages += 1
|
|
264
|
+
@n_forwarded_messages %= @messages_per_100msec
|
|
265
|
+
Fiber.yield if @n_forwarded_messages.zero?
|
|
335
266
|
end
|
|
336
267
|
|
|
337
268
|
def log_tag
|