presto-client 0.5.14 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,7 +29,9 @@ module Presto::Client
29
29
  require 'presto/client/model_versions/0.173.rb'
30
30
  require 'presto/client/model_versions/0.178.rb'
31
31
  require 'presto/client/model_versions/0.205.rb'
32
+ require 'presto/client/model_versions/303.rb'
33
+ require 'presto/client/model_versions/316.rb'
32
34
 
33
- Models = ModelVersions::V0_205
35
+ Models = ModelVersions::V316
34
36
 
35
37
  end
@@ -16,6 +16,7 @@
16
16
  module Presto::Client
17
17
 
18
18
  require 'faraday'
19
+ require 'faraday_middleware'
19
20
  require 'presto/client/models'
20
21
  require 'presto/client/errors'
21
22
  require 'presto/client/faraday_client'
@@ -125,16 +126,13 @@ module Presto::Client
125
126
  end
126
127
 
127
128
  def close
128
- @api.cancel_leaf_stage
129
+ @api.close
129
130
  nil
130
131
  end
131
132
 
132
133
  def raise_if_failed
133
- if @api.closed?
134
+ if @api.client_aborted?
134
135
  raise PrestoClientError, "Query aborted by user"
135
- elsif @api.exception?
136
- # query is gone
137
- raise @api.exception
138
136
  elsif @api.query_failed?
139
137
  results = @api.current_results
140
138
  error = results.error
@@ -31,8 +31,7 @@ module Presto::Client
31
31
 
32
32
  @options = options
33
33
  @query = query
34
- @closed = false
35
- @exception = nil
34
+ @state = :running
36
35
  @retry_timeout = options[:retry_timeout] || 120
37
36
  if model_version = @options[:model_version]
38
37
  @models = ModelVersions.const_get("V#{model_version.gsub(".", "_")}")
@@ -76,7 +75,7 @@ module Presto::Client
76
75
 
77
76
  # TODO error handling
78
77
  if response.status != 200
79
- raise PrestoHttpError.new(response.status, "Failed to start query: #{response.body} (#{response.status})")
78
+ exception! PrestoHttpError.new(response.status, "Failed to start query: #{response.body} (#{response.status})")
80
79
  end
81
80
 
82
81
  @results_headers = response.headers
@@ -91,14 +90,20 @@ module Presto::Client
91
90
  !!@options[:debug]
92
91
  end
93
92
 
94
- def closed?
95
- @closed
93
+ def running?
94
+ @state == :running
96
95
  end
97
96
 
98
- attr_reader :exception
97
+ def client_aborted?
98
+ @state == :client_aborted
99
+ end
100
+
101
+ def client_error?
102
+ @state == :client_error
103
+ end
99
104
 
100
- def exception?
101
- @exception
105
+ def finished?
106
+ @state == :finished
102
107
  end
103
108
 
104
109
  def query_failed?
@@ -106,7 +111,7 @@ module Presto::Client
106
111
  end
107
112
 
108
113
  def query_succeeded?
109
- @results.error == nil && !@exception && !@closed
114
+ @results.error == nil && finished?
110
115
  end
111
116
 
112
117
  def current_results
@@ -117,16 +122,29 @@ module Presto::Client
117
122
  @results_headers
118
123
  end
119
124
 
125
+ def query_id
126
+ @results.id
127
+ end
128
+
120
129
  def has_next?
121
130
  !!@results.next_uri
122
131
  end
123
132
 
133
+ def exception!(e)
134
+ @state = :client_error
135
+ raise e
136
+ end
137
+
124
138
  def advance
125
- if closed? || !has_next?
139
+ return false unless running?
140
+
141
+ unless has_next?
142
+ @state = :finished
126
143
  return false
127
144
  end
128
145
 
129
146
  uri = @results.next_uri
147
+
130
148
  response = faraday_get_with_retry(uri)
131
149
  @results_headers = response.headers
132
150
  @results = decode_model(uri, parse_body(response), @models::QueryResults)
@@ -150,8 +168,7 @@ module Presto::Client
150
168
  if body.size > 1024 + 3
151
169
  body = "#{body[0, 1024]}..."
152
170
  end
