HBASE-11344 Hide row keys and such from the web UIs

This commit is contained in:
Devaraj Das 2014-07-02 13:07:11 -07:00
parent 15831cefd5
commit 9f8d1876a0
7 changed files with 210 additions and 11 deletions

View File

@ -261,4 +261,13 @@
<Bug pattern="FE_FLOATING_POINT_EQUALITY"/> <Bug pattern="FE_FLOATING_POINT_EQUALITY"/>
</Match> </Match>
<Match>
<Class name="org.apache.hadoop.hbase.HRegionInfo"/>
<Or>
<Method name="getEndKeyForDisplay"/>
<Method name="getStartKeyForDisplay"/>
</Or>
<Bug pattern="MS_EXPOSE_REP"/>
</Match>
</FindBugsFilter> </FindBugsFilter>

View File

@ -33,9 +33,11 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.KeyValue.KVComparator; import org.apache.hadoop.hbase.KeyValue.KVComparator;
import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
@ -220,6 +222,9 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
// Current TableName // Current TableName
private TableName tableName = null; private TableName tableName = null;
final static String DISPLAY_KEYS_KEY = "hbase.display.keys";
public final static byte[] HIDDEN_END_KEY = Bytes.toBytes("hidden-end-key");
public final static byte[] HIDDEN_START_KEY = Bytes.toBytes("hidden-start-key");
/** HRegionInfo for first meta region */ /** HRegionInfo for first meta region */
public static final HRegionInfo FIRST_META_REGIONINFO = public static final HRegionInfo FIRST_META_REGIONINFO =
@ -1122,6 +1127,104 @@ public class HRegionInfo implements Comparable<HRegionInfo> {
return ProtobufUtil.toDelimitedByteArray(convert()); return ProtobufUtil.toDelimitedByteArray(convert());
} }
/**
* Get the descriptive name as {@link RegionState} does it but with hidden
* startkey optionally
* @param state
* @param conf
* @return descriptive string
*/
public static String getDescriptiveNameFromRegionStateForDisplay(RegionState state,
Configuration conf) {
if (conf.getBoolean(DISPLAY_KEYS_KEY, true)) return state.toDescriptiveString();
String descriptiveStringFromState = state.toDescriptiveString();
int idx = descriptiveStringFromState.lastIndexOf(" state=");
String regionName = getRegionNameAsStringForDisplay(state.getRegion(), conf);
return regionName + descriptiveStringFromState.substring(idx);
}
/**
* Get the end key for display. Optionally hide the real end key.
* @param hri
* @param conf
* @return the endkey
*/
public static byte[] getEndKeyForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey) return hri.getEndKey();
return HIDDEN_END_KEY;
}
/**
* Get the start key for display. Optionally hide the real start key.
* @param hri
* @param conf
* @return the startkey
*/
public static byte[] getStartKeyForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey) return hri.getStartKey();
return HIDDEN_START_KEY;
}
/**
* Get the region name for display. Optionally hide the start key.
* @param hri
* @param conf
* @return region name as String
*/
public static String getRegionNameAsStringForDisplay(HRegionInfo hri, Configuration conf) {
return Bytes.toStringBinary(getRegionNameForDisplay(hri, conf));
}
/**
* Get the region name for display. Optionally hide the start key.
* @param hri
* @param conf
* @return region name bytes
*/
public static byte[] getRegionNameForDisplay(HRegionInfo hri, Configuration conf) {
boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true);
if (displayKey || hri.getTable().equals(TableName.META_TABLE_NAME)) {
return hri.getRegionName();
} else {
// create a modified regionname with the startkey replaced but preserving
// the other parts including the encodedname.
try {
byte[][]regionNameParts = parseRegionName(hri.getRegionName());
regionNameParts[1] = HIDDEN_START_KEY; //replace the real startkey
int len = 0;
// get the total length
for (byte[] b : regionNameParts) {
len += b.length;
}
byte[] encodedRegionName =
Bytes.toBytes(encodeRegionName(hri.getRegionName()));
len += encodedRegionName.length;
//allocate some extra bytes for the delimiters and the last '.'
byte[] modifiedName = new byte[len + regionNameParts.length + 1];
int lengthSoFar = 0;
int loopCount = 0;
for (byte[] b : regionNameParts) {
System.arraycopy(b, 0, modifiedName, lengthSoFar, b.length);
lengthSoFar += b.length;
if (loopCount++ == 2) modifiedName[lengthSoFar++] = REPLICA_ID_DELIMITER;
else modifiedName[lengthSoFar++] = HConstants.DELIMITER;
}
// replace the last comma with '.'
modifiedName[lengthSoFar - 1] = ENC_SEPARATOR;
System.arraycopy(encodedRegionName, 0, modifiedName, lengthSoFar,
encodedRegionName.length);
lengthSoFar += encodedRegionName.length;
modifiedName[lengthSoFar] = ENC_SEPARATOR;
return modifiedName;
} catch (IOException e) {
//LOG.warn("Encountered exception " + e);
throw new RuntimeException(e);
}
}
}
/** /**
* Extract a HRegionInfo and ServerName from catalog table {@link Result}. * Extract a HRegionInfo and ServerName from catalog table {@link Result}.
* @param r Result to pull from * @param r Result to pull from

View File

@ -836,6 +836,13 @@ possible configurations would overwhelm and obscure the important.
When false (the default), the client will not allow the fallback to SIMPLE When false (the default), the client will not allow the fallback to SIMPLE
authentication, and will abort the connection.</description> authentication, and will abort the connection.</description>
</property> </property>
<property>
<name>hbase.display.keys</name>
<value>true</value>
<description>When this is set to true the webUI and such will display all start/end keys
as part of the table details, region names, etc. When this is set to false,
the keys are hidden.</description>
</property>
<property> <property>
<name>hbase.coprocessor.region.classes</name> <name>hbase.coprocessor.region.classes</name>
<value></value> <value></value>

View File

@ -85,7 +85,9 @@ if (toRemove > 0) {
<%else> <%else>
<tr> <tr>
</%if> </%if>
<td><% entry.getKey() %></td><td><% entry.getValue().toDescriptiveString() %></td> <td><% entry.getKey() %></td><td>
<% HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(
entry.getValue(), conf) %></td>
<td><% (currentTime - entry.getValue().getStamp()) %> </td></tr> <td><% (currentTime - entry.getValue().getStamp()) %> </td></tr>
</%for> </%for>
<tr BGCOLOR="#D7DF01"> <td>Total number of Regions in Transition for more than <% ritThreshold %> milliseconds</td><td> <% numOfRITOverThreshold %></td><td></td> <tr BGCOLOR="#D7DF01"> <td>Total number of Regions in Transition for more than <% ritThreshold %> milliseconds</td><td> <% numOfRITOverThreshold %></td><td></td>

View File

@ -93,9 +93,12 @@
<%for HRegionInfo r: onlineRegions %> <%for HRegionInfo r: onlineRegions %>
<tr> <tr>
<td><% r.getRegionNameAsString() %></td> <td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
<td><% Bytes.toStringBinary(r.getStartKey()) %></td> regionServer.getConfiguration()) %></td>
<td><% Bytes.toStringBinary(r.getEndKey()) %></td> <td><% Bytes.toStringBinary(HRegionInfo.getStartKeyForDisplay(r,
regionServer.getConfiguration())) %></td>
<td><% Bytes.toStringBinary(HRegionInfo.getEndKeyForDisplay(r,
regionServer.getConfiguration())) %></td>
<td><% r.getReplicaId() %></td> <td><% r.getReplicaId() %></td>
</tr> </tr>
</%for> </%for>
@ -119,7 +122,8 @@
<%java> <%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName()); RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java> </%java>
<td><% r.getRegionNameAsString() %></td> <td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %> <%if load != null %>
<td><% load.getReadRequestsCount() %></td> <td><% load.getReadRequestsCount() %></td>
<td><% load.getWriteRequestsCount() %></td> <td><% load.getWriteRequestsCount() %></td>
@ -151,7 +155,8 @@
<%java> <%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName()); RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java> </%java>
<td><% r.getRegionNameAsString() %></td> <td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %> <%if load != null %>
<td><% load.getStores() %></td> <td><% load.getStores() %></td>
<td><% load.getStorefiles() %></td> <td><% load.getStorefiles() %></td>
@ -189,7 +194,8 @@
((float) load.getCurrentCompactedKVs() / load.getTotalCompactingKVs())) + "%"; ((float) load.getCurrentCompactedKVs() / load.getTotalCompactingKVs())) + "%";
} }
</%java> </%java>
<td><% r.getRegionNameAsString() %></td> <td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %> <%if load != null %>
<td><% load.getTotalCompactingKVs() %></td> <td><% load.getTotalCompactingKVs() %></td>
<td><% load.getCurrentCompactedKVs() %></td> <td><% load.getCurrentCompactedKVs() %></td>
@ -216,7 +222,8 @@
<%java> <%java>
RegionLoad load = regionServer.createRegionLoad(r.getEncodedName()); RegionLoad load = regionServer.createRegionLoad(r.getEncodedName());
</%java> </%java>
<td><% r.getRegionNameAsString() %></td> <td><% HRegionInfo.getRegionNameAsStringForDisplay(r,
regionServer.getConfiguration()) %></td>
<%if load != null %> <%if load != null %>
<td><% load.getMemstoreSizeMB() %>m</td> <td><% load.getMemstoreSizeMB() %>m</td>
</%if> </%if>

View File

@ -283,7 +283,8 @@
} }
%> %>
<tr> <tr>
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getRegionName())) %></td> <td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getRegionNameForDisplay(regionInfo,
conf))) %></td>
<% <%
if (addr != null) { if (addr != null) {
String url = "//" + addr.getHostname() + ":" + master.getRegionServerInfoPort(addr) + "/"; String url = "//" + addr.getHostname() + ":" + master.getRegionServerInfoPort(addr) + "/";
@ -298,8 +299,10 @@
<% <%
} }
%> %>
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getStartKey())) %></td> <td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getStartKeyForDisplay(regionInfo,
<td><%= escapeXml(Bytes.toStringBinary(regionInfo.getEndKey())) %></td> conf))) %></td>
<td><%= escapeXml(Bytes.toStringBinary(HRegionInfo.getEndKeyForDisplay(regionInfo,
conf))) %></td>
<td><%= req%></td> <td><%= req%></td>
<% <%
if (withReplica) { if (withReplica) {

View File

@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestingUtility; import org.apache.hadoop.hbase.HBaseTestingUtility;
@ -34,10 +35,12 @@ import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.SmallTests; import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo; import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.RegionInfo;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.MD5Hash; import org.apache.hadoop.hbase.util.MD5Hash;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
@ -254,6 +257,71 @@ public class TestHRegionInfo {
assertEquals(expectedHri, convertedHri); assertEquals(expectedHri, convertedHri);
} }
@Test
public void testRegionDetailsForDisplay() throws IOException {
byte[] startKey = new byte[] {0x01, 0x01, 0x02, 0x03};
byte[] endKey = new byte[] {0x01, 0x01, 0x02, 0x04};
Configuration conf = new Configuration();
conf.setBoolean("hbase.display.keys", false);
HRegionInfo h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey);
checkEquality(h, conf);
// check HRIs with non-default replicaId
h = new HRegionInfo(TableName.valueOf("foo"), startKey, endKey, false,
System.currentTimeMillis(), 1);
checkEquality(h, conf);
Assert.assertArrayEquals(HRegionInfo.HIDDEN_END_KEY,
HRegionInfo.getEndKeyForDisplay(h, conf));
Assert.assertArrayEquals(HRegionInfo.HIDDEN_START_KEY,
HRegionInfo.getStartKeyForDisplay(h, conf));
RegionState state = new RegionState(h, RegionState.State.OPEN);
String descriptiveNameForDisplay =
HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf);
checkDescriptiveNameEquality(descriptiveNameForDisplay,state.toDescriptiveString(), startKey);
conf.setBoolean("hbase.display.keys", true);
Assert.assertArrayEquals(endKey, HRegionInfo.getEndKeyForDisplay(h, conf));
Assert.assertArrayEquals(startKey, HRegionInfo.getStartKeyForDisplay(h, conf));
Assert.assertEquals(state.toDescriptiveString(),
HRegionInfo.getDescriptiveNameFromRegionStateForDisplay(state, conf));
}
private void checkDescriptiveNameEquality(String descriptiveNameForDisplay, String origDesc,
byte[] startKey) {
// except for the "hidden-start-key" substring everything else should exactly match
String firstPart = descriptiveNameForDisplay.substring(0,
descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)));
String secondPart = descriptiveNameForDisplay.substring(
descriptiveNameForDisplay.indexOf(new String(HRegionInfo.HIDDEN_START_KEY)) +
HRegionInfo.HIDDEN_START_KEY.length);
String firstPartOrig = origDesc.substring(0,
origDesc.indexOf(Bytes.toStringBinary(startKey)));
String secondPartOrig = origDesc.substring(
origDesc.indexOf(Bytes.toStringBinary(startKey)) +
Bytes.toStringBinary(startKey).length());
assert(firstPart.equals(firstPartOrig));
assert(secondPart.equals(secondPartOrig));
}
private void checkEquality(HRegionInfo h, Configuration conf) throws IOException {
byte[] modifiedRegionName = HRegionInfo.getRegionNameForDisplay(h, conf);
byte[][] modifiedRegionNameParts = HRegionInfo.parseRegionName(modifiedRegionName);
byte[][] regionNameParts = HRegionInfo.parseRegionName(h.getRegionName());
//same number of parts
assert(modifiedRegionNameParts.length == regionNameParts.length);
for (int i = 0; i < regionNameParts.length; i++) {
// all parts should match except for [1] where in the modified one,
// we should have "hidden_start_key"
if (i != 1) {
Assert.assertArrayEquals(regionNameParts[i], modifiedRegionNameParts[i]);
} else {
Assert.assertNotEquals(regionNameParts[i][0], modifiedRegionNameParts[i][0]);
Assert.assertArrayEquals(modifiedRegionNameParts[1],
HRegionInfo.getStartKeyForDisplay(h, conf));
}
}
}
} }