diff --git a/.travis.yml b/.travis.yml
index 73bb5c7709b4d..18a803fcb62b6 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,6 +21,7 @@ env:
- PRODUCT_TESTS_BASIC_ENVIRONMENT=true
- PRODUCT_TESTS_SPECIFIC_ENVIRONMENT=true
- PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_2=true
+ - PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_3=true
- HIVE_TESTS=true
- KUDU_TESTS=true
@@ -30,10 +31,26 @@ dist: trusty
cache:
directories:
- $HOME/.m2/repository
+ - $HOME/.thrift
services:
- docker
+before_install:
+ - |
+ if [[ ! -e $HOME/.thrift/bin/thrift ]]; then
+ sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-thread-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev
+ wget https://www.apache.org/dist/thrift/0.9.3/thrift-0.9.3.tar.gz
+ tar xfz thrift-0.9.3.tar.gz
+ cd thrift-0.9.3 && ./configure --without-cpp --without-c_glib --without-python --without-ruby --without-php --without-erlang --without-go --without-nodejs -q --prefix=$HOME/.thrift
+ sudo make install > thrift_make_install.log
+ cd ..
+ fi
+ - |
+ if [[ ! -e /usr/local/bin/thrift ]]; then
+ sudo ln -s $HOME/.thrift/bin/thrift /usr/local/bin/thrift
+ fi
+
install:
- ./mvnw -v
- |
@@ -45,7 +62,7 @@ install:
./mvnw install $MAVEN_FAST_INSTALL -pl '!presto-docs,!presto-server,!presto-server-rpm'
fi
- |
- if [[ -v PRODUCT_TESTS_BASIC_ENVIRONMENT || -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT || -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_2 ]]; then
+ if [[ -v PRODUCT_TESTS_BASIC_ENVIRONMENT || -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT || -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_2 || -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_3 ]]; then
./mvnw install $MAVEN_FAST_INSTALL -pl '!presto-docs,!presto-server-rpm'
fi
- |
@@ -80,7 +97,7 @@ script:
fi
- |
if [[ -v TEST_SPECIFIC_MODULES ]]; then
- ./mvnw test $MAVEN_SKIP_CHECKS_AND_DOCS -B -pl $TEST_SPECIFIC_MODULES $TEST_FLAGS
+ travis_wait 60 ./mvnw test $MAVEN_SKIP_CHECKS_AND_DOCS -B -pl $TEST_SPECIFIC_MODULES $TEST_FLAGS
fi
- |
if [[ -v TEST_OTHER_MODULES ]]; then
@@ -107,12 +124,12 @@ script:
singlenode-hdfs-impersonation -g storage_formats,cli,hdfs_impersonation
fi
- |
- if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT ]]; then
+ if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_3 ]]; then
presto-product-tests/bin/run_on_docker.sh \
singlenode-kerberos-hdfs-impersonation -g storage_formats,cli,hdfs_impersonation,authorization,hive_file_header
fi
- |
- if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT ]]; then
+ if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_3 ]]; then
presto-product-tests/bin/run_on_docker.sh \
singlenode-kerberos-hdfs-impersonation-cross-realm -g storage_formats,cli,hdfs_impersonation
fi
@@ -149,7 +166,7 @@ script:
presto-product-tests/bin/run_on_docker.sh \
singlenode-cassandra -g cassandra
fi
- if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT ]]; then
+ if [[ -v PRODUCT_TESTS_SPECIFIC_ENVIRONMENT_3 ]]; then
presto-product-tests/bin/run_on_docker.sh \
multinode-tls-kerberos -g cli,group-by,join,tls
fi
@@ -193,8 +210,11 @@ before_cache:
- rm -rf $HOME/.m2/repository/com/facebook
notifications:
+ hipchat:
+ rooms:
+ secure: peNh1KxwlxIpFyb60S8AMvaJThgh1LsjE+Whf1rYkJalVd2wUrqBIoyDKVSueyHD01hQ06gT7rBV6Pu/QcBMR1a9BbMCjERfxLZFUAheuC2Rsb+p1c4dyvBcFUGacgW7XWKCaVYGDGxuUvb0I3Z8cR6KxhK2xi88tHiqBGVGV2yI6zzOTpWVknMfFBtn+ONU1Ob2P6trclXaDyFd4MxubULri6CQdl35eQAq/VnmR3SZOgyVu3V30MGKwI3zhSli+3VqmW0JmaDGoHN6gznM1+VqABLgmIq0P+n+r5gdZWRCorq10NZCFMhVQ8U6rQHcL7sAniYJJsC/yRt6+pjyzIF4N+LSzZ7T+FLxQqT7k/1ukNgrujLDfTpn76Mo9eYTZmfAdzbm1QKJDACwr8Slqhq1jGzcrFMHunvXhVqjOs24R+JAHblY0O9PXvv7aR29GOQWDCvD7nV5QBUr8Xz5q7ozbLqHTI+yH02Jj4EaZ+azWYdRmnr9wDBxWMYBEgOdj4pII9b298XEDB72TxA3KpLTpdLxBTR+gIk/LjJqb/wb84xUv8gPXkaXccltGd5YI90c84cX8isbzNkAylzyfF2Eyueh0XbnMHfpFqBS7qaVM0/D+UxZkU0WNJ0x7G9XJvkiq49bZz2q1KLE4XuvVnTZSSjVSUAS8RtHfwUV33c=
slack:
- secure: V5eyoGShxFoCcYJcp858vf/T6gC9KeMxL0C1EElcpZRcKBrIVZzvhek3HLHxZOxlghqnvNVsyDtU3u5orkEaAXeXj5c2dN+4XBsAB9oeN5MtQ0Z3VLAhZDqKIW1LzcXrq4DpzM0PkGhjfjum/P94/qFYk0UckPtB6a341AuYRo8=
+ secure: E7XVlbdwIdKxnr6Tk1rmCefufs1w8h4nCWz79Uh6wMma8gC7x5ChKFqwvLRJ0WUpmPS+Ng1xeTv+wmb8TMDv2X8snmht9420/TFRy9wi1aLWNJXQUveNBzn83sCS40jFi6gd9xqKawd68R84UVH3PeNhksDtDnKAblx71miwbKmLwHc1KFoLMEnaaWEg5NgFl8/UadYDvsLD44v6YDza8eYrLp3aGK8v9ewBDySHE16IHAfpteTRaU0kG/H1kvVvFdH/h/sSPfimehd51b4i3mm/nRrjJ/VSLc7p9w5FkHUECtA0N6zcytRxN6MrbhrxJ8XG3vte3KSRSFCqfgOSRM2NWcca4CtBP2V0SwrAYMo5jim6fr921lfcbUTWTSnvMYLC17QrAxoclVrgK05GjGoLgSH42UPGf3QNkqXzyueNzaLJ+KSlgwFblIQKp6WGZYSRorL0F7s50pIoqMVoebcrnB0ObK/CcE2ywS/HeTgoSkWSDSmKBsO+cmtv1yAamy9DlmgRGZlxIxdBELXtHRkQ2B6Z2QdiQU4MHiFBc/IESJbnCait4odn+oJUjehZg+b9vjCoWwVw3zNMIJhokyxO8SiyKJmbO0z1g2L/BykWGI1DQu8HkeQzO+CmNUV3AOrxDG3amL/tkB/06fyQtnYMDhUhvX64uWSaE36sYL4=
before_deploy:
- mkdir /tmp/artifacts
diff --git a/README.md b/README.md
index 695812979cd68..5bbea6ca1a485 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Presto [](https://travis-ci.org/prestodb/presto)
+# Presto [](https://travis-ci.org/twitter-forks/presto)
Presto is a distributed SQL query engine for big data.
diff --git a/pom.xml b/pom.xml
index dac63843f2cad..69694888e2c5f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
pom
presto-root
@@ -28,9 +28,9 @@
- scm:git:git://github.com/facebook/presto.git
- https://github.com/facebook/presto
- 0.210
+ scm:git:git://github.com/twitter-forks/presto.git
+ https://github.com/twitter-forks/presto
+ 0.210-tw-0.60
@@ -45,6 +45,7 @@
4.7.1
0.172
+ 0.172-tw-0.1
${dep.airlift.version}
0.36
1.11.293
@@ -117,9 +118,13 @@
presto-thrift-testing-server
presto-thrift-connector
presto-matching
+ presto-twitter-functions
presto-memory-context
presto-proxy
presto-kudu
+ twitter-http-client
+ twitter-eventlistener-plugin
+ presto-twitter-server
@@ -414,10 +419,11 @@
0.8.2
+
io.airlift
aircompressor
- 0.11
+ 0.12
@@ -537,7 +543,7 @@
io.airlift
http-client
- ${dep.airlift.version}
+ ${dep.airlift.twitter.version}
@@ -802,6 +808,12 @@
3.6.1
+
+ org.apache.commons
+ commons-pool2
+ 2.4.2
+
+
io.airlift.discovery
discovery-server
@@ -890,6 +902,54 @@
1.1.2.6
+
+ org.apache.curator
+ curator-recipes
+ 4.0.0
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+
+
+ org.apache.curator
+ curator-framework
+ 4.0.0
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+
+
+ org.apache.curator
+ curator-client
+ 4.0.0
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+
+
+ org.apache.curator
+ curator-test
+ 2.12.0
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+
org.apache.zookeeper
zookeeper
@@ -910,6 +970,26 @@
+
+ com.101tec
+ zkclient
+ 0.10
+
+
+ log4j
+ log4j
+
+
+ org.slf4j
+ slf4j-log4j12
+
+
+ org.apache.zookeeper
+ zookeeper
+
+
+
+
org.jgrapht
jgrapht-core
diff --git a/presto-accumulo/pom.xml b/presto-accumulo/pom.xml
index 8bc63cf9b7fbc..76cf92fd5c352 100644
--- a/presto-accumulo/pom.xml
+++ b/presto-accumulo/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-accumulo
diff --git a/presto-array/pom.xml b/presto-array/pom.xml
index 26eb28f17ea16..471258613f92d 100644
--- a/presto-array/pom.xml
+++ b/presto-array/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-array
diff --git a/presto-atop/pom.xml b/presto-atop/pom.xml
index 841132b0d2dfe..48dc85b2ecd05 100644
--- a/presto-atop/pom.xml
+++ b/presto-atop/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-atop
diff --git a/presto-base-jdbc/pom.xml b/presto-base-jdbc/pom.xml
index fae14de244eb9..6565dcccf1640 100644
--- a/presto-base-jdbc/pom.xml
+++ b/presto-base-jdbc/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-base-jdbc
diff --git a/presto-benchmark-driver/pom.xml b/presto-benchmark-driver/pom.xml
index da1c7bb0804a8..54c8a31f79fd7 100644
--- a/presto-benchmark-driver/pom.xml
+++ b/presto-benchmark-driver/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-benchmark-driver
diff --git a/presto-benchmark/pom.xml b/presto-benchmark/pom.xml
index bb4e571e17d49..b4c868014a7e0 100644
--- a/presto-benchmark/pom.xml
+++ b/presto-benchmark/pom.xml
@@ -5,7 +5,7 @@
presto-root
com.facebook.presto
- 0.210
+ 0.210-tw-0.61
presto-benchmark
diff --git a/presto-benchto-benchmarks/pom.xml b/presto-benchto-benchmarks/pom.xml
index bffbeb1b7fa42..19150483eb89e 100644
--- a/presto-benchto-benchmarks/pom.xml
+++ b/presto-benchto-benchmarks/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-benchto-benchmarks
diff --git a/presto-blackhole/pom.xml b/presto-blackhole/pom.xml
index 63aa547279ac9..65ffdb7404821 100644
--- a/presto-blackhole/pom.xml
+++ b/presto-blackhole/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-blackhole
diff --git a/presto-cassandra/pom.xml b/presto-cassandra/pom.xml
index dc38ebd4a5413..b49390f7cdb08 100644
--- a/presto-cassandra/pom.xml
+++ b/presto-cassandra/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-cassandra
diff --git a/presto-cli/pom.xml b/presto-cli/pom.xml
index aae4e6093c108..6e52e9fd58988 100644
--- a/presto-cli/pom.xml
+++ b/presto-cli/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-cli
diff --git a/presto-cli/src/main/java/com/facebook/presto/cli/ClientOptions.java b/presto-cli/src/main/java/com/facebook/presto/cli/ClientOptions.java
index b06ab313779be..b631e3ce9b0e2 100644
--- a/presto-cli/src/main/java/com/facebook/presto/cli/ClientOptions.java
+++ b/presto-cli/src/main/java/com/facebook/presto/cli/ClientOptions.java
@@ -20,6 +20,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.HostAndPort;
+import com.sun.security.auth.module.UnixSystem;
import io.airlift.airline.Option;
import io.airlift.units.Duration;
@@ -74,6 +75,11 @@ public class ClientOptions
@Option(name = "--keystore-password", title = "keystore password", description = "Keystore password")
public String keystorePassword;
+ // Pick the user name for the logged in user.
+ // Do not let it be overridden by users.
+ @Option(name = "--user", title = "user", description = "Username")
+ public String user = new UnixSystem().getUsername();
+
@Option(name = "--truststore-path", title = "truststore path", description = "Truststore path")
public String truststorePath;
@@ -83,9 +89,6 @@ public class ClientOptions
@Option(name = "--access-token", title = "access token", description = "Access token")
public String accessToken;
- @Option(name = "--user", title = "user", description = "Username")
- public String user = System.getProperty("user.name");
-
@Option(name = "--password", title = "password", description = "Prompt for password")
public boolean password;
diff --git a/presto-client/pom.xml b/presto-client/pom.xml
index 96b98481f50d4..dc59e0869afcf 100644
--- a/presto-client/pom.xml
+++ b/presto-client/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-client
diff --git a/presto-client/src/main/java/com/facebook/presto/client/SpnegoHandler.java b/presto-client/src/main/java/com/facebook/presto/client/SpnegoHandler.java
index 85f144a6dfca3..45f3ef5ca4acd 100644
--- a/presto-client/src/main/java/com/facebook/presto/client/SpnegoHandler.java
+++ b/presto-client/src/main/java/com/facebook/presto/client/SpnegoHandler.java
@@ -75,6 +75,7 @@ public class SpnegoHandler
private static final Oid KERBEROS_OID = createOid("1.2.840.113554.1.2.2");
private final String remoteServiceName;
+ private final boolean isCompleteServicePrinciple;
private final boolean useCanonicalHostname;
private final Optional principal;
private final Optional keytab;
@@ -92,6 +93,7 @@ public SpnegoHandler(
Optional credentialCache)
{
this.remoteServiceName = requireNonNull(remoteServiceName, "remoteServiceName is null");
+ this.isCompleteServicePrinciple = remoteServiceName.contains("@");
this.useCanonicalHostname = useCanonicalHostname;
this.principal = requireNonNull(principal, "principal is null");
this.keytab = requireNonNull(keytab, "keytab is null");
@@ -133,7 +135,7 @@ private static boolean isNegotiate(String value)
private Request authenticate(Request request)
{
String hostName = request.url().host();
- String principal = makeServicePrincipal(remoteServiceName, hostName, useCanonicalHostname);
+ String principal = isCompleteServicePrinciple ? remoteServiceName : makeServicePrincipal(remoteServiceName, hostName, useCanonicalHostname);
byte[] token = generateToken(principal);
String credential = format("%s %s", NEGOTIATE, Base64.getEncoder().encodeToString(token));
@@ -149,7 +151,7 @@ private byte[] generateToken(String servicePrincipal)
Session session = getSession();
context = doAs(session.getLoginContext().getSubject(), () -> {
GSSContext result = GSS_MANAGER.createContext(
- GSS_MANAGER.createName(servicePrincipal, NT_HOSTBASED_SERVICE),
+ GSS_MANAGER.createName(servicePrincipal, isCompleteServicePrinciple ? NT_USER_NAME : NT_HOSTBASED_SERVICE),
SPNEGO_OID,
session.getClientCredential(),
INDEFINITE_LIFETIME);
diff --git a/presto-docs/pom.xml b/presto-docs/pom.xml
index 1b3051ddedd7c..5e08593f7e3be 100644
--- a/presto-docs/pom.xml
+++ b/presto-docs/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-docs
diff --git a/presto-docs/src/main/sphinx/functions.rst b/presto-docs/src/main/sphinx/functions.rst
index 36c7111339cd6..70bf2d912d722 100644
--- a/presto-docs/src/main/sphinx/functions.rst
+++ b/presto-docs/src/main/sphinx/functions.rst
@@ -27,3 +27,4 @@ Functions and Operators
functions/color
functions/session
functions/teradata
+ functions/twitter
diff --git a/presto-docs/src/main/sphinx/functions/twitter.rst b/presto-docs/src/main/sphinx/functions/twitter.rst
new file mode 100644
index 0000000000000..573bea916b7b0
--- /dev/null
+++ b/presto-docs/src/main/sphinx/functions/twitter.rst
@@ -0,0 +1,58 @@
+==================
+Twitter Functions
+==================
+
+These functions provide some convenience functionality commonly used at Twitter.
+
+Map Functions
+-----------------
+
+.. function:: key_of_max_value(map) -> K
+
+ Get the key of the entry of map that holding max value. If more than one entry holds the same max value, return null.
+
+String Functions
+-----------------
+
+.. function:: split_every(string) -> array
+
+ Splits ``string`` on every character and returns an array.
+
+.. function:: split_every(string, length) -> array
+
+ Splits ``string`` on every ``length`` characters and returns an array.
+ length must be a positive number.
+
+.. function:: split_every(string, length, limit) -> array
+
+ Splits ``string`` on every ``length`` characters and returns an array of size at most ``limit``.
+ The last element in the array always contains everything left in the string. ``limit`` must be a positive number.
+
+Twitter IDs(Snowflake) Functions
+---------------------------------
+
+The utility functions for `Twitter IDs(Snowflake) `_.
+
+.. function:: is_snowflake(id) -> boolean
+
+ Return if a bigint is a snowflake ID (true/false).
+
+.. function:: first_snowflake_for(timestamp) -> bigint
+
+ Return the first snowflake ID given a timestamp.
+
+.. function:: timestamp_from_snowflake(id) -> timestamp
+
+ Return the timestamp given a snowflake ID.
+
+.. function:: cluster_id_from_snowflake(id) -> bigint
+
+ Return the cluster ID given a snowflake ID.
+
+.. function:: instance_id_from_snowflake(id) -> bigint
+
+ Return the instance ID given a snowflake ID.
+
+.. function:: sequence_num_from_snowflake(id) -> bigint
+
+ Return the sequence number given a snowflake ID.
diff --git a/presto-example-http/pom.xml b/presto-example-http/pom.xml
index 2531116738ec5..dbe8ae9cbc8a2 100644
--- a/presto-example-http/pom.xml
+++ b/presto-example-http/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-example-http
diff --git a/presto-geospatial-toolkit/pom.xml b/presto-geospatial-toolkit/pom.xml
index 70d4ddbea0e47..b6322b80cd6c9 100644
--- a/presto-geospatial-toolkit/pom.xml
+++ b/presto-geospatial-toolkit/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-geospatial-toolkit
diff --git a/presto-geospatial/pom.xml b/presto-geospatial/pom.xml
index 7d2b8fe333ab8..70fdfddb1b52d 100644
--- a/presto-geospatial/pom.xml
+++ b/presto-geospatial/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-geospatial
diff --git a/presto-hive-hadoop2/pom.xml b/presto-hive-hadoop2/pom.xml
index ea467768280c4..bd6c086edab30 100644
--- a/presto-hive-hadoop2/pom.xml
+++ b/presto-hive-hadoop2/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-hive-hadoop2
@@ -94,6 +94,12 @@
com.facebook.presto
presto-main
test
+
+
+ io.netty
+ netty
+
+
diff --git a/presto-hive/pom.xml b/presto-hive/pom.xml
index c62bad457d618..48652ef46b994 100644
--- a/presto-hive/pom.xml
+++ b/presto-hive/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-hive
@@ -53,11 +53,37 @@
hive-apache
+
+ org.apache.curator
+ curator-recipes
+
+
+
+ org.apache.curator
+ curator-framework
+
+
+
+ org.apache.curator
+ curator-client
+
+
+
+ org.apache.zookeeper
+ zookeeper
+ runtime
+
+
org.apache.thrift
libthrift
+
+ org.apache.commons
+ commons-pool2
+
+
io.airlift
aircompressor
@@ -98,6 +124,12 @@
configuration
+
+ com.googlecode.json-simple
+ json-simple
+ 1.1
+
+
com.google.guava
guava
@@ -175,6 +207,41 @@
jackson-databind
+
+ com.twitter.elephantbird
+ elephant-bird-core
+ 4.14
+ thrift9
+
+
+ commons-logging
+ commons-logging
+
+
+ com.hadoop.gplcompression
+ hadoop-lzo
+
+
+
+
+
+ commons-io
+ commons-io
+ 2.5
+ runtime
+
+
+
+ commons-lang
+ commons-lang
+ 2.4
+
+
+
+ org.anarres.lzo
+ lzo-hadoop
+
+
io.airlift
@@ -204,6 +271,18 @@
+
+ org.apache.curator
+ curator-test
+ test
+
+
+
+ com.101tec
+ zkclient
+ test
+
+
com.facebook.presto
presto-spi
@@ -259,12 +338,6 @@
test
-
- org.anarres.lzo
- lzo-hadoop
- test
-
-
com.facebook.presto
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java
index 9b34f821c1325..3c142b4405ceb 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientConfig.java
@@ -99,6 +99,7 @@ public class HiveClientConfig
private boolean useParquetColumnNames;
private boolean parquetOptimizedReaderEnabled = true;
private boolean parquetPredicatePushdownEnabled = true;
+ private DataSize parquetMaxReadBlockSize = new DataSize(16, MEGABYTE);
private boolean assumeCanonicalPartitionKeys;
@@ -693,6 +694,19 @@ public HiveClientConfig setParquetOptimizedReaderEnabled(boolean parquetOptimize
return this;
}
+ @NotNull
+ public DataSize getParquetMaxReadBlockSize()
+ {
+ return parquetMaxReadBlockSize;
+ }
+
+ @Config("hive.parquet.max-read-block-size")
+ public HiveClientConfig setParquetMaxReadBlockSize(DataSize parquetMaxReadBlockSize)
+ {
+ this.parquetMaxReadBlockSize = parquetMaxReadBlockSize;
+ return this;
+ }
+
public boolean isUseOrcColumnNames()
{
return useOrcColumnNames;
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientModule.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientModule.java
index 262f3bb78dbbf..760eea7c2e0ca 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientModule.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveClientModule.java
@@ -23,6 +23,9 @@
import com.facebook.presto.spi.connector.ConnectorPageSinkProvider;
import com.facebook.presto.spi.connector.ConnectorPageSourceProvider;
import com.facebook.presto.spi.connector.ConnectorSplitManager;
+import com.facebook.presto.twitter.hive.thrift.HiveThriftFieldIdResolverFactory;
+import com.facebook.presto.twitter.hive.thrift.ThriftFieldIdResolverFactory;
+import com.facebook.presto.twitter.hive.thrift.ThriftHiveRecordCursorProvider;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provides;
@@ -74,9 +77,11 @@ public void configure(Binder binder)
binder.bind(NamenodeStats.class).in(Scopes.SINGLETON);
newExporter(binder).export(NamenodeStats.class).as(generatedNameOf(NamenodeStats.class, connectorId));
+ binder.bind(ThriftFieldIdResolverFactory.class).toInstance(new HiveThriftFieldIdResolverFactory());
Multibinder recordCursorProviderBinder = newSetBinder(binder, HiveRecordCursorProvider.class);
recordCursorProviderBinder.addBinding().to(ParquetRecordCursorProvider.class).in(Scopes.SINGLETON);
+ recordCursorProviderBinder.addBinding().to(ThriftHiveRecordCursorProvider.class).in(Scopes.SINGLETON);
recordCursorProviderBinder.addBinding().to(GenericHiveRecordCursorProvider.class).in(Scopes.SINGLETON);
binder.bind(HiveWriterStats.class).in(Scopes.SINGLETON);
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java
index 62988901396a5..acf3f68b4d2ed 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveSessionProperties.java
@@ -64,6 +64,7 @@ public final class HiveSessionProperties
private static final String PARQUET_PREDICATE_PUSHDOWN_ENABLED = "parquet_predicate_pushdown_enabled";
private static final String PARQUET_OPTIMIZED_READER_ENABLED = "parquet_optimized_reader_enabled";
private static final String PARQUET_USE_COLUMN_NAME = "parquet_use_column_names";
+ private static final String PARQUET_MAX_READ_BLOCK_SIZE = "parquet_max_read_block_size";
private static final String MAX_SPLIT_SIZE = "max_split_size";
private static final String MAX_INITIAL_SPLIT_SIZE = "max_initial_split_size";
public static final String RCFILE_OPTIMIZED_WRITER_ENABLED = "rcfile_optimized_writer_enabled";
@@ -221,6 +222,11 @@ public HiveSessionProperties(HiveClientConfig hiveClientConfig, OrcFileWriterCon
"Experimental: Parquet: Access Parquet columns using names from the file",
hiveClientConfig.isUseParquetColumnNames(),
false),
+ dataSizeSessionProperty(
+ PARQUET_MAX_READ_BLOCK_SIZE,
+ "Parquet: Maximum size of a block to read",
+ hiveClientConfig.getParquetMaxReadBlockSize(),
+ false),
dataSizeSessionProperty(
MAX_SPLIT_SIZE,
"Max split size",
@@ -398,6 +404,11 @@ public static boolean isUseParquetColumnNames(ConnectorSession session)
return session.getProperty(PARQUET_USE_COLUMN_NAME, Boolean.class);
}
+ public static DataSize getParquetMaxReadBlockSize(ConnectorSession session)
+ {
+ return session.getProperty(PARQUET_MAX_READ_BLOCK_SIZE, DataSize.class);
+ }
+
public static DataSize getMaxSplitSize(ConnectorSession session)
{
return session.getProperty(MAX_SPLIT_SIZE, DataSize.class);
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveStorageFormat.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveStorageFormat.java
index 4e4523d041859..5a9edf5b383ce 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveStorageFormat.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveStorageFormat.java
@@ -14,6 +14,7 @@
package com.facebook.presto.hive;
import com.facebook.presto.spi.PrestoException;
+import com.facebook.presto.twitter.hive.thrift.ThriftGeneralInputFormat;
import io.airlift.units.DataSize;
import io.airlift.units.DataSize.Unit;
import org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat;
@@ -32,6 +33,7 @@
import org.apache.hadoop.hive.serde2.columnar.ColumnarSerDe;
import org.apache.hadoop.hive.serde2.columnar.LazyBinaryColumnarSerDe;
import org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe;
+import org.apache.hadoop.hive.serde2.lazybinary.LazyBinarySerDe;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector.Category;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector.PrimitiveCategory;
import org.apache.hadoop.hive.serde2.typeinfo.MapTypeInfo;
@@ -93,6 +95,11 @@ public enum HiveStorageFormat
LazySimpleSerDe.class.getName(),
TextInputFormat.class.getName(),
HiveIgnoreKeyTextOutputFormat.class.getName(),
+ new DataSize(8, Unit.MEGABYTE)),
+ THRIFTBINARY(
+ LazyBinarySerDe.class.getName(),
+ ThriftGeneralInputFormat.class.getName(),
+ HiveIgnoreKeyTextOutputFormat.class.getName(),
new DataSize(8, Unit.MEGABYTE));
private final String serde;
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveUtil.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveUtil.java
index 8c774ebd8cb14..9c895eeeeeba9 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveUtil.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveUtil.java
@@ -28,6 +28,7 @@
import com.facebook.presto.spi.type.StandardTypes;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.VarcharType;
+import com.facebook.presto.twitter.hive.thrift.ThriftGeneralInputFormat;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.VerifyException;
@@ -40,6 +41,7 @@
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.PathFilter;
import org.apache.hadoop.hive.common.JavaUtils;
import org.apache.hadoop.hive.ql.exec.Utilities;
import org.apache.hadoop.hive.ql.io.SymlinkTextInputFormat;
@@ -119,6 +121,7 @@
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
+import static com.hadoop.compression.lzo.LzoIndex.LZO_INDEX_SUFFIX;
import static java.lang.Byte.parseByte;
import static java.lang.Double.parseDouble;
import static java.lang.Float.floatToRawIntBits;
@@ -155,6 +158,22 @@ public final class HiveUtil
private static final String BIG_DECIMAL_POSTFIX = "BD";
+ private static final PathFilter LZOP_DEFAULT_SUFFIX_FILTER = new PathFilter() {
+ @Override
+ public boolean accept(Path path)
+ {
+ return path.toString().endsWith(".lzo");
+ }
+ };
+
+ private static final PathFilter LZOP_INDEX_DEFAULT_SUFFIX_FILTER = new PathFilter() {
+ @Override
+ public boolean accept(Path path)
+ {
+ return path.toString().endsWith(".lzo.index");
+ }
+ };
+
static {
DateTimeParser[] timestampWithoutTimeZoneParser = {
DateTimeFormat.forPattern("yyyy-M-d").getParser(),
@@ -187,7 +206,7 @@ private HiveUtil()
// propagate serialization configuration to getRecordReader
schema.stringPropertyNames().stream()
- .filter(name -> name.startsWith("serialization."))
+ .filter(name -> name.startsWith("serialization.") || name.startsWith("elephantbird."))
.forEach(name -> jobConf.set(name, schema.getProperty(name)));
// add Airlift LZO and LZOP to head of codecs list so as to not override existing entries
@@ -261,6 +280,11 @@ public static void setReadColumns(Configuration configuration, List rea
return MapredParquetInputFormat.class;
}
+ // Remove this after https://github.com/twitter/elephant-bird/pull/481 is included in a release
+ if ("com.twitter.elephantbird.mapred.input.HiveMultiInputFormat".equals(inputFormatName)) {
+ return ThriftGeneralInputFormat.class;
+ }
+
Class> clazz = conf.getClassByName(inputFormatName);
return (Class extends InputFormat, ?>>) clazz.asSubclass(InputFormat.class);
}
@@ -313,6 +337,21 @@ public static boolean isSplittable(InputFormat, ?> inputFormat, FileSystem fil
}
}
+ public static boolean isLzopCompressedFile(Path filePath)
+ {
+ return LZOP_DEFAULT_SUFFIX_FILTER.accept(filePath);
+ }
+
+ public static boolean isLzopIndexFile(Path filePath)
+ {
+ return LZOP_INDEX_DEFAULT_SUFFIX_FILTER.accept(filePath);
+ }
+
+ public static Path getLzopIndexPath(Path lzoPath)
+ {
+ return lzoPath.suffix(LZO_INDEX_SUFFIX);
+ }
+
public static StructObjectInspector getTableObjectInspector(Properties schema)
{
return getTableObjectInspector(getDeserializer(schema));
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/HiveWriteUtils.java b/presto-hive/src/main/java/com/facebook/presto/hive/HiveWriteUtils.java
index 8a161a9d468be..9d4fc92bfe8ee 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/HiveWriteUtils.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/HiveWriteUtils.java
@@ -528,6 +528,17 @@ public static boolean isViewFileSystem(HdfsContext context, HdfsEnvironment hdfs
}
}
+ public static boolean isHDFSCompatibleViewFileSystem(HdfsContext context, HdfsEnvironment hdfsEnvironment, Path path)
+ {
+ try {
+ return getRawFileSystem(hdfsEnvironment.getFileSystem(context, path))
+ .getClass().getName().equals("org.apache.hadoop.fs.viewfs.HDFSCompatibleViewFileSystem");
+ }
+ catch (IOException e) {
+ throw new PrestoException(HIVE_FILESYSTEM_ERROR, "Failed checking path: " + path, e);
+ }
+ }
+
private static FileSystem getRawFileSystem(FileSystem fileSystem)
{
if (fileSystem instanceof FilterFileSystem) {
@@ -556,6 +567,11 @@ public static Path createTemporaryPath(HdfsContext context, HdfsEnvironment hdfs
temporaryPrefix = ".hive-staging";
}
+ // use relative temporary directory on HDFSCompatibleViewFileSystem
+ if (isHDFSCompatibleViewFileSystem(context, hdfsEnvironment, targetPath)) {
+ temporaryPrefix = "../.hive-staging";
+ }
+
// create a temporary directory on the same filesystem
Path temporaryRoot = new Path(targetPath, temporaryPrefix);
Path temporaryPath = new Path(temporaryRoot, randomUUID().toString());
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/RetryDriver.java b/presto-hive/src/main/java/com/facebook/presto/hive/RetryDriver.java
index 911ee8f3712ba..22e1a8127817d 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/RetryDriver.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/RetryDriver.java
@@ -137,16 +137,18 @@ public V run(String callableName, Callable callable)
return callable.call();
}
catch (Exception e) {
+ log.debug("Failed on executing %s with attempt %d, Exception: %s", callableName, attempt, e.getMessage());
e = exceptionMapper.apply(e);
for (Class extends Exception> clazz : exceptionWhiteList) {
if (clazz.isInstance(e)) {
+ log.debug("Exception is in whitelist.");
throw e;
}
}
if (attempt >= maxAttempts || Duration.nanosSince(startTime).compareTo(maxRetryTime) >= 0) {
+ log.debug("Maximum attempts or maximum retry time reached. attempt: %d, maxAttempts: %d, duration: [%s] maxRetryTime: [%s]", attempt, maxAttempts, Duration.nanosSince(startTime).toString(), maxRetryTime.toString());
throw e;
}
- log.debug("Failed on executing %s with attempt %d, will retry. Exception: %s", callableName, attempt, e.getMessage());
int delayInMs = (int) Math.min(minSleepTime.toMillis() * Math.pow(scaleFactor, attempt - 1), maxSleepTime.toMillis());
int jitter = ThreadLocalRandom.current().nextInt(Math.max(1, (int) (delayInMs * 0.1)));
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftMetastoreModule.java b/presto-hive/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftMetastoreModule.java
index 62d94b3875ba0..1ba8ea19281de 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftMetastoreModule.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/metastore/thrift/ThriftMetastoreModule.java
@@ -16,17 +16,21 @@
import com.facebook.presto.hive.ForCachingHiveMetastore;
import com.facebook.presto.hive.metastore.CachingHiveMetastore;
import com.facebook.presto.hive.metastore.ExtendedHiveMetastore;
+import com.facebook.presto.twitter.hive.MetastoreStaticClusterModule;
+import com.facebook.presto.twitter.hive.MetastoreZkDiscoveryBasedModule;
+import com.facebook.presto.twitter.hive.PooledHiveMetastoreClientFactory;
+import com.facebook.presto.twitter.hive.ZookeeperServersetMetastoreConfig;
import com.google.inject.Binder;
-import com.google.inject.Module;
import com.google.inject.Scopes;
+import io.airlift.configuration.AbstractConfigurationAwareModule;
-import static io.airlift.configuration.ConfigBinder.configBinder;
+import static io.airlift.configuration.ConditionalModule.installModuleIf;
import static java.util.Objects.requireNonNull;
import static org.weakref.jmx.ObjectNames.generatedNameOf;
import static org.weakref.jmx.guice.ExportBinder.newExporter;
public class ThriftMetastoreModule
- implements Module
+ extends AbstractConfigurationAwareModule
{
private final String connectorId;
@@ -36,11 +40,11 @@ public ThriftMetastoreModule(String connectorId)
}
@Override
- public void configure(Binder binder)
+ public void setup(Binder binder)
{
binder.bind(HiveMetastoreClientFactory.class).in(Scopes.SINGLETON);
- binder.bind(HiveCluster.class).to(StaticHiveCluster.class).in(Scopes.SINGLETON);
- configBinder(binder).bindConfig(StaticMetastoreConfig.class);
+ binder.bind(PooledHiveMetastoreClientFactory.class).in(Scopes.SINGLETON);
+ bindMetastoreClusterModule();
binder.bind(HiveMetastore.class).to(ThriftHiveMetastore.class).in(Scopes.SINGLETON);
binder.bind(ExtendedHiveMetastore.class).annotatedWith(ForCachingHiveMetastore.class).to(BridgingHiveMetastore.class).in(Scopes.SINGLETON);
@@ -50,4 +54,16 @@ public void configure(Binder binder)
newExporter(binder).export(ExtendedHiveMetastore.class)
.as(generatedNameOf(CachingHiveMetastore.class, connectorId));
}
+
+ private void bindMetastoreClusterModule()
+ {
+ install(installModuleIf(
+ ZookeeperServersetMetastoreConfig.class,
+ zkMetastoreConfig -> zkMetastoreConfig.getZookeeperServerHostAndPort() == null,
+ new MetastoreStaticClusterModule()));
+ install(installModuleIf(
+ ZookeeperServersetMetastoreConfig.class,
+ zkMetastoreConfig -> zkMetastoreConfig.getZookeeperServerHostAndPort() != null,
+ new MetastoreZkDiscoveryBasedModule()));
+ }
}
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSource.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSource.java
index 690b03dc26c2c..248f86f88ecbb 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSource.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSource.java
@@ -38,9 +38,9 @@
import static com.facebook.presto.hive.HiveColumnHandle.ColumnType.REGULAR;
import static com.facebook.presto.hive.HiveErrorCode.HIVE_BAD_DATA;
import static com.facebook.presto.hive.HiveErrorCode.HIVE_CURSOR_ERROR;
-import static com.facebook.presto.hive.parquet.ParquetTypeUtils.getFieldIndex;
+import static com.facebook.presto.hive.parquet.ParquetTypeUtils.findColumnIObyName;
+import static com.facebook.presto.hive.parquet.ParquetTypeUtils.findFieldIndexByName;
import static com.facebook.presto.hive.parquet.ParquetTypeUtils.getParquetType;
-import static com.facebook.presto.hive.parquet.ParquetTypeUtils.lookupColumnByName;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import static parquet.io.ColumnIOConverter.constructField;
@@ -106,7 +106,7 @@ public ParquetPageSource(
}
else {
String columnName = useParquetColumnNames ? name : fileSchema.getFields().get(column.getHiveColumnIndex()).getName();
- fieldsBuilder.add(constructField(type, lookupColumnByName(messageColumnIO, columnName)));
+ fieldsBuilder.add(constructField(type, findColumnIObyName(messageColumnIO, columnName)));
}
}
types = typesBuilder.build();
@@ -164,7 +164,7 @@ public Page getNextPage()
Optional field = fields.get(fieldId);
int fieldIndex;
if (useParquetColumnNames) {
- fieldIndex = getFieldIndex(fileSchema, columnNames.get(fieldId));
+ fieldIndex = findFieldIndexByName(fileSchema, columnNames.get(fieldId));
}
else {
fieldIndex = hiveColumnIndexes[fieldId];
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java
index 5dd5a33f081be..28c80ffabc147 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetPageSourceFactory.java
@@ -27,6 +27,7 @@
import com.facebook.presto.spi.predicate.TupleDomain;
import com.facebook.presto.spi.type.TypeManager;
import com.google.common.collect.ImmutableSet;
+import io.airlift.units.DataSize;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
@@ -54,6 +55,7 @@
import static com.facebook.presto.hive.HiveColumnHandle.ColumnType.REGULAR;
import static com.facebook.presto.hive.HiveErrorCode.HIVE_CANNOT_OPEN_SPLIT;
import static com.facebook.presto.hive.HiveErrorCode.HIVE_MISSING_DATA;
+import static com.facebook.presto.hive.HiveSessionProperties.getParquetMaxReadBlockSize;
import static com.facebook.presto.hive.HiveSessionProperties.isParquetOptimizedReaderEnabled;
import static com.facebook.presto.hive.HiveSessionProperties.isParquetPredicatePushdownEnabled;
import static com.facebook.presto.hive.HiveSessionProperties.isUseParquetColumnNames;
@@ -123,6 +125,7 @@ public Optional extends ConnectorPageSource> createPageSource(
schema,
columns,
isUseParquetColumnNames(session),
+ getParquetMaxReadBlockSize(session),
typeManager,
isParquetPredicatePushdownEnabled(session),
effectivePredicate,
@@ -140,6 +143,7 @@ public static ParquetPageSource createParquetPageSource(
Properties schema,
List columns,
boolean useParquetColumnNames,
+ DataSize maxReadBlockSize,
TypeManager typeManager,
boolean predicatePushdownEnabled,
TupleDomain effectivePredicate,
@@ -186,7 +190,8 @@ public static ParquetPageSource createParquetPageSource(
messageColumnIO,
blocks,
dataSource,
- systemMemoryContext);
+ systemMemoryContext,
+ maxReadBlockSize);
return new ParquetPageSource(
parquetReader,
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetTypeUtils.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetTypeUtils.java
index 88c8bb895dc27..5283e5736ff7a 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetTypeUtils.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/ParquetTypeUtils.java
@@ -217,7 +217,7 @@ public static int getFieldIndex(MessageType fileSchema, String name)
public static parquet.schema.Type getParquetType(HiveColumnHandle column, MessageType messageType, boolean useParquetColumnNames)
{
if (useParquetColumnNames) {
- return getParquetTypeByName(column.getName(), messageType);
+ return findParquetTypeByName(column, messageType);
}
if (column.getHiveColumnIndex() < messageType.getFieldCount()) {
@@ -226,6 +226,56 @@ public static parquet.schema.Type getParquetType(HiveColumnHandle column, Messag
return null;
}
+ /**
+ * Find the column type by name using returning the first match with the following logic:
+ *
+ * - direct match
+ * - case-insensitive match
+ * - if the name ends with _, remove it and direct match
+ * - if the name ends with _, remove it and case-insensitive match
+ *
+ */
+ private static parquet.schema.Type findParquetTypeByName(HiveColumnHandle column, MessageType messageType)
+ {
+ String name = column.getName();
+ parquet.schema.Type type = getParquetTypeByName(name, messageType);
+
+ // when a parquet field is a hive keyword we append an _ to it in hive. When doing
+ // a name-based lookup, we need to strip it off again if we didn't get a direct match.
+ if (type == null && name.endsWith("_")) {
+ type = getParquetTypeByName(name.substring(0, name.length() - 1), messageType);
+ }
+ return type;
+ }
+
+ // Find the column index by name following the same logic as findParquetTypeByName
+ public static int findFieldIndexByName(MessageType fileSchema, String name)
+ {
+ // direct match and case-insensitive match
+ int fieldIndex = getFieldIndex(fileSchema, name);
+
+ // when a parquet field is a hive keyword we append an _ to it in hive.
+ // try remove _ and direct match / case-insensitive match again
+ if (fieldIndex == -1 && name.endsWith("_")) {
+ fieldIndex = getFieldIndex(fileSchema, name.substring(0, name.length() - 1));
+ }
+
+ return fieldIndex;
+ }
+
+ // Find the ColumnIO by name following the same logic as findParquetTypeByName
+ public static ColumnIO findColumnIObyName(GroupColumnIO groupColumnIO, String name)
+ {
+ // direct match and case-insensitive match
+ ColumnIO columnIO = lookupColumnByName(groupColumnIO, name);
+
+ if (columnIO == null && name.endsWith("_")) {
+ columnIO = lookupColumnByName(groupColumnIO, name.substring(0, name.length() - 1));
+ }
+
+ return columnIO;
+ }
+
public static ParquetEncoding getParquetEncoding(Encoding encoding)
{
switch (encoding) {
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/reader/ParquetReader.java b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/reader/ParquetReader.java
index cf6b544fadf25..ad907f69dafda 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/parquet/reader/ParquetReader.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/parquet/reader/ParquetReader.java
@@ -28,6 +28,7 @@
import com.facebook.presto.spi.type.MapType;
import com.facebook.presto.spi.type.Type;
import com.facebook.presto.spi.type.TypeSignatureParameter;
+import io.airlift.units.DataSize;
import it.unimi.dsi.fastutil.booleans.BooleanArrayList;
import it.unimi.dsi.fastutil.booleans.BooleanList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -51,6 +52,7 @@
import static com.facebook.presto.spi.type.StandardTypes.MAP;
import static com.facebook.presto.spi.type.StandardTypes.ROW;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.toIntExact;
import static java.util.Objects.requireNonNull;
@@ -59,6 +61,8 @@ public class ParquetReader
implements Closeable
{
private static final int MAX_VECTOR_LENGTH = 1024;
+ private static final int INITIAL_BATCH_SIZE = 1;
+ private static final int BATCH_SIZE_GROWTH_FACTOR = 2;
private final List blocks;
private final List columns;
@@ -71,21 +75,29 @@ public class ParquetReader
private long currentGroupRowCount;
private long nextRowInGroup;
private int batchSize;
+ private int nextBatchSize = INITIAL_BATCH_SIZE;
private final ParquetPrimitiveColumnReader[] columnReaders;
+ private long[] maxBytesPerCell;
+ private long maxCombinedBytesPerRow;
+ private final long maxReadBlockBytes;
+ private int maxBatchSize = MAX_VECTOR_LENGTH;
private AggregatedMemoryContext currentRowGroupMemoryContext;
public ParquetReader(MessageColumnIO messageColumnIO,
List blocks,
ParquetDataSource dataSource,
- AggregatedMemoryContext systemMemoryContext)
+ AggregatedMemoryContext systemMemoryContext,
+ DataSize maxReadBlockSize)
{
this.blocks = blocks;
this.dataSource = requireNonNull(dataSource, "dataSource is null");
this.systemMemoryContext = requireNonNull(systemMemoryContext, "systemMemoryContext is null");
this.currentRowGroupMemoryContext = systemMemoryContext.newAggregatedMemoryContext();
+ this.maxReadBlockBytes = requireNonNull(maxReadBlockSize, "maxReadBlockSize is null").toBytes();
columns = messageColumnIO.getLeaves();
columnReaders = new ParquetPrimitiveColumnReader[columns.size()];
+ maxBytesPerCell = new long[columns.size()];
}
@Override
@@ -107,8 +119,9 @@ public int nextBatch()
return -1;
}
- batchSize = toIntExact(min(MAX_VECTOR_LENGTH, currentGroupRowCount - nextRowInGroup));
-
+ batchSize = toIntExact(min(nextBatchSize, maxBatchSize));
+ nextBatchSize = min(batchSize * BATCH_SIZE_GROWTH_FACTOR, MAX_VECTOR_LENGTH);
+ batchSize = toIntExact(min(batchSize, currentGroupRowCount - nextRowInGroup));
nextRowInGroup += batchSize;
currentPosition += batchSize;
Arrays.stream(columnReaders)
@@ -193,7 +206,8 @@ private ColumnChunk readPrimitive(PrimitiveField field)
throws IOException
{
ColumnDescriptor columnDescriptor = field.getDescriptor();
- ParquetPrimitiveColumnReader columnReader = columnReaders[field.getId()];
+ int fieldId = field.getId();
+ ParquetPrimitiveColumnReader columnReader = columnReaders[fieldId];
if (columnReader.getPageReader() == null) {
validateParquet(currentBlockMetadata.getRowCount() > 0, "Row group has 0 rows");
ColumnChunkMetaData metadata = getColumnChunkMetaData(columnDescriptor);
@@ -205,7 +219,17 @@ private ColumnChunk readPrimitive(PrimitiveField field)
ParquetColumnChunk columnChunk = new ParquetColumnChunk(descriptor, buffer, 0);
columnReader.setPageReader(columnChunk.readAllPages());
}
- return columnReader.readPrimitive(field);
+ ColumnChunk columnChunk = columnReader.readPrimitive(field);
+
+ // update max size per primitive column chunk
+ long bytesPerCell = columnChunk.getBlock().getSizeInBytes() / batchSize;
+ if (maxBytesPerCell[fieldId] < bytesPerCell) {
+ // update batch size
+ maxCombinedBytesPerRow = maxCombinedBytesPerRow - maxBytesPerCell[fieldId] + bytesPerCell;
+ maxBatchSize = toIntExact(min(maxBatchSize, max(1, maxReadBlockBytes / maxCombinedBytesPerRow)));
+ maxBytesPerCell[fieldId] = bytesPerCell;
+ }
+ return columnChunk;
}
private byte[] allocateBlock(int length)
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/util/HiveFileIterator.java b/presto-hive/src/main/java/com/facebook/presto/hive/util/HiveFileIterator.java
index 4595b720c77ad..19617e4d0abae 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/util/HiveFileIterator.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/util/HiveFileIterator.java
@@ -97,7 +97,14 @@ protected LocatedFileStatus computeNext()
if (paths.isEmpty()) {
return endOfData();
}
- remoteIterator = getLocatedFileStatusRemoteIterator(paths.removeFirst());
+ try {
+ remoteIterator = getLocatedFileStatusRemoteIterator(paths.removeFirst());
+ }
+ catch (PrestoException e) {
+ if (!e.getErrorCode().equals(HIVE_FILE_NOT_FOUND.toErrorCode())) {
+ throw e;
+ }
+ }
}
}
diff --git a/presto-hive/src/main/java/com/facebook/presto/hive/util/InternalHiveSplitFactory.java b/presto-hive/src/main/java/com/facebook/presto/hive/util/InternalHiveSplitFactory.java
index dd19146b5800f..9448b8a27e5bc 100644
--- a/presto-hive/src/main/java/com/facebook/presto/hive/util/InternalHiveSplitFactory.java
+++ b/presto-hive/src/main/java/com/facebook/presto/hive/util/InternalHiveSplitFactory.java
@@ -41,6 +41,7 @@
import java.util.Properties;
import static com.facebook.presto.hive.HiveColumnHandle.isPathColumnHandle;
+import static com.facebook.presto.hive.HiveUtil.isLzopIndexFile;
import static com.facebook.presto.hive.HiveUtil.isSplittable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.ImmutableList.toImmutableList;
@@ -239,6 +240,10 @@ private static Optional getPathDomain(TupleDomain effe
private static boolean pathMatchesPredicate(Optional pathDomain, String path)
{
+ if (isLzopIndexFile(new Path(path))) {
+ return false;
+ }
+
if (!pathDomain.isPresent()) {
return true;
}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreStaticClusterModule.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreStaticClusterModule.java
new file mode 100644
index 0000000000000..8751b5bc474f6
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreStaticClusterModule.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import com.facebook.presto.hive.metastore.thrift.HiveCluster;
+import com.facebook.presto.hive.metastore.thrift.StaticHiveCluster;
+import com.facebook.presto.hive.metastore.thrift.StaticMetastoreConfig;
+import com.google.inject.Binder;
+import com.google.inject.Module;
+import com.google.inject.Scopes;
+
+import static io.airlift.configuration.ConfigBinder.configBinder;
+
+public class MetastoreStaticClusterModule
+ implements Module
+{
+ @Override
+ public void configure(Binder binder)
+ {
+ binder.bind(HiveCluster.class).to(StaticHiveCluster.class).in(Scopes.SINGLETON);
+ configBinder(binder).bindConfig(StaticMetastoreConfig.class);
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreZkDiscoveryBasedModule.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreZkDiscoveryBasedModule.java
new file mode 100644
index 0000000000000..5459eca553054
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/MetastoreZkDiscoveryBasedModule.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import com.facebook.presto.hive.metastore.thrift.HiveCluster;
+import com.google.inject.Binder;
+import com.google.inject.Module;
+import com.google.inject.Scopes;
+
+import static io.airlift.configuration.ConfigBinder.configBinder;
+
+public class MetastoreZkDiscoveryBasedModule
+ implements Module
+{
+ @Override
+ public void configure(Binder binder)
+ {
+ binder.bind(HiveCluster.class).to(ZookeeperServersetHiveCluster.class).in(Scopes.SINGLETON);
+ configBinder(binder).bindConfig(ZookeeperServersetMetastoreConfig.class);
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/PooledHiveMetastoreClientFactory.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/PooledHiveMetastoreClientFactory.java
new file mode 100644
index 0000000000000..270e313e75114
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/PooledHiveMetastoreClientFactory.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import com.facebook.presto.hive.HiveClientConfig;
+import com.facebook.presto.hive.authentication.HiveMetastoreAuthentication;
+import com.facebook.presto.hive.metastore.thrift.HiveMetastoreClient;
+import com.facebook.presto.hive.metastore.thrift.ThriftHiveMetastoreClient;
+import com.facebook.presto.twitter.hive.util.PooledTTransportFactory;
+import com.facebook.presto.twitter.hive.util.TTransportPool;
+import com.google.common.net.HostAndPort;
+import io.airlift.units.Duration;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.transport.TTransportException;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+
+import static java.lang.Math.toIntExact;
+import static java.util.Objects.requireNonNull;
+
+public class PooledHiveMetastoreClientFactory
+{
+ private final HostAndPort socksProxy;
+ private final int timeoutMillis;
+ private final HiveMetastoreAuthentication metastoreAuthentication;
+ private final TTransportPool transportPool;
+
+ public PooledHiveMetastoreClientFactory(@Nullable HostAndPort socksProxy,
+ Duration timeout,
+ HiveMetastoreAuthentication metastoreAuthentication,
+ int maxTransport,
+ long idleTimeout,
+ long transportEvictInterval,
+ int evictNumTests)
+ {
+ this.socksProxy = socksProxy;
+ this.timeoutMillis = toIntExact(timeout.toMillis());
+ this.metastoreAuthentication = requireNonNull(metastoreAuthentication, "metastoreAuthentication is null");
+ GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
+ poolConfig.setMaxIdle(maxTransport);
+ poolConfig.setMaxTotal(maxTransport);
+ poolConfig.setMinEvictableIdleTimeMillis(idleTimeout);
+ poolConfig.setTimeBetweenEvictionRunsMillis(transportEvictInterval);
+ poolConfig.setNumTestsPerEvictionRun(evictNumTests);
+ this.transportPool = new TTransportPool(poolConfig);
+ }
+
+ @Inject
+ public PooledHiveMetastoreClientFactory(HiveClientConfig config,
+ ZookeeperServersetMetastoreConfig zkConfig,
+ HiveMetastoreAuthentication metastoreAuthentication)
+ {
+ this(config.getMetastoreSocksProxy(),
+ config.getMetastoreTimeout(),
+ metastoreAuthentication,
+ zkConfig.getMaxTransport(),
+ zkConfig.getTransportIdleTimeout(),
+ zkConfig.getTransportEvictInterval(),
+ zkConfig.getTransportEvictNumTests());
+ }
+
+ public HiveMetastoreClient create(String host, int port)
+ throws TTransportException
+ {
+ try {
+ TTransport transport = transportPool.borrowObject(host, port);
+ if (transport == null) {
+ transport = transportPool.borrowObject(host, port,
+ new PooledTTransportFactory(transportPool,
+ host, port, socksProxy,
+ timeoutMillis, metastoreAuthentication));
+ }
+ return new ThriftHiveMetastoreClient(transport);
+ }
+ catch (Exception e) {
+ throw new TTransportException(String.format("%s: %s", host, e.getMessage()), e.getCause());
+ }
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperMetastoreMonitor.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperMetastoreMonitor.java
new file mode 100644
index 0000000000000..cf8df021c1a1b
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperMetastoreMonitor.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import com.google.common.net.HostAndPort;
+import io.airlift.log.Logger;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.utils.ZKPaths;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
+
+public class ZookeeperMetastoreMonitor
+ implements PathChildrenCacheListener
+{
+ public static final Logger log = Logger.get(ZookeeperMetastoreMonitor.class);
+ private CuratorFramework client;
+ private PathChildrenCache cache;
+ private ConcurrentMap servers; // (Node_Name->HostAndPort)
+
+ public ZookeeperMetastoreMonitor(String zkServer, String watchPath, int maxRetries, int retrySleepTime)
+ throws Exception
+ {
+ client = CuratorFrameworkFactory.newClient(zkServer, new ExponentialBackoffRetry(retrySleepTime, maxRetries));
+ client.start();
+
+ cache = new PathChildrenCache(client, watchPath, true); // true indicating cache node contents in addition to the stat
+ try {
+ cache.start();
+ }
+ catch (Exception ex) {
+ throw new RuntimeException("Curator PathCache Creation failed: " + ex.getMessage());
+ }
+
+ cache.getListenable().addListener(this);
+ servers = new ConcurrentHashMap<>();
+ }
+
+ public void close()
+ {
+ client.close();
+
+ try {
+ cache.close();
+ }
+ catch (IOException ex) {
+ // do nothing
+ }
+ }
+
+ public List getServers()
+ {
+ return servers.values().stream().collect(Collectors.toList());
+ }
+
+ private HostAndPort deserialize(byte[] bytes)
+ {
+ String serviceEndpoint = "serviceEndpoint";
+ JSONObject data = (JSONObject) JSONValue.parse(new String(bytes));
+ if (data != null && data.containsKey(serviceEndpoint)) {
+ Map hostPortMap = (Map) data.get(serviceEndpoint);
+ String host = hostPortMap.get("host").toString();
+ int port = Integer.parseInt(hostPortMap.get("port").toString());
+ return HostAndPort.fromParts(host, port);
+ }
+ else {
+ log.warn("failed to deserialize child node data");
+ throw new IllegalArgumentException("No host:port found");
+ }
+ }
+
+ @Override
+ public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
+ {
+ switch (event.getType()) {
+ case CHILD_ADDED:
+ case CHILD_UPDATED: {
+ HostAndPort hostPort = deserialize(event.getData().getData());
+ String node = ZKPaths.getNodeFromPath(event.getData().getPath());
+ log.info("child updated: " + node + ": " + hostPort);
+ servers.put(node, hostPort);
+ break;
+ }
+
+ case CHILD_REMOVED: {
+ String node = ZKPaths.getNodeFromPath(event.getData().getPath());
+ log.info("child removed: " + node);
+ servers.remove(node);
+ break;
+ }
+
+ default:
+ log.info("connection state changed: " + event.getType());
+ break;
+ }
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetHiveCluster.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetHiveCluster.java
new file mode 100644
index 0000000000000..c91912f0ff916
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetHiveCluster.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import com.facebook.presto.hive.metastore.thrift.HiveCluster;
+import com.facebook.presto.hive.metastore.thrift.HiveMetastoreClient;
+import com.google.common.net.HostAndPort;
+import io.airlift.log.Logger;
+import org.apache.thrift.transport.TTransportException;
+
+import javax.inject.Inject;
+
+import java.util.Collections;
+import java.util.List;
+
+import static java.util.Objects.requireNonNull;
+
+public class ZookeeperServersetHiveCluster
+ implements HiveCluster
+{
+ private static final Logger log = Logger.get(ZookeeperServersetHiveCluster.class);
+ private final PooledHiveMetastoreClientFactory clientFactory;
+ private ZookeeperMetastoreMonitor zkMetastoreMonitor;
+
+ @Inject
+ public ZookeeperServersetHiveCluster(ZookeeperServersetMetastoreConfig config, PooledHiveMetastoreClientFactory clientFactory)
+ throws Exception
+ {
+ String zkServerHostAndPort = requireNonNull(config.getZookeeperServerHostAndPort(), "zkServerHostAndPort is null");
+ String zkMetastorePath = requireNonNull(config.getZookeeperMetastorePath(), "zkMetastorePath is null");
+ int zkRetries = requireNonNull(config.getZookeeperMaxRetries(), "zkMaxRetried is null");
+ int zkRetrySleepTime = requireNonNull(config.getZookeeperRetrySleepTime(), "zkRetrySleepTime is null");
+ this.clientFactory = requireNonNull(clientFactory, "clientFactory is null");
+ this.zkMetastoreMonitor = new ZookeeperMetastoreMonitor(zkServerHostAndPort, zkMetastorePath, zkRetries, zkRetrySleepTime);
+ }
+
+ @Override
+ public HiveMetastoreClient createMetastoreClient()
+ {
+ List metastores = zkMetastoreMonitor.getServers();
+ Collections.shuffle(metastores);
+ TTransportException lastException = null;
+ for (HostAndPort metastore : metastores) {
+ try {
+ log.info("Connecting to metastore at: %s", metastore.toString());
+ return clientFactory.create(metastore.getHost(), metastore.getPort());
+ }
+ catch (TTransportException e) {
+ log.debug("Failed connecting to Hive metastore at: %s", metastore.toString());
+ lastException = e;
+ }
+ }
+
+ throw new RuntimeException("Failed connecting to Hive metastore.", lastException);
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetMetastoreConfig.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetMetastoreConfig.java
new file mode 100644
index 0000000000000..65b424b6c437e
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/ZookeeperServersetMetastoreConfig.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive;
+
+import io.airlift.configuration.Config;
+import io.airlift.configuration.ConfigDescription;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+public class ZookeeperServersetMetastoreConfig
+{
+ private String zookeeperServerHostAndPort;
+ private String zookeeperMetastorePath;
+ private int zookeeperRetrySleepTime = 500; // ms
+ private int zookeeperMaxRetries = 3;
+ private int maxTransport = 128;
+ private long transportIdleTimeout = 300_000L;
+ private long transportEvictInterval = 10_000L;
+ private int transportEvictNumTests = 3;
+
+ public String getZookeeperServerHostAndPort()
+ {
+ return zookeeperServerHostAndPort;
+ }
+
+ @Config("hive.metastore.zookeeper.uri")
+ @ConfigDescription("Zookeeper Host and Port")
+ public ZookeeperServersetMetastoreConfig setZookeeperServerHostAndPort(String zookeeperServerHostAndPort)
+ {
+ this.zookeeperServerHostAndPort = zookeeperServerHostAndPort;
+ return this;
+ }
+
+ public String getZookeeperMetastorePath()
+ {
+ return zookeeperMetastorePath;
+ }
+
+ @Config("hive.metastore.zookeeper.path")
+ @ConfigDescription("Hive metastore Zookeeper path")
+ public ZookeeperServersetMetastoreConfig setZookeeperMetastorePath(String zkPath)
+ {
+ this.zookeeperMetastorePath = zkPath;
+ return this;
+ }
+
+ @NotNull
+ public int getZookeeperRetrySleepTime()
+ {
+ return zookeeperRetrySleepTime;
+ }
+
+ @Config("hive.metastore.zookeeper.retry.sleeptime")
+ @ConfigDescription("Zookeeper sleep time between reties")
+ public ZookeeperServersetMetastoreConfig setZookeeperRetrySleepTime(int zookeeperRetrySleepTime)
+ {
+ this.zookeeperRetrySleepTime = zookeeperRetrySleepTime;
+ return this;
+ }
+
+ @Min(1)
+ public int getZookeeperMaxRetries()
+ {
+ return zookeeperMaxRetries;
+ }
+
+ @Config("hive.metastore.zookeeper.max.retries")
+ @ConfigDescription("Zookeeper max reties")
+ public ZookeeperServersetMetastoreConfig setZookeeperMaxRetries(int zookeeperMaxRetries)
+ {
+ this.zookeeperMaxRetries = zookeeperMaxRetries;
+ return this;
+ }
+
+ @Min(1)
+ public int getMaxTransport()
+ {
+ return maxTransport;
+ }
+
+ @Config("hive.metastore.max-transport-num")
+ public ZookeeperServersetMetastoreConfig setMaxTransport(int maxTransport)
+ {
+ this.maxTransport = maxTransport;
+ return this;
+ }
+
+ public long getTransportIdleTimeout()
+ {
+ return transportIdleTimeout;
+ }
+
+ @Config("hive.metastore.transport-idle-timeout")
+ public ZookeeperServersetMetastoreConfig setTransportIdleTimeout(long transportIdleTimeout)
+ {
+ this.transportIdleTimeout = transportIdleTimeout;
+ return this;
+ }
+
+ public long getTransportEvictInterval()
+ {
+ return transportEvictInterval;
+ }
+
+ @Config("hive.metastore.transport-eviction-interval")
+ public ZookeeperServersetMetastoreConfig setTransportEvictInterval(long transportEvictInterval)
+ {
+ this.transportEvictInterval = transportEvictInterval;
+ return this;
+ }
+
+ @Min(0)
+ public int getTransportEvictNumTests()
+ {
+ return transportEvictNumTests;
+ }
+
+ @Config("hive.metastore.transport-eviction-num-tests")
+ public ZookeeperServersetMetastoreConfig setTransportEvictNumTests(int transportEvictNumTests)
+ {
+ this.transportEvictNumTests = transportEvictNumTests;
+ return this;
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolver.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolver.java
new file mode 100644
index 0000000000000..077a409fd2a2e
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolver.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.facebook.presto.hive.HiveErrorCode.HIVE_INVALID_METADATA;
+import static com.facebook.presto.hive.HiveUtil.checkCondition;
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Resolve the translation of continuous hive ids to discontinuous thrift ids by using a json property.
+ * Example:
+ * We have the thrift definition:
+ *
+ * struct Name {
+ * 1: string first,
+ * 2: string last
+ * }
+ * struct Person {
+ * 1: Name name,
+ * 3: String phone
+ * }
+ *
+ * Hive table for Person:
+ *
+ * +---------+-------------+----------------------------------+-----------------+
+ * | hive id | column name | type | thrift field id |
+ * +---------+-------------+----------------------------------+-----------------+
+ * | 0 | name | struct | 1 |
+ * +---------+-------------+----------------------------------+-----------------+
+ * | 1 | phone | string | 3 |
+ * +---------+-------------+----------------------------------+-----------------+
+ *
+ * The corresponding id mapping object is:
+ *
+ * x = {
+ * '0': {
+ * '0': 1,
+ * '1': 2,
+ * },
+ * '1': 3
+ * }
+ *
+ * The json property is:
+ *
+ * {"0":{"0":1,"1":2},"1":3}
+ */
+public class HiveThriftFieldIdResolver
+ implements ThriftFieldIdResolver
+{
+ private final JsonNode root;
+ private final Map nestedResolvers = new HashMap<>();
+ private final Map thriftIds = new HashMap<>();
+
+ public HiveThriftFieldIdResolver(JsonNode root)
+ {
+ this.root = root;
+ }
+
+ @Override
+ public short getThriftId(int hiveIndex)
+ {
+ if (root == null) {
+ return (short) (hiveIndex + 1);
+ }
+
+ Short thriftId = thriftIds.get(hiveIndex);
+ if (thriftId != null) {
+ return thriftId;
+ }
+ else {
+ JsonNode child = root.get(String.valueOf(hiveIndex));
+ checkCondition(child != null, HIVE_INVALID_METADATA, "Missed json value for hiveIndex: %s, root: %s", hiveIndex, root);
+ if (child.isNumber()) {
+ thriftId = (short) child.asInt();
+ }
+ else {
+ checkCondition(child.get("id") != null, HIVE_INVALID_METADATA, "Missed id for hiveIndex: %s, root: %s", hiveIndex, root);
+ thriftId = (short) child.get("id").asInt();
+ }
+ thriftIds.put(hiveIndex, thriftId);
+ return thriftId;
+ }
+ }
+
+ @Override
+ public ThriftFieldIdResolver getNestedResolver(int hiveIndex)
+ {
+ if (root == null) {
+ return this;
+ }
+
+ ThriftFieldIdResolver nestedResolver = nestedResolvers.get(hiveIndex);
+ if (nestedResolver != null) {
+ return nestedResolver;
+ }
+ else {
+ JsonNode child = root.get(String.valueOf(hiveIndex));
+ checkCondition(child != null, HIVE_INVALID_METADATA, "Missed json value for hiveIndex: %s, root: %s", hiveIndex, root);
+ nestedResolver = new HiveThriftFieldIdResolver(child);
+ nestedResolvers.put(hiveIndex, nestedResolver);
+ return nestedResolver;
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("root", root)
+ .add("nestedResolvers", nestedResolvers)
+ .add("thriftIds", thriftIds)
+ .toString();
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolverFactory.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolverFactory.java
new file mode 100644
index 0000000000000..c1c736a9f4536
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/HiveThriftFieldIdResolverFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.airlift.log.Logger;
+
+import java.io.IOException;
+import java.util.Properties;
+
+public class HiveThriftFieldIdResolverFactory
+ implements ThriftFieldIdResolverFactory
+{
+ private static final Logger log = Logger.get(HiveThriftFieldIdResolverFactory.class);
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+ public static final String THRIFT_FIELD_ID_JSON = "thrift.field.id.json";
+ // The default resolver which returns thrift id as hive id plus one
+ public static final ThriftFieldIdResolver HIVE_THRIFT_FIELD_ID_DEFAULT_RESOLVER = new HiveThriftFieldIdResolver(null);
+
+ public ThriftFieldIdResolver createResolver(Properties schema)
+ {
+ String jsonData = schema.getProperty(THRIFT_FIELD_ID_JSON);
+ if (jsonData == null) {
+ return HIVE_THRIFT_FIELD_ID_DEFAULT_RESOLVER;
+ }
+
+ try {
+ JsonNode root = objectMapper.readTree(jsonData);
+ return new HiveThriftFieldIdResolver(root);
+ }
+ catch (IOException e) {
+ log.debug(e, "Failed to create an optimized thrift id resolver, json string: %s, schema: %s. Will use a default resolver.", jsonData, schema);
+ }
+
+ return HIVE_THRIFT_FIELD_ID_DEFAULT_RESOLVER;
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolver.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolver.java
new file mode 100644
index 0000000000000..83047e1d953fb
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolver.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+public interface ThriftFieldIdResolver
+{
+ ThriftFieldIdResolver getNestedResolver(int hiveIndex);
+ short getThriftId(int hiveIndex);
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolverFactory.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolverFactory.java
new file mode 100644
index 0000000000000..034308aaa569a
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftFieldIdResolverFactory.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import java.util.Properties;
+
+public interface ThriftFieldIdResolverFactory
+{
+ ThriftFieldIdResolver createResolver(Properties schema);
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralDeserializer.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralDeserializer.java
new file mode 100644
index 0000000000000..001994f7a7e4e
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralDeserializer.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import com.twitter.elephantbird.mapreduce.io.ThriftWritable;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.io.Writable;
+import org.apache.thrift.TException;
+
+import java.util.Properties;
+
+import static com.facebook.presto.hive.HiveErrorCode.HIVE_INVALID_METADATA;
+import static com.facebook.presto.hive.HiveErrorCode.HIVE_UNKNOWN_ERROR;
+import static com.facebook.presto.hive.HiveUtil.checkCondition;
+import static org.apache.hadoop.hive.serde.Constants.SERIALIZATION_CLASS;
+
+public class ThriftGeneralDeserializer
+{
+ private static final String REQUIRED_SERIALIZATION_CLASS = ThriftGenericRow.class.getName();
+ public ThriftGeneralDeserializer(Configuration conf, Properties properties)
+ {
+ String thriftClassName = properties.getProperty(SERIALIZATION_CLASS, null);
+ checkCondition(thriftClassName != null, HIVE_INVALID_METADATA, "Table or partition is missing Hive deserializer property: %s", SERIALIZATION_CLASS);
+ checkCondition(thriftClassName.equals(REQUIRED_SERIALIZATION_CLASS), HIVE_INVALID_METADATA, SERIALIZATION_CLASS + thriftClassName + " cannot match " + REQUIRED_SERIALIZATION_CLASS);
+ }
+
+ public ThriftGenericRow deserialize(Writable writable, short[] thriftIds)
+ {
+ checkCondition(writable instanceof ThriftWritable, HIVE_UNKNOWN_ERROR, "Not an instance of ThriftWritable: " + writable);
+ ThriftGenericRow row = (ThriftGenericRow) ((ThriftWritable) writable).get();
+ try {
+ row.parse(thriftIds);
+ }
+ catch (TException e) {
+ throw new IllegalStateException("ThriftGenericRow failed to parse values", e);
+ }
+ return row;
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralInputFormat.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralInputFormat.java
new file mode 100644
index 0000000000000..1f9690036dbf9
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGeneralInputFormat.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import com.facebook.presto.spi.PrestoException;
+import com.twitter.elephantbird.mapred.input.DeprecatedFileInputFormatWrapper;
+import com.twitter.elephantbird.mapreduce.input.MultiInputFormat;
+import com.twitter.elephantbird.mapreduce.io.BinaryWritable;
+import com.twitter.elephantbird.util.TypeRef;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.io.LongWritable;
+import org.apache.hadoop.mapred.FileSplit;
+import org.apache.hadoop.mapred.InputSplit;
+import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapred.RecordReader;
+import org.apache.hadoop.mapred.Reporter;
+
+import java.io.IOException;
+
+import static com.facebook.presto.hive.HiveErrorCode.HIVE_INVALID_METADATA;
+import static com.facebook.presto.hive.HiveUtil.checkCondition;
+import static com.facebook.presto.hive.HiveUtil.getLzopIndexPath;
+import static com.facebook.presto.hive.HiveUtil.isLzopCompressedFile;
+import static java.lang.String.format;
+import static org.apache.hadoop.hive.serde.Constants.SERIALIZATION_CLASS;
+
+/**
+ * Mirror of com.twitter.elephantbird.mapred.input.HiveMultiInputFormat allows to pass the thriftClassName
+ * directly as a property of JobConfig and check lzo index existence when check splitability.
+ * PR for twitter/elephant-bird:
+ * https://github.com/twitter/elephant-bird/pull/481
+ * https://github.com/twitter/elephant-bird/pull/485
+ * Remove the class once #481 is included in a release
+ */
+@SuppressWarnings("deprecation")
+public class ThriftGeneralInputFormat
+ extends DeprecatedFileInputFormatWrapper
+{
+ public ThriftGeneralInputFormat()
+ {
+ super(new MultiInputFormat());
+ }
+
+ private void initialize(FileSplit split, JobConf job) throws IOException
+ {
+ String thriftClassName = job.get(SERIALIZATION_CLASS);
+ checkCondition(thriftClassName != null, HIVE_INVALID_METADATA, "Table or partition is missing Hive deserializer property: %s", SERIALIZATION_CLASS);
+
+ try {
+ Class thriftClass = job.getClassByName(thriftClassName);
+ setInputFormatInstance(new MultiInputFormat(new TypeRef(thriftClass) {}));
+ }
+ catch (ClassNotFoundException e) {
+ throw new PrestoException(HIVE_INVALID_METADATA, format("Failed getting class for %s", thriftClassName));
+ }
+ }
+
+ @Override
+ public boolean isSplitable(FileSystem fs, Path filename)
+ {
+ if (isLzopCompressedFile(filename)) {
+ Path indexFile = getLzopIndexPath(filename);
+ try {
+ return fs.exists(indexFile);
+ }
+ catch (IOException e) {
+ return false;
+ }
+ }
+ return super.isSplitable(fs, filename);
+ }
+
+ @Override
+ public RecordReader getRecordReader(
+ InputSplit split,
+ JobConf job,
+ Reporter reporter)
+ throws IOException
+ {
+ initialize((FileSplit) split, job);
+ return super.getRecordReader(split, job, reporter);
+ }
+}
diff --git a/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGenericRow.java b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGenericRow.java
new file mode 100644
index 0000000000000..5b961f7d813ac
--- /dev/null
+++ b/presto-hive/src/main/java/com/facebook/presto/twitter/hive/thrift/ThriftGenericRow.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.facebook.presto.twitter.hive.thrift;
+
+import io.airlift.log.Logger;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.thrift.TBase;
+import org.apache.thrift.TException;
+import org.apache.thrift.TFieldIdEnum;
+import org.apache.thrift.protocol.TBinaryProtocol;
+import org.apache.thrift.protocol.TField;
+import org.apache.thrift.protocol.TList;
+import org.apache.thrift.protocol.TMap;
+import org.apache.thrift.protocol.TProtocol;
+import org.apache.thrift.protocol.TProtocolUtil;
+import org.apache.thrift.protocol.TSet;
+import org.apache.thrift.protocol.TType;
+import org.apache.thrift.transport.TMemoryInputTransport;
+import org.apache.thrift.transport.TTransport;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ThriftGenericRow
+ implements TBase
+{
+ private static final Logger log = Logger.get(ThriftGenericRow.class);
+ private final Map values = new HashMap<>();
+ private byte[] buf;
+ private int off;
+ private int len;
+
+ public ThriftGenericRow()
+ {
+ }
+
+ public ThriftGenericRow(Map values)
+ {
+ this.values.putAll(values);
+ }
+
+ public class Fields
+ implements TFieldIdEnum
+ {
+ private final short thriftId;
+ private final String fieldName;
+
+ Fields(short thriftId, String fieldName)
+ {
+ this.thriftId = thriftId;
+ this.fieldName = fieldName;
+ }
+
+ public short getThriftFieldId()
+ {
+ return thriftId;
+ }
+
+ public String getFieldName()
+ {
+ return fieldName;
+ }
+ }
+
+ public void read(TProtocol iprot)
+ throws TException
+ {
+ TTransport trans = iprot.getTransport();
+ buf = trans.getBuffer();
+ off = trans.getBufferPosition();
+ TProtocolUtil.skip(iprot, TType.STRUCT);
+ len = trans.getBufferPosition() - off;
+ }
+
+ public void parse()
+ throws TException
+ {
+ parse(null);
+ }
+
+ public void parse(short[] thriftIds)
+ throws TException
+ {
+ Set idSet = thriftIds == null ? null : new HashSet(Arrays.asList(ArrayUtils.toObject(thriftIds)));
+ TMemoryInputTransport trans = new TMemoryInputTransport(buf, off, len);
+ TBinaryProtocol iprot = new TBinaryProtocol(trans);
+ TField field;
+ iprot.readStructBegin();
+ while (true) {
+ field = iprot.readFieldBegin();
+ if (field.type == TType.STOP) {
+ break;
+ }
+ if (idSet != null && !idSet.remove(Short.valueOf(field.id))) {
+ TProtocolUtil.skip(iprot, field.type);
+ }
+ else {
+ values.put(field.id, readElem(iprot, field.type));
+ }
+ iprot.readFieldEnd();
+ }
+ iprot.readStructEnd();
+ }
+
+ private Object readElem(TProtocol iprot, byte type)
+ throws TException
+ {
+ switch (type) {
+ case TType.BOOL:
+ return iprot.readBool();
+ case TType.BYTE:
+ return iprot.readByte();
+ case TType.I16:
+ return iprot.readI16();
+ case TType.ENUM:
+ case TType.I32:
+ return iprot.readI32();
+ case TType.I64:
+ return iprot.readI64();
+ case TType.DOUBLE:
+ return iprot.readDouble();
+ case TType.STRING:
+ return iprot.readString();
+ case TType.STRUCT:
+ return readStruct(iprot);
+ case TType.LIST:
+ return readList(iprot);
+ case TType.SET:
+ return readSet(iprot);
+ case TType.MAP:
+ return readMap(iprot);
+ default:
+ TProtocolUtil.skip(iprot, type);
+ return null;
+ }
+ }
+
+ private Object readStruct(TProtocol iprot)
+ throws TException
+ {
+ ThriftGenericRow elem = new ThriftGenericRow();
+ elem.read(iprot);
+ elem.parse();
+ return elem;
+ }
+
+ private Object readList(TProtocol iprot)
+ throws TException
+ {
+ TList ilist = iprot.readListBegin();
+ List
diff --git a/presto-jmx/pom.xml b/presto-jmx/pom.xml
index 1cd91957a2997..1d96d2fe2f0f4 100644
--- a/presto-jmx/pom.xml
+++ b/presto-jmx/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-jmx
diff --git a/presto-kafka/pom.xml b/presto-kafka/pom.xml
index 04a0eb833e105..850cf9e6d37fe 100644
--- a/presto-kafka/pom.xml
+++ b/presto-kafka/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-kafka
diff --git a/presto-kafka07/pom.xml b/presto-kafka07/pom.xml
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaConnectorModule.java b/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaConnectorModule.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaInternalFieldDescription.java b/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaInternalFieldDescription.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaMetadata.java b/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaMetadata.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaRecordSet.java b/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaRecordSet.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaRecordSetProvider.java b/presto-kafka07/src/main/java/com/facebook/presto/kafka/KafkaRecordSetProvider.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kafka07/src/test/java/com/facebook/presto/kafka/util/KafkaLoader.java b/presto-kafka07/src/test/java/com/facebook/presto/kafka/util/KafkaLoader.java
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/presto-kudu/pom.xml b/presto-kudu/pom.xml
index c95380f10cda9..224a8826bc6a1 100644
--- a/presto-kudu/pom.xml
+++ b/presto-kudu/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-kudu
diff --git a/presto-local-file/pom.xml b/presto-local-file/pom.xml
index 4d9d8098325b2..04199e8dd06a5 100644
--- a/presto-local-file/pom.xml
+++ b/presto-local-file/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-local-file
diff --git a/presto-main/pom.xml b/presto-main/pom.xml
index 7891442954ab0..3edd1dfa0b7bd 100644
--- a/presto-main/pom.xml
+++ b/presto-main/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-main
diff --git a/presto-main/src/main/java/com/facebook/presto/metadata/DiscoveryNodeManager.java b/presto-main/src/main/java/com/facebook/presto/metadata/DiscoveryNodeManager.java
index ca55deb9f1d64..42ac7b711d612 100644
--- a/presto-main/src/main/java/com/facebook/presto/metadata/DiscoveryNodeManager.java
+++ b/presto-main/src/main/java/com/facebook/presto/metadata/DiscoveryNodeManager.java
@@ -133,12 +133,18 @@ public void startPollingNodeStates()
Set deadNodes = difference(nodeStates.keySet(), aliveNodeIds).immutableCopy();
nodeStates.keySet().removeAll(deadNodes);
+ if (deadNodes.size() > 0) {
+ log.warn("Dead nodes: %s", deadNodes);
+ }
+
// Add new nodes
for (Node node : aliveNodes) {
nodeStates.putIfAbsent(node.getNodeIdentifier(),
new RemoteNodeState(httpClient, uriBuilderFrom(node.getHttpUri()).appendPath("/v1/info/state").build()));
}
+ log.debug("Number of alive nodes: %d", nodeStates.size());
+
// Schedule refresh
nodeStates.values().forEach(RemoteNodeState::asyncRefresh);
}, 1, 5, TimeUnit.SECONDS);
diff --git a/presto-main/src/main/java/com/facebook/presto/server/JavaVersion.java b/presto-main/src/main/java/com/facebook/presto/server/JavaVersion.java
index b5fd1ab4fafa2..a7e72f2b68995 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/JavaVersion.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/JavaVersion.java
@@ -28,7 +28,7 @@
public class JavaVersion
{
// As described in JEP-223
- private static final String VERSION_NUMBER = "(?[1-9][0-9]*)(\\.(?(0|[1-9][0-9]*))(\\.(?:(0|[1-9][0-9]*)))?)?";
+ private static final String VERSION_NUMBER = "(?[1-9][0-9]*)(\\.(?(0|[1-9][0-9]*))(\\.(?:(0|[1-9][0-9]*)))?)*";
private static final String PRE = "(?:-(?:[a-zA-Z0-9]+))?";
private static final String BUILD = "(?:(?:\\+)(?:0|[1-9][0-9]*)?)?";
private static final String OPT = "(?:-(?:[-a-zA-Z0-9.]+))?";
diff --git a/presto-main/src/main/java/com/facebook/presto/server/PrestoServer.java b/presto-main/src/main/java/com/facebook/presto/server/PrestoServer.java
index bd5916c4b323f..013e6750c3dec 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/PrestoServer.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/PrestoServer.java
@@ -107,8 +107,6 @@ public void run()
new ServerMainModule(sqlParserOptions),
new GracefulShutdownModule());
- modules.addAll(getAdditionalModules());
-
Bootstrap app = new Bootstrap(modules.build());
try {
@@ -141,11 +139,6 @@ public void run()
}
}
- protected Iterable extends Module> getAdditionalModules()
- {
- return ImmutableList.of();
- }
-
private static void updateConnectorIds(Announcer announcer, CatalogManager metadata, ServerConfig serverConfig, NodeSchedulerConfig schedulerConfig)
{
// get existing announcement
diff --git a/presto-main/src/main/java/com/facebook/presto/server/PrestoSystemRequirements.java b/presto-main/src/main/java/com/facebook/presto/server/PrestoSystemRequirements.java
index 7f2abfe5a98aa..ae289f86b71e0 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/PrestoSystemRequirements.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/PrestoSystemRequirements.java
@@ -54,7 +54,7 @@ private static void verifyJvmVendor()
{
String vendor = StandardSystemProperty.JAVA_VENDOR.value();
if (!"Oracle Corporation".equals(vendor)) {
- failRequirement("Presto requires an Oracle or OpenJDK JVM (found %s)", vendor);
+ warnRequirement("Presto requires an Oracle or OpenJDK JVM (found %s)", vendor);
}
}
diff --git a/presto-main/src/main/java/com/facebook/presto/server/ServerConfig.java b/presto-main/src/main/java/com/facebook/presto/server/ServerConfig.java
index bbe127c6979c5..19a25ce502ab8 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/ServerConfig.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/ServerConfig.java
@@ -28,6 +28,7 @@ public class ServerConfig
private boolean includeExceptionInResponse = true;
private Duration gracePeriod = new Duration(2, MINUTES);
private boolean enhancedErrorReporting = true;
+ private boolean maintenanceCoordinator;
public boolean isCoordinator()
{
@@ -106,4 +107,16 @@ public ServerConfig setEnhancedErrorReporting(boolean value)
this.enhancedErrorReporting = value;
return this;
}
+
+ public boolean isMaintenanceCoordinator()
+ {
+ return maintenanceCoordinator;
+ }
+
+ @Config("maintenance.coordinator")
+ public ServerConfig setMaintenanceCoordinator(boolean maintenanceCoordinator)
+ {
+ this.maintenanceCoordinator = maintenanceCoordinator;
+ return this;
+ }
}
diff --git a/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java b/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java
index bcbffc7ba53ea..ec0ee8fb6dadd 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/ServerMainModule.java
@@ -137,6 +137,7 @@
import com.google.inject.Provides;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
+import com.twitter.presto.maintenance.MaintenanceCoordinatorModule;
import io.airlift.concurrent.BoundedExecutor;
import io.airlift.configuration.AbstractConfigurationAwareModule;
import io.airlift.slice.Slice;
@@ -193,6 +194,9 @@ protected void setup(Binder binder)
if (serverConfig.isCoordinator()) {
install(new CoordinatorModule());
+ if (serverConfig.isMaintenanceCoordinator()) {
+ install(new MaintenanceCoordinatorModule());
+ }
}
else {
// Install no-op session supplier on workers, since only coordinators create sessions.
diff --git a/presto-main/src/main/java/com/facebook/presto/server/protocol/StatementResource.java b/presto-main/src/main/java/com/facebook/presto/server/protocol/StatementResource.java
index da49095deb1db..3a10eb3f3fc8b 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/protocol/StatementResource.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/protocol/StatementResource.java
@@ -70,6 +70,7 @@
import static com.facebook.presto.client.PrestoHeaders.PRESTO_STARTED_TRANSACTION_ID;
import static com.facebook.presto.memory.context.AggregatedMemoryContext.newSimpleAggregatedMemoryContext;
import static com.google.common.base.Strings.isNullOrEmpty;
+import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.net.HttpHeaders.X_FORWARDED_PROTO;
import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
import static io.airlift.concurrent.Threads.threadsNamed;
@@ -139,6 +140,23 @@ public Response createQuery(
proto = uriInfo.getRequestUri().getScheme();
}
+ // The Teradata Presto ODBC Driver checks node version to decide the Presto's statement
+ // protocol and sends test queries about PREPARE statement.
+ // Rewrite the statement so that Presto always returns version for the compatible protocol.
+ // Ban the statement which will never be consumed by the driver.
+ if (nullToEmpty(servletRequest.getHeader("User-Agent")).equals("Teradata Presto ODBC Driver")) {
+ if (statement.equals("select node_version from system.runtime.nodes where coordinator=true")) {
+ statement = "select '0.148' as node_version";
+ }
+ else if (statement.equals("DESCRIBE OUTPUT prepare_test_stmt")) {
+ throw new WebApplicationException(Response
+ .status(Status.BAD_REQUEST)
+ .type(MediaType.TEXT_PLAIN)
+ .entity("SQL statement is known, and wouldn't be consumed by this driver")
+ .build());
+ }
+ }
+
SessionContext sessionContext = new HttpRequestSessionContext(servletRequest);
ExchangeClient exchangeClient = exchangeClientSupplier.get(new SimpleLocalMemoryContext(newSimpleAggregatedMemoryContext(), StatementResource.class.getSimpleName()));
diff --git a/presto-main/src/main/java/com/facebook/presto/server/security/AuthenticationFilter.java b/presto-main/src/main/java/com/facebook/presto/server/security/AuthenticationFilter.java
index d7b6c1a4a64fb..9381da12d67c4 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/security/AuthenticationFilter.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/security/AuthenticationFilter.java
@@ -44,11 +44,15 @@ public class AuthenticationFilter
implements Filter
{
private final List authenticators;
+ private final String httpAuthenticationPathRegex;
+ private final boolean allowByPass;
@Inject
- public AuthenticationFilter(List authenticators)
+ public AuthenticationFilter(Set authenticators, SecurityConfig securityConfig)
{
this.authenticators = ImmutableList.copyOf(authenticators);
+ this.httpAuthenticationPathRegex = requireNonNull(securityConfig.getHttpAuthenticationPathRegex(), "httpAuthenticationPathRegex is null");
+ this.allowByPass = securityConfig.getAllowByPass();
}
@Override
@@ -64,8 +68,8 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
- // skip authentication if non-secure or not configured
- if (!request.isSecure() || authenticators.isEmpty()) {
+ // skip authentication if (not configured) or (non-secure and not match httpAuthenticationPathRegex)
+ if (authenticators.isEmpty() || (!request.isSecure() && !request.getPathInfo().matches(httpAuthenticationPathRegex))) {
nextFilter.doFilter(request, response);
return;
}
@@ -92,6 +96,12 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
return;
}
+ // if authentication by pass allowed.
+ if (allowByPass) {
+ nextFilter.doFilter(request, response);
+ return;
+ }
+
// authentication failed
skipRequestBody(request);
diff --git a/presto-main/src/main/java/com/facebook/presto/server/security/KerberosAuthenticator.java b/presto-main/src/main/java/com/facebook/presto/server/security/KerberosAuthenticator.java
index 6ecd91a6f1dd4..581b86ff6ac2c 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/security/KerberosAuthenticator.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/security/KerberosAuthenticator.java
@@ -64,8 +64,9 @@ public KerberosAuthenticator(KerberosConfig config)
System.setProperty("java.security.krb5.conf", config.getKerberosConfig().getAbsolutePath());
try {
+ boolean isCompleteServicePrinciple = config.getServiceName().contains("@");
String hostname = InetAddress.getLocalHost().getCanonicalHostName().toLowerCase(Locale.US);
- String servicePrincipal = config.getServiceName() + "/" + hostname;
+ String servicePrincipal = isCompleteServicePrinciple ? config.getServiceName() : config.getServiceName() + "/" + hostname;
loginContext = new LoginContext("", null, null, new Configuration()
{
@Override
@@ -91,7 +92,7 @@ public AppConfigurationEntry[] getAppConfigurationEntry(String name)
loginContext.login();
serverCredential = doAs(loginContext.getSubject(), () -> gssManager.createCredential(
- gssManager.createName(config.getServiceName() + "@" + hostname, GSSName.NT_HOSTBASED_SERVICE),
+ isCompleteServicePrinciple ? gssManager.createName(config.getServiceName(), GSSName.NT_USER_NAME) : gssManager.createName(config.getServiceName() + "@" + hostname, GSSName.NT_HOSTBASED_SERVICE),
INDEFINITE_LIFETIME,
new Oid[] {
new Oid("1.2.840.113554.1.2.2"), // kerberos 5
diff --git a/presto-main/src/main/java/com/facebook/presto/server/security/SecurityConfig.java b/presto-main/src/main/java/com/facebook/presto/server/security/SecurityConfig.java
index 68293cfcba462..bf275b64a1107 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/security/SecurityConfig.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/security/SecurityConfig.java
@@ -33,6 +33,10 @@ public class SecurityConfig
private List authenticationTypes = ImmutableList.of();
+ private String httpAuthenticationPathRegex = "^\b$";
+
+ private boolean allowByPass;
+
public enum AuthenticationType
{
CERTIFICATE,
@@ -67,4 +71,31 @@ public SecurityConfig setAuthenticationTypes(String types)
.collect(toImmutableList());
return this;
}
+
+ @NotNull
+ public String getHttpAuthenticationPathRegex()
+ {
+ return httpAuthenticationPathRegex;
+ }
+
+ @Config("http-server.http.authentication.path.regex")
+ @ConfigDescription("Regex of path that needs to be authenticated for non-secured http request")
+ public SecurityConfig setHttpAuthenticationPathRegex(String regex)
+ {
+ httpAuthenticationPathRegex = regex;
+ return this;
+ }
+
+ public boolean getAllowByPass()
+ {
+ return allowByPass;
+ }
+
+ @Config("http-server.authentication.allow-by-pass")
+ @ConfigDescription("Allow authentication by pass")
+ public SecurityConfig setAllowByPass(boolean allowByPass)
+ {
+ this.allowByPass = allowByPass;
+ return this;
+ }
}
diff --git a/presto-main/src/main/java/com/facebook/presto/server/security/ServerSecurityModule.java b/presto-main/src/main/java/com/facebook/presto/server/security/ServerSecurityModule.java
index 81cfb07628828..d65e0900a9660 100644
--- a/presto-main/src/main/java/com/facebook/presto/server/security/ServerSecurityModule.java
+++ b/presto-main/src/main/java/com/facebook/presto/server/security/ServerSecurityModule.java
@@ -42,6 +42,7 @@ protected void setup(Binder binder)
{
newSetBinder(binder, Filter.class, TheServlet.class).addBinding()
.to(AuthenticationFilter.class).in(Scopes.SINGLETON);
+ configBinder(binder).bindConfig(SecurityConfig.class);
binder.bind(PasswordAuthenticatorManager.class).in(Scopes.SINGLETON);
diff --git a/presto-main/src/main/java/com/facebook/presto/type/RowParametricType.java b/presto-main/src/main/java/com/facebook/presto/type/RowParametricType.java
index 92892f8fa6115..22ab9bf8ce917 100644
--- a/presto-main/src/main/java/com/facebook/presto/type/RowParametricType.java
+++ b/presto-main/src/main/java/com/facebook/presto/type/RowParametricType.java
@@ -13,6 +13,7 @@
*/
package com.facebook.presto.type;
+import com.facebook.presto.spi.type.NamedType;
import com.facebook.presto.spi.type.NamedTypeSignature;
import com.facebook.presto.spi.type.ParameterKind;
import com.facebook.presto.spi.type.ParametricType;
@@ -26,6 +27,7 @@
import com.facebook.presto.spi.type.TypeSignatureParameter;
import java.util.List;
+import java.util.Optional;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.stream.Collectors.toList;
@@ -48,7 +50,9 @@ public String getName()
@Override
public Type createType(TypeManager typeManager, List parameters)
{
- checkArgument(!parameters.isEmpty(), "Row type must have at least one parameter");
+ if (parameters.isEmpty()) {
+ parameters.add(TypeParameter.of(new NamedType(Optional.of(new RowFieldName(UnknownType.NAME, false)), UnknownType.UNKNOWN)));
+ }
checkArgument(
parameters.stream().allMatch(parameter -> parameter.getKind() == ParameterKind.NAMED_TYPE),
"Expected only named types as a parameters, got %s",
diff --git a/presto-main/src/main/java/com/twitter/presto/maintenance/ForMaintenance.java b/presto-main/src/main/java/com/twitter/presto/maintenance/ForMaintenance.java
new file mode 100644
index 0000000000000..66aff04827f67
--- /dev/null
+++ b/presto-main/src/main/java/com/twitter/presto/maintenance/ForMaintenance.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.twitter.presto.maintenance;
+
+import javax.inject.Qualifier;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Retention(RUNTIME)
+@Target({FIELD, PARAMETER, METHOD})
+@Qualifier
+public @interface ForMaintenance
+{
+}
diff --git a/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorModule.java b/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorModule.java
new file mode 100644
index 0000000000000..70a9750d551be
--- /dev/null
+++ b/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorModule.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.twitter.presto.maintenance;
+
+import com.google.inject.Binder;
+import com.google.inject.Module;
+
+import static io.airlift.http.client.HttpClientBinder.httpClientBinder;
+import static io.airlift.jaxrs.JaxrsBinder.jaxrsBinder;
+
+public class MaintenanceCoordinatorModule
+ implements Module
+{
+ @Override
+ public void configure(Binder binder)
+ {
+ httpClientBinder(binder).bindHttpClient("maintenance", ForMaintenance.class);
+ jaxrsBinder(binder).bind(MaintenanceCoordinatorResource.class);
+ }
+}
diff --git a/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorResource.java b/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorResource.java
new file mode 100644
index 0000000000000..1624967eb432c
--- /dev/null
+++ b/presto-main/src/main/java/com/twitter/presto/maintenance/MaintenanceCoordinatorResource.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.twitter.presto.maintenance;
+
+import com.facebook.presto.spi.NodeState;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import io.airlift.http.client.HttpClient;
+import io.airlift.http.client.Request;
+import io.airlift.json.JsonCodec;
+import io.airlift.log.Logger;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+import java.io.IOException;
+import java.net.URI;
+
+import static com.google.common.net.MediaType.JSON_UTF_8;
+import static io.airlift.http.client.HttpUriBuilder.uriBuilderFrom;
+import static io.airlift.http.client.JsonBodyGenerator.jsonBodyGenerator;
+import static io.airlift.http.client.JsonResponseHandler.createJsonResponseHandler;
+import static io.airlift.http.client.Request.Builder.prepareGet;
+import static io.airlift.http.client.Request.Builder.preparePut;
+import static io.airlift.http.client.StatusResponseHandler.createStatusResponseHandler;
+import static io.airlift.json.JsonCodec.jsonCodec;
+import static java.util.Objects.requireNonNull;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
+import static javax.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
+
+@Path("/canDrain")
+public class MaintenanceCoordinatorResource
+{
+ private static final Logger log = Logger.get(MaintenanceCoordinatorResource.class);
+ private static final JsonCodec NODE_STATE_CODEC = jsonCodec(NodeState.class);
+ private static final ObjectMapper jsonObjectMapper = new ObjectMapper();
+ private final HttpClient httpClient;
+
+ @Inject
+ public MaintenanceCoordinatorResource(@ForMaintenance HttpClient httpClient)
+ {
+ this.httpClient = requireNonNull(httpClient, "httpClient is null");
+ }
+
+ @POST
+ public DrainResponse canDrain(String jsonString)
+ {
+ URI nodeUri = extractHostUri(jsonString);
+ log.info("Try draining node : " + nodeUri);
+
+ // check the state of the target node
+ NodeState state = getNodeState(nodeUri);
+
+ // if the node is active, we send the shutdown request
+ if (state == NodeState.ACTIVE) {
+ shutdownNode(nodeUri);
+ }
+ return new DrainResponse(false);
+
+ // We should NEVER return "true" to drain request. What will happen is that the first request will request graceful shutdown in the target and the target node
+ // state will transfer from ACTIVE to SHUTTING_DOWN. When the shutdown is completed, getNodeState() will fail and the exception will propagate to aurora COp.
+ // COp always list active tasks before requesting drain, but there is a race condition which may expose a small window where the task finishes between COp list the
+ // active tasks and maintenance coordinator query the state of the target. COp will treat the exception as a NO, and the next retry should proceed without requesting
+ // maintenance coordinator.
+ }
+
+ private NodeState getNodeState(URI nodeUri)
+ {
+ // synchronously send SHUTTING_DOWN request to worker node
+ Request request = prepareGet()
+ .setUri(getNodeStateUri(nodeUri))
+ .setHeader(CONTENT_TYPE, JSON_UTF_8.toString())
+ .build();
+
+ NodeState nodeState = httpClient.execute(request, createJsonResponseHandler(NODE_STATE_CODEC));
+
+ log.info("Node " + nodeUri + " in state : " + nodeState);
+ return nodeState;
+ }
+
+ private void shutdownNode(URI nodeUri)
+ {
+ log.info("Shutting down node : " + nodeUri);
+ Request request = preparePut()
+ .setUri(getNodeStateUri(nodeUri))
+ .setHeader(CONTENT_TYPE, JSON_UTF_8.toString())
+ .setBodyGenerator(jsonBodyGenerator(jsonCodec(NodeState.class), NodeState.SHUTTING_DOWN))
+ .build();
+
+ httpClient.execute(request, createStatusResponseHandler());
+ }
+
+ // extract the worker node URI from the request body
+ private URI extractHostUri(String message)
+ {
+ try {
+ JsonNode jsonRoot = jsonObjectMapper.readTree(message);
+ String hostName = jsonRoot
+ .get("taskConfig")
+ .get("assignedTask")
+ .get("slaveHost")
+ .asText();
+ int port = jsonRoot
+ .get("taskConfig")
+ .get("assignedTask")
+ .get("assignedPorts")
+ .get("http")
+ .asInt();
+ return URI.create("http://" + hostName + ":" + port);
+ }
+ catch (IOException e) {
+ String errorMessage = "Malformed Json body in drain request " + message;
+ log.warn(e, errorMessage);
+ throw new WebApplicationException(
+ Response.status(Response.Status.BAD_REQUEST)
+ .type(TEXT_PLAIN_TYPE)
+ .entity(errorMessage)
+ .build());
+ }
+ }
+
+ private URI getNodeStateUri(URI nodeUri)
+ {
+ return uriBuilderFrom(nodeUri).appendPath("/v1/info/state").build();
+ }
+
+ public static class DrainResponse
+ {
+ private final boolean drain;
+
+ @JsonCreator
+ public DrainResponse(@JsonProperty("drain") boolean drain)
+ {
+ this.drain = drain;
+ }
+
+ @JsonProperty
+ public boolean getDrain()
+ {
+ return drain;
+ }
+ }
+}
diff --git a/presto-main/src/main/resources/webapp/tableau/presto-client.js b/presto-main/src/main/resources/webapp/tableau/presto-client.js
index 3bc357dd1b659..14de90193895b 100644
--- a/presto-main/src/main/resources/webapp/tableau/presto-client.js
+++ b/presto-main/src/main/resources/webapp/tableau/presto-client.js
@@ -17,6 +17,8 @@ function StatementClient(connectionData, headerCallback, dataCallback, errorCall
this.currentResults = null;
this.valid = true;
+ this.isHttps = window.location.protocol === "https:"
+
if (!(connectionData.sessionParameters === undefined)) {
var parameterMap = JSON.parse(connectionData.sessionParameters);
for (var name in parameterMap) {
@@ -72,7 +74,7 @@ StatementClient.prototype.advance = function(lastRecordNumber) {
var statementClient = this;
$.ajax({
type: "GET",
- url: this.currentResults.nextUri,
+ url: this.isHttps ? this.currentResults.nextUri.replace(/^http:/, 'https:') : this.currentResults.nextUri,
headers: this.headers,
dataType: 'json',
// FIXME having problems when async: true
diff --git a/presto-main/src/test/java/com/facebook/presto/server/TestServerConfig.java b/presto-main/src/test/java/com/facebook/presto/server/TestServerConfig.java
index de9c5c7fbd786..a435def1e5272 100644
--- a/presto-main/src/test/java/com/facebook/presto/server/TestServerConfig.java
+++ b/presto-main/src/test/java/com/facebook/presto/server/TestServerConfig.java
@@ -35,6 +35,7 @@ public void testDefaults()
.setDataSources(null)
.setIncludeExceptionInResponse(true)
.setGracePeriod(new Duration(2, MINUTES))
+ .setMaintenanceCoordinator(false)
.setEnhancedErrorReporting(true));
}
@@ -48,6 +49,7 @@ public void testExplicitPropertyMappings()
.put("http.include-exception-in-response", "false")
.put("shutdown.grace-period", "5m")
.put("sql.parser.enhanced-error-reporting", "false")
+ .put("maintenance.coordinator", "true")
.build();
ServerConfig expected = new ServerConfig()
@@ -56,6 +58,7 @@ public void testExplicitPropertyMappings()
.setDataSources("jmx")
.setIncludeExceptionInResponse(false)
.setGracePeriod(new Duration(5, MINUTES))
+ .setMaintenanceCoordinator(true)
.setEnhancedErrorReporting(false);
assertFullMapping(properties, expected);
diff --git a/presto-main/src/test/java/com/facebook/presto/server/security/TestSecurityConfig.java b/presto-main/src/test/java/com/facebook/presto/server/security/TestSecurityConfig.java
index 96beefb828f7c..7773603588574 100644
--- a/presto-main/src/test/java/com/facebook/presto/server/security/TestSecurityConfig.java
+++ b/presto-main/src/test/java/com/facebook/presto/server/security/TestSecurityConfig.java
@@ -29,7 +29,9 @@ public class TestSecurityConfig
public void testDefaults()
{
ConfigAssertions.assertRecordedDefaults(ConfigAssertions.recordDefaults(SecurityConfig.class)
- .setAuthenticationTypes(""));
+ .setAuthenticationTypes("")
+ .setHttpAuthenticationPathRegex("^\b$")
+ .setAllowByPass(false));
}
@Test
@@ -37,10 +39,14 @@ public void testExplicitPropertyMappings()
{
Map properties = new ImmutableMap.Builder()
.put("http-server.authentication.type", "KERBEROS,PASSWORD")
+ .put("http-server.http.authentication.path.regex", "^/v1/statement")
+ .put("http-server.authentication.allow-by-pass", "true")
.build();
SecurityConfig expected = new SecurityConfig()
- .setAuthenticationTypes(ImmutableList.of(KERBEROS, PASSWORD));
+ .setAuthenticationTypes(ImmutableList.of(KERBEROS, PASSWORD))
+ .setHttpAuthenticationPathRegex("^/v1/statement")
+ .setAllowByPass(true);
ConfigAssertions.assertFullMapping(properties, expected);
}
diff --git a/presto-matching/pom.xml b/presto-matching/pom.xml
index 8a4c3941a91e9..4751fad8b1408 100644
--- a/presto-matching/pom.xml
+++ b/presto-matching/pom.xml
@@ -18,7 +18,7 @@
presto-root
com.facebook.presto
- 0.210
+ 0.210-tw-0.61
presto-matching
diff --git a/presto-memory-context/pom.xml b/presto-memory-context/pom.xml
index 7199f8ca5bb40..0b64e4201690a 100644
--- a/presto-memory-context/pom.xml
+++ b/presto-memory-context/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-memory-context
diff --git a/presto-memory/pom.xml b/presto-memory/pom.xml
index ba3b35aaba703..f9d0af4aac280 100644
--- a/presto-memory/pom.xml
+++ b/presto-memory/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-memory
diff --git a/presto-ml/pom.xml b/presto-ml/pom.xml
index 379a1bc9e5b68..8fc8188257b22 100644
--- a/presto-ml/pom.xml
+++ b/presto-ml/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-ml
diff --git a/presto-mongodb/pom.xml b/presto-mongodb/pom.xml
index f7556658a2841..9481c4df5456b 100644
--- a/presto-mongodb/pom.xml
+++ b/presto-mongodb/pom.xml
@@ -4,7 +4,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-mongodb
diff --git a/presto-mysql/pom.xml b/presto-mysql/pom.xml
index 6833037f5544e..e9cfc03141a81 100644
--- a/presto-mysql/pom.xml
+++ b/presto-mysql/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-mysql
diff --git a/presto-orc/pom.xml b/presto-orc/pom.xml
index f64ae452a3dc9..7fd98bc6b1b0e 100644
--- a/presto-orc/pom.xml
+++ b/presto-orc/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-orc
diff --git a/presto-parser/pom.xml b/presto-parser/pom.xml
index afcc9bea28e83..22f9be4e0a6a0 100644
--- a/presto-parser/pom.xml
+++ b/presto-parser/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-parser
diff --git a/presto-password-authenticators/pom.xml b/presto-password-authenticators/pom.xml
index c5adf1238ebc6..7b53e0e8763c5 100644
--- a/presto-password-authenticators/pom.xml
+++ b/presto-password-authenticators/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-password-authenticators
diff --git a/presto-plugin-toolkit/pom.xml b/presto-plugin-toolkit/pom.xml
index 3af756818b147..0487b866f46dd 100644
--- a/presto-plugin-toolkit/pom.xml
+++ b/presto-plugin-toolkit/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-plugin-toolkit
diff --git a/presto-postgresql/pom.xml b/presto-postgresql/pom.xml
index d0dcc83f0b465..84471fd5616a4 100644
--- a/presto-postgresql/pom.xml
+++ b/presto-postgresql/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-postgresql
diff --git a/presto-product-tests/conf/presto/etc/singlenode-kerberized.properties b/presto-product-tests/conf/presto/etc/singlenode-kerberized.properties
index da8640e97ed4f..4d842152dd7c1 100644
--- a/presto-product-tests/conf/presto/etc/singlenode-kerberized.properties
+++ b/presto-product-tests/conf/presto/etc/singlenode-kerberized.properties
@@ -19,7 +19,7 @@ discovery.uri=https://presto-master.docker.cluster:7778
http.authentication.krb5.config=/etc/krb5.conf
http-server.authentication.type=KERBEROS,CERTIFICATE
-http.server.authentication.krb5.service-name=presto-server
+http.server.authentication.krb5.service-name=presto-server/presto-master.docker.cluster@LABS.TERADATA.COM
http-server.http.enabled=false
http-server.https.enabled=true
http-server.https.port=7778
diff --git a/presto-product-tests/conf/tempto/tempto-configuration-for-docker-kerberos.yaml b/presto-product-tests/conf/tempto/tempto-configuration-for-docker-kerberos.yaml
index 6e9c06e2a0403..97366c081826b 100644
--- a/presto-product-tests/conf/tempto/tempto-configuration-for-docker-kerberos.yaml
+++ b/presto-product-tests/conf/tempto/tempto-configuration-for-docker-kerberos.yaml
@@ -39,7 +39,7 @@ databases:
cli_kerberos_principal: presto-client/presto-master.docker.cluster@LABS.TERADATA.COM
cli_kerberos_keytab: /etc/presto/conf/presto-client.keytab
cli_kerberos_config_path: /etc/krb5.conf
- cli_kerberos_service_name: presto-server
+ cli_kerberos_service_name: presto-server/presto-master.docker.cluster@LABS.TERADATA.COM
cli_kerberos_use_canonical_hostname: false
configured_hdfs_user: hdfs
diff --git a/presto-product-tests/pom.xml b/presto-product-tests/pom.xml
index 830af0ebb4735..f9845d00bef52 100644
--- a/presto-product-tests/pom.xml
+++ b/presto-product-tests/pom.xml
@@ -5,7 +5,7 @@
presto-root
com.facebook.presto
- 0.210
+ 0.210-tw-0.61
presto-product-tests
diff --git a/presto-product-tests/src/main/java/com/facebook/presto/tests/hive/TestHiveCoercion.java b/presto-product-tests/src/main/java/com/facebook/presto/tests/hive/TestHiveCoercion.java
index 7adc0335ef51e..b82b1cb5ddcfd 100644
--- a/presto-product-tests/src/main/java/com/facebook/presto/tests/hive/TestHiveCoercion.java
+++ b/presto-product-tests/src/main/java/com/facebook/presto/tests/hive/TestHiveCoercion.java
@@ -256,7 +256,6 @@ public void testHiveCoercionAvro()
private void doTestHiveCoercion(HiveTableDefinition tableDefinition)
{
String tableName = mutableTableInstanceOf(tableDefinition).getNameInDatabase();
-
String floatToDoubleType = tableName.toLowerCase(Locale.ENGLISH).contains("parquet") ? "DOUBLE" : "REAL";
query(format(
diff --git a/presto-proxy/pom.xml b/presto-proxy/pom.xml
index 74c58fb7147be..47b1569375a5c 100644
--- a/presto-proxy/pom.xml
+++ b/presto-proxy/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-proxy
diff --git a/presto-raptor/pom.xml b/presto-raptor/pom.xml
index 7df8064b391a8..244e74bf9c4a6 100644
--- a/presto-raptor/pom.xml
+++ b/presto-raptor/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-raptor
diff --git a/presto-rcfile/pom.xml b/presto-rcfile/pom.xml
index 0647cfc20a057..f6dd8d27e9242 100644
--- a/presto-rcfile/pom.xml
+++ b/presto-rcfile/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-rcfile
diff --git a/presto-record-decoder/pom.xml b/presto-record-decoder/pom.xml
index 590a27b57d655..9a5825fa3d62f 100644
--- a/presto-record-decoder/pom.xml
+++ b/presto-record-decoder/pom.xml
@@ -5,7 +5,7 @@
com.facebook.presto
presto-root
- 0.210
+ 0.210-tw-0.61
presto-record-decoder
@@ -80,6 +80,18 @@
jackson-annotations
+
+
+ org.apache.thrift
+ libthrift
+
+
+
+ commons-lang
+ commons-lang
+ 2.5
+
+
org.testng
@@ -92,17 +104,58 @@
testing
test
-
- org.assertj
- assertj-core
+ com.facebook.presto
+ presto-main
test
+
+
+ javax.servlet-api
+ javax.servlet
+
+
-
- com.facebook.presto
- presto-main
+ org.assertj
+ assertj-core
test
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.thrift.tools
+ maven-thrift-plugin
+ 0.1.11
+
+ /usr/local/bin/thrift
+
+
+
+ thrift-sources
+ generate-sources
+
+ compile
+
+
+
+ thrift-test-sources
+ generate-test-sources
+
+ testCompile
+
+
+
+
+
+
diff --git a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/DecoderModule.java b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/DecoderModule.java
index 69ff1a11b680e..ab83ad5a27233 100644
--- a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/DecoderModule.java
+++ b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/DecoderModule.java
@@ -23,6 +23,8 @@
import com.facebook.presto.decoder.json.JsonRowDecoderFactory;
import com.facebook.presto.decoder.raw.RawRowDecoder;
import com.facebook.presto.decoder.raw.RawRowDecoderFactory;
+import com.facebook.presto.decoder.thrift.ThriftRowDecoder;
+import com.facebook.presto.decoder.thrift.ThriftRowDecoderFactory;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.multibindings.MapBinder;
@@ -44,6 +46,7 @@ public void configure(Binder binder)
decoderFactoriesByName.addBinding(JsonRowDecoder.NAME).to(JsonRowDecoderFactory.class).in(SINGLETON);
decoderFactoriesByName.addBinding(RawRowDecoder.NAME).to(RawRowDecoderFactory.class).in(SINGLETON);
decoderFactoriesByName.addBinding(AvroRowDecoder.NAME).to(AvroRowDecoderFactory.class).in(SINGLETON);
+ decoderFactoriesByName.addBinding(ThriftRowDecoder.NAME).to(ThriftRowDecoderFactory.class).in(SINGLETON);
binder.bind(DispatchingRowDecoderFactory.class).in(SINGLETON);
}
diff --git a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawColumnDecoder.java b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawColumnDecoder.java
index a8c436d11895b..2e3153f255890 100644
--- a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawColumnDecoder.java
+++ b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawColumnDecoder.java
@@ -181,7 +181,7 @@ private void checkFieldTypeOneOf(FieldType declaredFieldType, String columnName,
}
}
- public FieldValueProvider decodeField(byte[] value)
+ public FieldValueProvider decode(byte[] value)
{
requireNonNull(value, "value is null");
diff --git a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawRowDecoder.java b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawRowDecoder.java
index f497b30867fa2..4028b1ca54d5d 100644
--- a/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawRowDecoder.java
+++ b/presto-record-decoder/src/main/java/com/facebook/presto/decoder/raw/RawRowDecoder.java
@@ -53,6 +53,6 @@ public Optional