153
- @exception = PrestoHttpError.new(500, "Presto API returned unexpected structure at #{uri}. Expected #{body_class} but got #{body}: #{e}")
154
- raise @exception
171
+ exception! PrestoHttpError.new(500, "Presto API returned unexpected structure at #{uri}. Expected #{body_class} but got #{body}: #{e}")
155
172
  end
156
173
  end
157
174
 
@@ -166,8 +183,7 @@ module Presto::Client
166
183
  JSON.parse(response.body, opts = JSON_OPTIONS)
167
184
  end
168
185
  rescue => e
169
- @exception = PrestoHttpError.new(500, "Presto API returned unexpected data format. #{e}")
170
- raise @exception
186
+ exception! PrestoHttpError.new(500, "Presto API returned unexpected data format. #{e}")
171
187
  end
172
188
  end
173
189
 
@@ -184,8 +200,7 @@ module Presto::Client
184
200
  # temporally error to retry
185
201
  response = nil
186
202
  rescue => e
187
- @exception = e
188
- raise @exception
203
+ exception! e
189
204
  end
190
205
 
191
206
  if response
@@ -195,8 +210,7 @@ module Presto::Client
195
210
 
196
211
  if response.status != 503 # retry only if 503 Service Unavailable
197
212
  # deterministic error
198
- @exception = PrestoHttpError.new(response.status, "Presto API error at #{uri} returned #{response.status}: #{response.body}")
199
- raise @exception
213
+ exception! PrestoHttpError.new(response.status, "Presto API error at #{uri} returned #{response.status}: #{response.body}")
200
214
  end
201
215
  end
202
216
 
@@ -204,18 +218,14 @@ module Presto::Client
204
218
 
205
219
  attempts += 1
206
220
  sleep attempts * 0.1
207
- end while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < @retry_timeout && !@closed
221
+ end while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < @retry_timeout && !client_aborted?
208
222
 
209
- @exception = PrestoHttpError.new(408, "Presto API error due to timeout")
210
- raise @exception
223
+ exception! PrestoHttpError.new(408, "Presto API error due to timeout")
211
224
  end
212
225
 
213
226
  def raise_if_timeout!
214
227
  if @started_at
215
- if @results && @results.next_uri == nil
216
- # query is already done
217
- return
218
- end
228
+ return if finished?
219
229
 
220
230
  elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started_at
221
231
 
@@ -234,30 +244,34 @@ module Presto::Client
234
244
 
235
245
  def raise_timeout_error!
236
246
  if query_id = @results && @results.id
237
- raise PrestoQueryTimeoutError, "Query #{query_id} timed out"
247
+ exception! PrestoQueryTimeoutError.new("Query #{query_id} timed out")
238
248
  else
239
- raise PrestoQueryTimeoutError, "Query timed out"
249
+ exception! PrestoQueryTimeoutError.new("Query timed out")
240
250
  end
241
251
  end
242
252
 
243
253
  def cancel_leaf_stage
244
- if uri = @results.next_uri
245
- response = @faraday.delete do |req|
254
+ if uri = @results.partial_cancel_uri
255
+ @faraday.delete do |req|
246
256
  req.url uri
247
257
  end
248
- return response.status / 100 == 2
249
258
  end
250
- return false
251
259
  end
252
260
 
253
261
  def close
254
- return if @closed
262
+ return unless running?
255
263
 
256
- # cancel running statement
257
- # TODO make async reqeust and ignore response?
258
- cancel_leaf_stage
264
+ @state = :client_aborted
265
+
266
+ begin
267
+ if uri = @results.next_uri
268
+ @faraday.delete do |req|
269
+ req.url uri
270
+ end
271
+ end
272
+ rescue => e
273
+ end
259
274
 
260
- @closed = true
261
275
  nil
262
276
  end
263
277
  end
@@ -15,6 +15,6 @@
15
15
  #
16
16
  module Presto
17
17
  module Client
18
- VERSION = "0.5.14"
18
+ VERSION = "0.6.4"
19
19
  end
20
20
  end
@@ -131,6 +131,7 @@ module Presto::Client::ModelVersions
131
131
  when "apply" then ApplyNode
132
132
  when "assignUniqueId" then AssignUniqueId
133
133
  when "lateralJoin" then LateralJoinNode
134
+ when "statisticsWriterNode" then StatisticsWriterNode
134
135
  end
135
136
  if model_class
136
137
  node = model_class.decode(hash)
