Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ message Version {
optional string osVersion = 3;
optional string serverVersion = 4;
optional string jerseyVersion = 5;
optional string version = 6;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are older clients going to be able to handle this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks, this is a very good question. I'll investigate this a bit to make sure.

Copy link
Contributor Author

@PDavid PDavid Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The short answer is: yes.

The long answer:

Extending a Protocol Buffer

Sooner or later after you release the code that uses your protocol buffer, you will undoubtedly want to “improve” the protocol buffer’s definition. If you want your new buffers to be backwards-compatible, and your old buffers to be forward-compatible – and you almost certainly do want this – then there are some rules you need to follow. In the new version of the protocol buffer:

  • you must not change the tag numbers of any existing fields.
  • you must not add or delete any required fields.
  • you may delete optional or repeated fields.
  • you may add new optional or repeated fields but you must use fresh tag numbers (that is, tag numbers that -
    were never used in this protocol buffer, not even by deleted fields).
    (There are some exceptions to these rules, but they are rarely used.)

If you follow these rules, old code will happily read new messages and simply ignore any new fields. To the old code, optional fields that were deleted will simply have their default value, and deleted repeated fields will be empty. New code will also transparently read old messages. However, keep in mind that new optional fields will not be present in old messages, so you will need to either check explicitly whether they’re set with has_, or provide a reasonable default value in your .proto file with [default = value] after the tag number. If the default value is not specified for an optional element, a type-specific default value is used instead: for strings, the default value is the empty string.
...

Source: https://protobuf.dev/getting-started/javatutorial/#extending-a-protobuf

Besides I tested it like this:

  • Took (copied) the Base64 encoded serialized protobuf message which also contains the newly added version and revision fields:
AS_PB = "CgUwLjAuMRInU3VuIE1pY3Jvc3lzdGVtcyBJbmMuIDEuNi4wXzEzLTExLjMtYjAyGi1MaW51eCAyLjYuMTg"
      + "tMTI4LjEuNi5lbDUuY2VudG9zLnBsdXN4ZW4gYW1kNjQiBjYuMS4xNCoIMS4xLjAtZWEyFjQuMC4wLWFscGhhLT"
      + "EtU05BUFNIT1Q6KDUwODVkMjdhYjE3ZDg1NzExOGE5NmFlM2YzN2MwMGI2MGM5MjU0NzE=";
  • Switched to the master branch (which does not yet have these version and revision fields yet).
  • In TestVersionModel I changed the serialized protobuf string to the new one which has the new fields
  • Run a Maven clean install to make sure the project is clean
  • Executed TestVersionModel unit test which was green (was able to read the protobuf message).

(I also tried out this in a small new Java project.)

--> older clients should read new message and newer clients should read old messages without a problem.

optional string revision = 7;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
import org.apache.hadoop.hbase.rest.RESTServlet;
import org.apache.hadoop.hbase.rest.RestUtil;
import org.apache.hadoop.hbase.util.VersionInfo;
import org.apache.yetus.audience.InterfaceAudience;

import org.apache.hbase.thirdparty.com.google.protobuf.CodedInputStream;
Expand Down Expand Up @@ -54,6 +55,8 @@ public class VersionModel implements Serializable, ProtobufMessageHandler {
private String osVersion;
private String serverVersion;
private String jerseyVersion;
private String version;
private String revision;

/**
* Default constructor. Do not use.
Expand All @@ -75,6 +78,9 @@ public VersionModel(ServletContext context) {
jerseyVersion = ServletContainer.class.getPackage().getImplementationVersion();
// Currently, this will always be null because the manifest doesn't have any useful information
if (jerseyVersion == null) jerseyVersion = "";

version = VersionInfo.getVersion();
revision = VersionInfo.getRevision();
}

/** Returns the REST gateway version */
Expand Down Expand Up @@ -107,6 +113,18 @@ public String getJerseyVersion() {
return jerseyVersion;
}

/** Returns the build version of the REST server component */
@XmlAttribute(name = "Version")
public String getVersion() {
return version;
}

/** Returns the source control revision of the REST server component */
@XmlAttribute(name = "Revision")
public String getRevision() {
return revision;
}

/**
* @param version the REST gateway version string
*/
Expand Down Expand Up @@ -142,6 +160,20 @@ public void setJerseyVersion(String version) {
this.jerseyVersion = version;
}

/**
* @param version the REST server component build version string
*/
public void setVersion(String version) {
this.version = version;
}

/**
* @param revision the REST server component source control revision string
*/
public void setRevision(String revision) {
this.revision = revision;
}

/*
* (non-Javadoc)
* @see java.lang.Object#toString()
Expand All @@ -159,6 +191,10 @@ public String toString() {
sb.append(serverVersion);
sb.append("] [Jersey: ");
sb.append(jerseyVersion);
sb.append("] [Version: ");
sb.append(version);
sb.append("] [Revision: ");
sb.append(revision);
sb.append("]\n");
return sb.toString();
}
Expand All @@ -171,6 +207,8 @@ public Message messageFromObject() {
builder.setOsVersion(osVersion);
builder.setServerVersion(serverVersion);
builder.setJerseyVersion(jerseyVersion);
builder.setVersion(version);
builder.setRevision(revision);
return builder.build();
}

Expand All @@ -193,6 +231,12 @@ public ProtobufMessageHandler getObjectFromMessage(CodedInputStream cis) throws
if (builder.hasJerseyVersion()) {
jerseyVersion = builder.getJerseyVersion();
}
if (builder.hasVersion()) {
version = builder.getVersion();
}
if (builder.hasRevision()) {
revision = builder.getRevision();
}
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.testclassification.RestTests;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.VersionInfo;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.ClassRule;
Expand Down Expand Up @@ -77,8 +78,9 @@ public static void tearDownAfterClass() throws Exception {

private static void validate(VersionModel model) {
assertNotNull(model);
assertNotNull(model.getRESTVersion());
assertEquals(RESTServlet.VERSION_STRING, model.getRESTVersion());
String restVersion = model.getRESTVersion();
assertNotNull(restVersion);
assertEquals(RESTServlet.VERSION_STRING, restVersion);
String osVersion = model.getOSVersion();
assertNotNull(osVersion);
assertTrue(osVersion.contains(System.getProperty("os.name")));
Expand All @@ -94,6 +96,13 @@ private static void validate(VersionModel model) {
assertNotNull(jerseyVersion);
// TODO: fix when we actually get a jersey version
// assertEquals(jerseyVersion, ServletContainer.class.getPackage().getImplementationVersion());

String version = model.getVersion();
assertNotNull(version);
assertEquals(VersionInfo.getVersion(), version);
String revision = model.getRevision();
assertNotNull(revision);
assertEquals(VersionInfo.getRevision(), revision);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,25 @@ public class TestVersionModel extends TestModelBase<VersionModel> {
private static final String JVM_VERSION = "Sun Microsystems Inc. 1.6.0_13-11.3-b02";
private static final String JETTY_VERSION = "6.1.14";
private static final String JERSEY_VERSION = "1.1.0-ea";
private static final String VERSION = "4.0.0-alpha-1-SNAPSHOT";
private static final String REVISION = "5085d27ab17d857118a96ae3f37c00b60c925471";

public TestVersionModel() throws Exception {
super(VersionModel.class);
AS_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Version JVM=\"Sun "
+ "Microsystems Inc. 1.6.0_13-11.3-b02\" Jersey=\"1.1.0-ea\" "
+ "OS=\"Linux 2.6.18-128.1.6.el5.centos.plusxen amd64\" REST=\"0.0.1\" Server=\"6.1.14\"/>";
+ "OS=\"Linux 2.6.18-128.1.6.el5.centos.plusxen amd64\" REST=\"0.0.1\" Server=\"6.1.14\" "
+ "Version=\"4.0.0-alpha-1-SNAPSHOT\" "
+ "Revision=\"5085d27ab17d857118a96ae3f37c00b60c925471\"/>";

AS_PB = "CgUwLjAuMRInU3VuIE1pY3Jvc3lzdGVtcyBJbmMuIDEuNi4wXzEzLTExLjMtYjAyGi1MaW51eCAy"
+ "LjYuMTgtMTI4LjEuNi5lbDUuY2VudG9zLnBsdXN4ZW4gYW1kNjQiBjYuMS4xNCoIMS4xLjAtZWE=";
AS_PB = "CgUwLjAuMRInU3VuIE1pY3Jvc3lzdGVtcyBJbmMuIDEuNi4wXzEzLTExLjMtYjAyGi1MaW51eCAyLjYuMTg"
+ "tMTI4LjEuNi5lbDUuY2VudG9zLnBsdXN4ZW4gYW1kNjQiBjYuMS4xNCoIMS4xLjAtZWEyFjQuMC4wLWFscGhhLT"
+ "EtU05BUFNIT1Q6KDUwODVkMjdhYjE3ZDg1NzExOGE5NmFlM2YzN2MwMGI2MGM5MjU0NzE=";

AS_JSON = "{\"JVM\":\"Sun Microsystems Inc. 1.6.0_13-11.3-b02\",\"Jersey\":\"1.1.0-ea\","
+ "\"OS\":\"Linux 2.6.18-128.1.6.el5.centos.plusxen amd64\",\""
+ "REST\":\"0.0.1\",\"Server\":\"6.1.14\"}";
+ "REST\":\"0.0.1\",\"Server\":\"6.1.14\", \"Version\":\"4.0.0-alpha-1-SNAPSHOT\","
+ "\"Revision\":\"5085d27ab17d857118a96ae3f37c00b60c925471\"}";
}

@Override
Expand All @@ -60,6 +66,8 @@ protected VersionModel buildTestModel() {
model.setJVMVersion(JVM_VERSION);
model.setServerVersion(JETTY_VERSION);
model.setJerseyVersion(JERSEY_VERSION);
model.setVersion(VERSION);
model.setRevision(REVISION);
return model;
}

Expand All @@ -70,5 +78,7 @@ protected void checkModel(VersionModel model) {
assertEquals(JVM_VERSION, model.getJVMVersion());
assertEquals(JETTY_VERSION, model.getServerVersion());
assertEquals(JERSEY_VERSION, model.getJerseyVersion());
assertEquals(VERSION, model.getVersion());
assertEquals(REVISION, model.getRevision());
}
}
11 changes: 11 additions & 0 deletions src/main/asciidoc/_chapters/external_apis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ creation or mutation, and `DELETE` for deletion.
-H "Accept: text/xml" \
"http://example.com:8000/version/cluster"

|/version/rest
|GET
|Version of the HBase REST Server
|curl -vi -X GET \
-H "Accept: text/xml" \
"http://example.com:8000/version/rest"

|/status/cluster
|GET
|Cluster status
Expand Down Expand Up @@ -565,6 +572,8 @@ Detailed Explanation:
<attribute name="OS" type="string"></attribute>
<attribute name="Server" type="string"></attribute>
<attribute name="Jersey" type="string"></attribute>
<attribute name="Version" type="string"></attribute>
<attribute name="Revision" type="string"></attribute>
</complexType>

<element name="TableList" type="tns:TableList"></element>
Expand Down Expand Up @@ -719,6 +728,8 @@ message Version {
optional string osVersion = 3;
optional string serverVersion = 4;
optional string jerseyVersion = 5;
optional string version = 6;
optional string revision = 7;
}

message StorageClusterStatus {
Expand Down