You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ch...@apache.org on 2020/03/02 22:32:37 UTC
[phoenix] branch master updated: PHOENIX-5636: Improve the error
message when client connects to server with higher major version
This is an automated email from the ASF dual-hosted git repository.
chinmayskulkarni pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/master by this push:
new 3013c3e PHOENIX-5636: Improve the error message when client connects to server with higher major version
3013c3e is described below
commit 3013c3e954ebdbec7274cb950e3583bc08975135
Author: Christine Feng <ch...@gmail.com>
AuthorDate: Fri Jan 31 14:33:24 2020 -0800
PHOENIX-5636: Improve the error message when client connects to server with higher major version
Signed-off-by: Chinmay Kulkarni <ch...@apache.org>
---
.../phoenix/query/ConnectionQueryServicesImpl.java | 57 ++++++++++++++--------
.../java/org/apache/phoenix/util/MetaDataUtil.java | 48 ++++++++++++++++--
.../org/apache/phoenix/util/MetaDataUtilTest.java | 38 +++++++++++----
3 files changed, 109 insertions(+), 34 deletions(-)
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 06f44d4..d5b0720 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -1487,20 +1487,10 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
return MetaDataUtil.decodeHasIndexWALCodec(serverVersion);
}
- private static boolean isCompatible(Long serverVersion) {
- if (serverVersion == null) {
- return false;
- }
- return MetaDataUtil.areClientAndServerCompatible(serverVersion);
- }
private void checkClientServerCompatibility(byte[] metaTable) throws SQLException,
AccessDeniedException {
- StringBuilder buf = new StringBuilder("Newer Phoenix clients can't communicate with older "
- + "Phoenix servers. The following servers require an updated "
- + QueryConstants.DEFAULT_COPROCESS_JAR_NAME
- + " to be put in the classpath of HBase: ");
- boolean isIncompatible = false;
+ StringBuilder errorMessage = new StringBuilder();
int minHBaseVersion = Integer.MAX_VALUE;
boolean isTableNamespaceMappingEnabled = false;
long systemCatalogTimestamp = Long.MAX_VALUE;
@@ -1553,11 +1543,26 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
long serverJarVersion = versionResponse.getVersion();
isTableNamespaceMappingEnabled |= MetaDataUtil.decodeTableNamespaceMappingEnabled(serverJarVersion);
- if (!isCompatible(serverJarVersion)) {
- isIncompatible = true;
- HRegionLocation name = regionMap.get(result.getKey());
- buf.append(name);
- buf.append(';');
+ MetaDataUtil.ClientServerCompatibility compatibility = MetaDataUtil.areClientAndServerCompatible(serverJarVersion);
+ if (!compatibility.getIsCompatible()) {
+ if (compatibility.getErrorCode() == SQLExceptionCode.OUTDATED_JARS.getErrorCode()) {
+ HRegionLocation name = regionMap.get(result.getKey());
+ errorMessage.append("Newer Phoenix clients can't communicate with older "
+ + "Phoenix servers. Client version: "
+ + MetaDataProtocol.CURRENT_CLIENT_VERSION
+ + "; Server version: "
+ + getServerVersion(serverJarVersion)
+ + " The following servers require an updated "
+ + QueryConstants.DEFAULT_COPROCESS_JAR_NAME
+ + " to be put in the classpath of HBase: ");
+ errorMessage.append(name);
+ errorMessage.append(';');
+ } else if (compatibility.getErrorCode() == SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode()) {
+ errorMessage.append("Major version of client is less than that of the server. Client version: "
+ + MetaDataProtocol.CURRENT_CLIENT_VERSION
+ + "; Server version: "
+ + getServerVersion(serverJarVersion));
+ }
}
hasIndexWALCodec &= hasIndexWALCodec(serverJarVersion);
if (minHBaseVersion > MetaDataUtil.decodeHBaseVersion(serverJarVersion)) {
@@ -1570,6 +1575,15 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
systemCatalogTimestamp = systemCatalogTimestamp < versionResponse.getSystemCatalogTimestamp() ?
systemCatalogTimestamp: versionResponse.getSystemCatalogTimestamp();
}
+
+ if (compatibility.getErrorCode() != 0) {
+ if (compatibility.getErrorCode() == SQLExceptionCode.OUTDATED_JARS.getErrorCode()) {
+ errorMessage.setLength(errorMessage.length()-1);
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.OUTDATED_JARS).setMessage(errorMessage.toString()).build().buildException();
+ } else if (compatibility.getErrorCode() == SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode()) {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR).setMessage(errorMessage.toString()).build().buildException();
+ }
+ }
}
if (isTableNamespaceMappingEnabled != SchemaUtil.isNamespaceMappingEnabled(PTableType.TABLE,
getProps())) { throw new SQLExceptionInfo.Builder(
@@ -1588,15 +1602,18 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
}
}
}
- if (isIncompatible) {
- buf.setLength(buf.length()-1);
- throw new SQLExceptionInfo.Builder(SQLExceptionCode.OUTDATED_JARS).setMessage(buf.toString()).build().buildException();
- }
+
if (systemCatalogTimestamp < MIN_SYSTEM_TABLE_TIMESTAMP) {
throw new UpgradeRequiredException(systemCatalogTimestamp);
}
}
+ private String getServerVersion(long serverJarVersion) {
+ return (VersionUtil.decodeMajorVersion(MetaDataUtil.decodePhoenixVersion(serverJarVersion)) + "."
+ + VersionUtil.decodeMinorVersion(MetaDataUtil.decodePhoenixVersion(serverJarVersion)) + "."
+ + VersionUtil.decodePatchVersion(MetaDataUtil.decodePhoenixVersion(serverJarVersion)));
+ }
+
/**
* Invoke the SYSTEM.CHILD_LINK metadata coprocessor endpoint
* @param parentTableKey key corresponding to the parent of the view
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
index d68b1aa..c25f81d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
@@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
@@ -60,6 +61,7 @@ import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.ipc.RemoteException;
import org.apache.phoenix.coprocessor.MetaDataEndpointImpl;
import org.apache.phoenix.coprocessor.MetaDataProtocol;
+import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.hbase.index.util.GenericKeyValueBuilder;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.hbase.index.util.IndexManagementUtil;
@@ -122,7 +124,33 @@ public class MetaDataUtil {
ColumnFamilyDescriptorBuilder.KEEP_DELETED_CELLS,
ColumnFamilyDescriptorBuilder.REPLICATION_SCOPE);
- public static boolean areClientAndServerCompatible(long serverHBaseAndPhoenixVersion) {
+ public static class ClientServerCompatibility {
+
+ private int errorCode;
+ private boolean isCompatible;
+
+ ClientServerCompatibility() {
+ this.errorCode = 0;
+ }
+
+ public int getErrorCode() {
+ return this.errorCode;
+ }
+
+ void setErrorCode(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public boolean getIsCompatible() {
+ return this.isCompatible;
+ }
+
+ void setCompatible(boolean isCompatible) {
+ this.isCompatible = isCompatible;
+ }
+ }
+
+ public static ClientServerCompatibility areClientAndServerCompatible(long serverHBaseAndPhoenixVersion) {
// As of 3.0, we allow a client and server to differ for the minor version.
// Care has to be taken to upgrade the server before the client, as otherwise
// the client may call expressions that don't yet exist on the server.
@@ -132,12 +160,24 @@ public class MetaDataUtil {
}
// Default scope for testing
- static boolean areClientAndServerCompatible(int serverVersion, int clientMajorVersion, int clientMinorVersion) {
+ @VisibleForTesting
+ static ClientServerCompatibility areClientAndServerCompatible(int serverVersion, int clientMajorVersion, int clientMinorVersion) {
// A server and client with the same major and minor version number must be compatible.
// So it's important that we roll the PHOENIX_MAJOR_VERSION or PHOENIX_MINOR_VERSION
// when we make an incompatible change.
- return VersionUtil.encodeMinPatchVersion(clientMajorVersion, clientMinorVersion) <= serverVersion && // Minor major and minor cannot be ahead of server
- VersionUtil.encodeMaxMinorVersion(clientMajorVersion) >= serverVersion; // Major version must at least be up to server version
+ ClientServerCompatibility compatibility = new ClientServerCompatibility();
+ if (VersionUtil.encodeMinPatchVersion(clientMajorVersion, clientMinorVersion) > serverVersion) { // Client major and minor cannot be ahead of server
+ compatibility.setErrorCode(SQLExceptionCode.OUTDATED_JARS.getErrorCode());
+ compatibility.setCompatible(false);
+ return compatibility;
+ } else if (VersionUtil.encodeMaxMinorVersion(clientMajorVersion) < serverVersion) { // Client major version must at least be up to server major version
+ compatibility.setErrorCode(SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode());
+ compatibility.setCompatible(false);
+ return compatibility;
+ }
+ compatibility.setCompatible(true);
+ return compatibility;
+
}
// Given the encoded integer representing the phoenix version in the encoded version value.
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
index 52df041..4b13e44 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/MetaDataUtilTest.java
@@ -37,6 +37,7 @@ import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.VersionInfo;
import org.apache.phoenix.coprocessor.MetaDataProtocol;
+import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.hbase.index.util.GenericKeyValueBuilder;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
@@ -104,16 +105,33 @@ public class MetaDataUtilTest {
@Test
public void testCompatibility() {
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,1), 1, 2));
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,10), 1, 1));
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,0), 1, 2));
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,255), 1, 2));
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(2,2,0), 2, 0));
- assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(2,10,36), 2, 9));
- assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 4, 0));
- assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 2, 0));
- assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 3, 2));
- assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 3, 5));
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,1), 1, 2).getIsCompatible());
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,10), 1, 1).getIsCompatible());
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,0), 1, 2).getIsCompatible());
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(1,2,255), 1, 2).getIsCompatible());
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(2,2,0), 2, 0).getIsCompatible());
+ assertTrue(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(2,10,36), 2, 9).getIsCompatible());
+ assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 4, 0).getIsCompatible());
+ assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 2, 0).getIsCompatible());
+ assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 3, 2).getIsCompatible());
+ assertFalse(MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 3, 5).getIsCompatible());
+ }
+
+ @Test
+ public void testCompatibilityNewerClient() {
+ MetaDataUtil.ClientServerCompatibility compatibility1 = MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 4, 0);
+ assertFalse(compatibility1.getIsCompatible());
+ assertEquals(compatibility1.getErrorCode(), SQLExceptionCode.OUTDATED_JARS.getErrorCode());
+ MetaDataUtil.ClientServerCompatibility compatibility2 = MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 3, 2);
+ assertFalse(compatibility2.getIsCompatible());
+ assertEquals(compatibility2.getErrorCode(), SQLExceptionCode.OUTDATED_JARS.getErrorCode());
+ }
+
+ @Test
+ public void testCompatibilityMismatchedMajorVersions() {
+ MetaDataUtil.ClientServerCompatibility compatibility = MetaDataUtil.areClientAndServerCompatible(VersionUtil.encodeVersion(3,1,10), 2, 0);
+ assertFalse(compatibility.getIsCompatible());
+ assertEquals(compatibility.getErrorCode(), SQLExceptionCode.INCOMPATIBLE_CLIENT_SERVER_JAR.getErrorCode());
}
@Test