@@ -197,9 +198,25 @@ module Presto::Client::ModelVersions
197
198
  end
198
199
  obj = allocate
199
200
  model_class = case hash["@type"]
200
- when "CreateHandle" then CreateHandle
201
- when "InsertHandle" then InsertHandle
202
- when "DeleteHandle" then DeleteHandle
201
+ when "CreateTarget" then CreateTarget
202
+ when "InsertTarget" then InsertTarget
203
+ when "DeleteTarget" then DeleteTarget
204
+ end
205
+ if model_class
206
+ model_class.decode(hash)
207
+ end
208
+ end
209
+ end
210
+
211
+ class << WriteStatisticsTarget =
212
+ Base.new(:type, :handle)
213
+ def decode(hash)
214
+ unless hash.is_a?(Hash)
215
+ raise TypeError, "Can't convert #{hash.class} to Hash"
216
+ end
217
+ obj = allocate
218
+ model_class = case hash["@type"]
219
+ when "WriteStatisticsHandle" then WriteStatisticsHandle
203
220
  end
204
221
  if model_class
205
222
  model_class.decode(hash)
@@ -246,6 +263,13 @@ module Presto::Client::ModelVersions
246
263
  end
247
264
  end
248
265
 
266
+ class ResourceGroupId < Array
267
+ def initialize(array)
268
+ super()
269
+ concat(array)
270
+ end
271
+ end
272
+
249
273
  ##
250
274
  # Those model classes are automatically generated
251
275
  #
data/modelgen/modelgen.rb CHANGED
@@ -13,13 +13,13 @@ erb = ERB.new(File.read(template_path))
13
13
 
14
14
  source_path = source_dir
15
15
 
16
- predefined_simple_classes = %w[StageId TaskId Lifespan ConnectorSession]
17
- predefined_models = %w[DistributionSnapshot PlanNode EquiJoinClause WriterTarget OperatorInfo HashCollisionsInfo]
16
+ predefined_simple_classes = %w[StageId TaskId Lifespan ConnectorSession ResourceGroupId]
17
+ predefined_models = %w[DistributionSnapshot PlanNode EquiJoinClause WriterTarget WriteStatisticsTarget OperatorInfo HashCollisionsInfo]
18
18
 
19
- assume_primitive = %w[Object Type Long Symbol QueryId PlanNodeId PlanFragmentId MemoryPoolId TransactionId URI Duration DataSize DateTime ColumnHandle ConnectorTableHandle ConnectorOutputTableHandle ConnectorIndexHandle ConnectorColumnHandle ConnectorInsertTableHandle ConnectorTableLayoutHandle Expression FunctionCall TimeZoneKey Locale TypeSignature Frame TupleDomain<ColumnHandle> SerializableNativeValue ConnectorTransactionHandle OutputBufferId ConnectorPartitioningHandle NullableValue ConnectorId HostAddress JsonNode Node]
20
- enum_types = %w[QueryState StageState TaskState QueueState PlanDistribution OutputPartitioning Step SortOrder BufferState NullPartitioning BlockedReason ParameterKind FunctionKind PartitionFunctionHandle Scope ErrorType DistributionType PipelineExecutionStrategy JoinType]
19
+ assume_primitive = %w[Object Type Long Symbol QueryId PlanNodeId PlanFragmentId MemoryPoolId TransactionId URI Duration DataSize DateTime ColumnHandle ConnectorTableHandle ConnectorOutputTableHandle ConnectorIndexHandle ConnectorColumnHandle ConnectorInsertTableHandle ConnectorTableLayoutHandle Expression FunctionCall TimeZoneKey Locale TypeSignature Frame TupleDomain<ColumnHandle> SerializableNativeValue ConnectorTransactionHandle OutputBufferId ConnectorPartitioningHandle NullableValue ConnectorId HostAddress JsonNode Node CatalogName QualifiedObjectName]
20
+ enum_types = %w[QueryState StageState TaskState QueueState PlanDistribution OutputPartitioning Step SortOrder BufferState NullPartitioning BlockedReason ParameterKind FunctionKind PartitionFunctionHandle Scope ErrorType DistributionType PipelineExecutionStrategy JoinType ExchangeNode.Type ColumnStatisticType TableStatisticType StageExecutionStrategy SemanticErrorCode]
21
21
 
22
- root_models = %w[QueryResults QueryInfo] + %w[
22
+ root_models = %w[QueryResults QueryInfo BasicQueryInfo] + %w[
23
23
  OutputNode
24
24
  ProjectNode
25
25
  TableScanNode
@@ -42,7 +42,6 @@ IndexJoinNode
42
42
  IndexSourceNode
43
43
  TableWriterNode
44
44
  DeleteNode
45
- MetadataDeleteNode
46
45
  TableFinishNode
47
46
  UnnestNode
48
47
  ExchangeNode
@@ -54,6 +53,7 @@ ExplainAnalyzeNode
54
53
  ApplyNode
55
54
  AssignUniqueId
56
55
  LateralJoinNode
56
+ StatisticsWriterNode
57
57
  ] + %w[
58
58
  ExchangeClientStatus
59
59
  LocalExchangeBufferInfo
@@ -62,7 +62,8 @@ SplitOperatorInfo
62
62
  PartitionedOutputInfo
63
63
  JoinOperatorInfo
64
64
  WindowInfo
65
- TableWriterInfo]
65
+ TableWriterInfo
66
+ ]
66
67
 
67
68
  name_mapping = Hash[*%w[
68
69
  StatementStats StageStats ClientStageStats
@@ -71,13 +72,14 @@ QueryResults Column ClientColumn
71
72
  ].each_slice(3).map { |x, y, z| [[x,y], z] }.flatten(1)]
72
73
 
73
74
  path_mapping = Hash[*%w[
74
- ClientColumn presto-client/src/main/java/com/facebook/presto/client/Column.java
75
- ClientStageStats presto-client/src/main/java/com/facebook/presto/client/StageStats.java
76
- Column presto-main/src/main/java/com/facebook/presto/execution/Column.java
77
- QueryStats presto-main/src/main/java/com/facebook/presto/execution/QueryStats.java
78
- StageStats presto-main/src/main/java/com/facebook/presto/execution/StageStats.java
79
- PartitionedOutputInfo presto-main/src/main/java/com/facebook/presto/operator/PartitionedOutputOperator.java
80
- TableWriterInfo presto-main/src/main/java/com/facebook/presto/operator/TableWriterOperator.java
75
+ ClientColumn presto-client/src/main/java/io/prestosql/client/Column.java
76
+ ClientStageStats presto-client/src/main/java/io/prestosql/client/StageStats.java
77
+ Column presto-main/src/main/java/io/prestosql/execution/Column.java
78
+ QueryStats presto-main/src/main/java/io/prestosql/execution/QueryStats.java
79
+ StageStats presto-main/src/main/java/io/prestosql/execution/StageStats.java
80
+ PartitionedOutputInfo presto-main/src/main/java/io/prestosql/operator/PartitionedOutputOperator.java
81
+ TableWriterInfo presto-main/src/main/java/io/prestosql/operator/TableWriterOperator.java
82
+ TableInfo presto-main/src/main/java/io/prestosql/execution/TableInfo.java
81
83
  ].map.with_index { |v,i| i % 2 == 0 ? v : (source_path + "/" + v) }]
82
84
 
83
85
  # model => [ [key,nullable,type], ... ]
@@ -3,13 +3,13 @@ module PrestoModels
3
3
  require 'find'
4
4
  require 'stringio'
5
5
 
6
- PRIMITIVE_TYPES = %w[String boolean long int short byte double float Integer]
6
+ PRIMITIVE_TYPES = %w[String boolean long int short byte double float Integer Double Boolean]
7
7
  ARRAY_PRIMITIVE_TYPES = PRIMITIVE_TYPES.map { |t| "#{t}[]" }
8
8
 
9
9
  class Model < Struct.new(:name, :fields)
10
10
  end
11
11
 
12
- class Field < Struct.new(:key, :nullable, :array, :map, :type, :base_type, :map_value_base_type)
12
+ class Field < Struct.new(:key, :nullable, :array, :map, :type, :base_type, :map_value_base_type, :base_type_alias)
13
13
  alias_method :nullable?, :nullable
14
14
  alias_method :array?, :array
15
15
  alias_method :map?, :map
@@ -47,10 +47,12 @@ module PrestoModels
47
47
 
48
48
  private
49
49
 
50
- PROPERTY_PATTERN = /@JsonProperty\(\"(\w+)\"\)\s+(@Nullable\s+)?([\w\<\>\[\]\,\s]+)\s+\w+/
50
+ PROPERTY_PATTERN = /@JsonProperty\(\"(\w+)\"\)\s+(@Nullable\s+)?([\w\<\>\[\]\,\s\.]+)\s+\w+/
51
51
  CREATOR_PATTERN = /@JsonCreator[\s]+public[\s]+(static\s+)?(\w+)[\w\s]*\((?:\s*#{PROPERTY_PATTERN}\s*,?)+\)/
52
+ GENERIC_PATTERN = /(\w+)\<(\w+)\>/
52
53
 
53
- def analyze_fields(model_name, creator_block)
54
+ def analyze_fields(model_name, creator_block, generic: nil)
55
+ model_name = "#{model_name}_#{generic}" if generic
54
56
  extra = @extra_fields[model_name] || []
55
57
  fields = creator_block.scan(PROPERTY_PATTERN).concat(extra).map do |key,nullable,type|
56
58
  map = false
@@ -63,7 +65,7 @@ module PrestoModels
63
65
  base_type = m[1]
64
66
  map_value_base_type = m[2]
65
67
  map = true
66
- elsif m = /Optional<([\w\[\]]+)>/.match(type)
68
+ elsif m = /Optional<([\w\[\]\<\>]+)>/.match(type)
67
69
  base_type = m[1]
68
70
  nullable = true
69
71
  elsif m = /OptionalInt/.match(type)
@@ -72,6 +74,9 @@ module PrestoModels
72
74
  elsif m = /OptionalLong/.match(type)
73
75
  base_type = 'Long'
74
76
  nullable = true
77
+ elsif m = /OptionalDouble/.match(type)
78
+ base_type = 'Double'
79
+ nullable = true
75
80
  elsif type =~ /\w+/
76
81
  base_type = type
77
82
  else
@@ -79,7 +84,16 @@ module PrestoModels
79
84
  end
80
85
  base_type = @name_mapping[[model_name, base_type]] || base_type
81
86
  map_value_base_type = @name_mapping[[model_name, map_value_base_type]] || map_value_base_type
82
- Field.new(key, !!nullable, array, map, type, base_type, map_value_base_type)
87
+
88
+ if generic
89
+ base_type = generic if base_type == 'T'
90
+ map_value_base_type = generic if map_value_base_type == 'T'
91
+ end
92
+ if m = GENERIC_PATTERN.match(base_type)
93
+ base_type_alias = "#{m[1]}_#{m[2]}"
94
+ end
95
+
96
+ Field.new(key, !!nullable, array, map, type, base_type, map_value_base_type, base_type_alias)
83
97
  end
84
98
 
85
99
  @models[model_name] = Model.new(model_name, fields)
@@ -92,9 +106,15 @@ module PrestoModels
92
106
  return fields
93
107
  end
94
108
 
95
- def analyze_model(model_name, parent_model = nil)
109
+ def analyze_model(model_name, parent_model= nil, generic: nil)
96
110
  return if @models[model_name] || @ignore_types.include?(model_name)
97
111
 
112
+ if m = GENERIC_PATTERN.match(model_name)
113
+ analyze_model(m[1], generic: m[2])
114
+ analyze_model(m[2])
115
+ return
116
+ end
117
+
98
118
  path = find_class_file(model_name, parent_model)
99
119
  java = File.read(path)
100
120
 
@@ -114,7 +134,7 @@ module PrestoModels
114
134
  fields = analyze_fields(inner_model_name, m[0])
115
135
  end
116
136
 
117
- fields = analyze_fields(model_name, body)
137
+ fields = analyze_fields(model_name, body, generic: generic)
118
138
 
119
139
  rescue => e
120
140
  puts "Skipping model #{parent_model}/#{model_name}: #{e}"
@@ -214,7 +234,7 @@ module PrestoModels
214
234
  elem_expr = convert_expression(field.base_type, field.base_type, "h")
215
235
  expr << "hash[\"#{field.key}\"].map {|h| #{elem_expr} }"
216
236
  else
217
- expr << convert_expression(field.type, field.base_type, "hash[\"#{field.key}\"]")
237
+ expr << convert_expression(field.type, field.base_type_alias || field.base_type, "hash[\"#{field.key}\"]")
218
238
  end
219
239
  end
220
240