HBASE-23969 Meta browser should show all `info` columns (#1485)
Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> Signed-off-by: Viraj Jasani <vjasani@apache.org>
This commit is contained in:
parent
a782531633
commit
a40a0322a7
|
@ -384,32 +384,42 @@ public class MetaTableAccessor {
|
|||
}
|
||||
|
||||
/**
|
||||
* @return Deserialized regioninfo values taken from column values that match
|
||||
* @return Deserialized values of <qualifier,regioninfo> pairs taken from column values that match
|
||||
* the regex 'info:merge.*' in array of <code>cells</code>.
|
||||
*/
|
||||
@Nullable
|
||||
public static List<RegionInfo> getMergeRegions(Cell [] cells) {
|
||||
public static Map<String, RegionInfo> getMergeRegionsWithName(Cell [] cells) {
|
||||
if (cells == null) {
|
||||
return null;
|
||||
}
|
||||
List<RegionInfo> regionsToMerge = null;
|
||||
Map<String, RegionInfo> regionsToMerge = null;
|
||||
for (Cell cell: cells) {
|
||||
if (!isMergeQualifierPrefix(cell)) {
|
||||
continue;
|
||||
}
|
||||
// Ok. This cell is that of a info:merge* column.
|
||||
RegionInfo ri = RegionInfo.parseFromOrNull(cell.getValueArray(), cell.getValueOffset(),
|
||||
cell.getValueLength());
|
||||
cell.getValueLength());
|
||||
if (ri != null) {
|
||||
if (regionsToMerge == null) {
|
||||
regionsToMerge = new ArrayList<>();
|
||||
regionsToMerge = new LinkedHashMap<>();
|
||||
}
|
||||
regionsToMerge.add(ri);
|
||||
regionsToMerge.put(Bytes.toString(CellUtil.cloneQualifier(cell)), ri);
|
||||
}
|
||||
}
|
||||
return regionsToMerge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deserialized regioninfo values taken from column values that match
|
||||
* the regex 'info:merge.*' in array of <code>cells</code>.
|
||||
*/
|
||||
@Nullable
|
||||
public static List<RegionInfo> getMergeRegions(Cell [] cells) {
|
||||
Map<String, RegionInfo> mergeRegionsWithName = getMergeRegionsWithName(cells);
|
||||
return (mergeRegionsWithName == null) ? null : new ArrayList<>(mergeRegionsWithName.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if any merge regions present in <code>cells</code>; i.e.
|
||||
* the column in <code>cell</code> matches the regex 'info:merge.*'.
|
||||
|
@ -873,8 +883,7 @@ public class MetaTableAccessor {
|
|||
* @param replicaId the replicaId of the region
|
||||
* @return a byte[] for sn column qualifier
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static byte[] getServerNameColumn(int replicaId) {
|
||||
public static byte[] getServerNameColumn(int replicaId) {
|
||||
return replicaId == 0 ? HConstants.SERVERNAME_QUALIFIER
|
||||
: Bytes.toBytes(HConstants.SERVERNAME_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
|
||||
+ String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId));
|
||||
|
@ -966,6 +975,33 @@ public class MetaTableAccessor {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link ServerName} from catalog table {@link Result} where the region is
|
||||
* transitioning on. It should be the same as {@link MetaTableAccessor#getServerName(Result,int)}
|
||||
* if the server is at OPEN state.
|
||||
*
|
||||
* @param r Result to pull the transitioning server name from
|
||||
* @return A ServerName instance or {@link MetaTableAccessor#getServerName(Result,int)}
|
||||
* if necessary fields not found or empty.
|
||||
*/
|
||||
@Nullable
|
||||
public static ServerName getTargetServerName(final Result r, final int replicaId) {
|
||||
final Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY,
|
||||
getServerNameColumn(replicaId));
|
||||
if (cell == null || cell.getValueLength() == 0) {
|
||||
RegionLocations locations = MetaTableAccessor.getRegionLocations(r);
|
||||
if (locations != null) {
|
||||
HRegionLocation location = locations.getRegionLocation(replicaId);
|
||||
if (location != null) {
|
||||
return location.getServerName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return ServerName.parseServerName(Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
|
||||
cell.getValueLength()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The latest seqnum that the server writing to meta observed when opening the region.
|
||||
* E.g. the seqNum when the result of {@link #getServerName(Result, int)} was written.
|
||||
|
|
|
@ -493,11 +493,15 @@ public final class HConstants {
|
|||
|
||||
public static final byte [] SERVERNAME_QUALIFIER = Bytes.toBytes(SERVERNAME_QUALIFIER_STR);
|
||||
|
||||
/** The lower-half split region column qualifier string. */
|
||||
public static final String SPLITA_QUALIFIER_STR = "splitA";
|
||||
/** The lower-half split region column qualifier */
|
||||
public static final byte [] SPLITA_QUALIFIER = Bytes.toBytes("splitA");
|
||||
public static final byte [] SPLITA_QUALIFIER = Bytes.toBytes(SPLITA_QUALIFIER_STR);
|
||||
|
||||
/** The upper-half split region column qualifier String. */
|
||||
public static final String SPLITB_QUALIFIER_STR = "splitB";
|
||||
/** The upper-half split region column qualifier */
|
||||
public static final byte [] SPLITB_QUALIFIER = Bytes.toBytes("splitB");
|
||||
public static final byte [] SPLITB_QUALIFIER = Bytes.toBytes(SPLITB_QUALIFIER_STR);
|
||||
|
||||
/**
|
||||
* Merge qualifier prefix.
|
||||
|
|
|
@ -134,7 +134,7 @@ public class RegionStateStore {
|
|||
final State state = getRegionState(result, regionInfo);
|
||||
|
||||
final ServerName lastHost = hrl.getServerName();
|
||||
final ServerName regionLocation = getRegionServer(result, replicaId);
|
||||
ServerName regionLocation = MetaTableAccessor.getTargetServerName(result, replicaId);
|
||||
final long openSeqNum = hrl.getSeqNum();
|
||||
|
||||
// TODO: move under trace, now is visible for debugging
|
||||
|
@ -199,7 +199,7 @@ public class RegionStateStore {
|
|||
put.add(CellBuilderFactory.create(CellBuilderType.SHALLOW_COPY)
|
||||
.setRow(put.getRow())
|
||||
.setFamily(HConstants.CATALOG_FAMILY)
|
||||
.setQualifier(getServerNameColumn(replicaId))
|
||||
.setQualifier(MetaTableAccessor.getServerNameColumn(replicaId))
|
||||
.setTimestamp(put.getTimestamp())
|
||||
.setType(Cell.Type.Put)
|
||||
.setValue(Bytes.toBytes(regionLocation.getServerName()))
|
||||
|
@ -299,42 +299,6 @@ public class RegionStateStore {
|
|||
return master.getTableDescriptors().get(tableName);
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Server Name
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
* Returns the {@link ServerName} from catalog table {@link Result}
|
||||
* where the region is transitioning. It should be the same as
|
||||
* {@link MetaTableAccessor#getServerName(Result,int)} if the server is at OPEN state.
|
||||
* @param r Result to pull the transitioning server name from
|
||||
* @return A ServerName instance or {@link MetaTableAccessor#getServerName(Result,int)}
|
||||
* if necessary fields not found or empty.
|
||||
*/
|
||||
static ServerName getRegionServer(final Result r, int replicaId) {
|
||||
final Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY,
|
||||
getServerNameColumn(replicaId));
|
||||
if (cell == null || cell.getValueLength() == 0) {
|
||||
RegionLocations locations = MetaTableAccessor.getRegionLocations(r);
|
||||
if (locations != null) {
|
||||
HRegionLocation location = locations.getRegionLocation(replicaId);
|
||||
if (location != null) {
|
||||
return location.getServerName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return ServerName.parseServerName(Bytes.toString(cell.getValueArray(),
|
||||
cell.getValueOffset(), cell.getValueLength()));
|
||||
}
|
||||
|
||||
private static byte[] getServerNameColumn(int replicaId) {
|
||||
return replicaId == 0
|
||||
? HConstants.SERVERNAME_QUALIFIER
|
||||
: Bytes.toBytes(HConstants.SERVERNAME_QUALIFIER_STR + META_REPLICA_ID_DELIMITER
|
||||
+ String.format(RegionInfo.REPLICA_ID_FORMAT, replicaId));
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Region State
|
||||
// ==========================================================================
|
||||
|
|
|
@ -18,13 +18,16 @@
|
|||
package org.apache.hadoop.hbase.master.webapp;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.apache.hadoop.hbase.HConstants;
|
||||
import org.apache.hadoop.hbase.HRegionLocation;
|
||||
import org.apache.hadoop.hbase.MetaTableAccessor;
|
||||
import org.apache.hadoop.hbase.RegionLocations;
|
||||
|
@ -34,6 +37,7 @@ import org.apache.hadoop.hbase.client.Result;
|
|||
import org.apache.hadoop.hbase.master.RegionState;
|
||||
import org.apache.hadoop.hbase.master.assignment.RegionStateStore;
|
||||
import org.apache.hadoop.hbase.util.Bytes;
|
||||
import org.apache.hadoop.hbase.util.PairOfSameType;
|
||||
import org.apache.yetus.audience.InterfaceAudience;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +49,11 @@ public final class RegionReplicaInfo {
|
|||
private final RegionInfo regionInfo;
|
||||
private final RegionState.State regionState;
|
||||
private final ServerName serverName;
|
||||
private final long seqNum;
|
||||
/** See {@link org.apache.hadoop.hbase.HConstants#SERVERNAME_QUALIFIER_STR}. */
|
||||
private final ServerName targetServerName;
|
||||
private final Map<String, RegionInfo> mergeRegionInfo;
|
||||
private final Map<String, RegionInfo> splitRegionInfo;
|
||||
|
||||
private RegionReplicaInfo(final Result result, final HRegionLocation location) {
|
||||
this.row = result != null ? result.getRow() : null;
|
||||
|
@ -53,6 +62,26 @@ public final class RegionReplicaInfo {
|
|||
? RegionStateStore.getRegionState(result, regionInfo)
|
||||
: null;
|
||||
this.serverName = location != null ? location.getServerName() : null;
|
||||
this.seqNum = (location != null) ? location.getSeqNum() : HConstants.NO_SEQNUM;
|
||||
this.targetServerName = (result != null && regionInfo != null)
|
||||
? MetaTableAccessor.getTargetServerName(result, regionInfo.getReplicaId())
|
||||
: null;
|
||||
this.mergeRegionInfo = (result != null)
|
||||
? MetaTableAccessor.getMergeRegionsWithName(result.rawCells())
|
||||
: null;
|
||||
|
||||
if (result != null) {
|
||||
PairOfSameType<RegionInfo> daughterRegions = MetaTableAccessor.getDaughterRegions(result);
|
||||
this.splitRegionInfo = new LinkedHashMap<>();
|
||||
if (daughterRegions.getFirst() != null) {
|
||||
splitRegionInfo.put(HConstants.SPLITA_QUALIFIER_STR, daughterRegions.getFirst());
|
||||
}
|
||||
if (daughterRegions.getSecond() != null) {
|
||||
splitRegionInfo.put(HConstants.SPLITB_QUALIFIER_STR, daughterRegions.getSecond());
|
||||
}
|
||||
} else {
|
||||
this.splitRegionInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<RegionReplicaInfo> from(final Result result) {
|
||||
|
@ -102,6 +131,22 @@ public final class RegionReplicaInfo {
|
|||
return serverName;
|
||||
}
|
||||
|
||||
public long getSeqNum() {
|
||||
return seqNum;
|
||||
}
|
||||
|
||||
public ServerName getTargetServerName() {
|
||||
return targetServerName;
|
||||
}
|
||||
|
||||
public Map<String, RegionInfo> getMergeRegionInfo() {
|
||||
return mergeRegionInfo;
|
||||
}
|
||||
|
||||
public Map<String, RegionInfo> getSplitRegionInfo() {
|
||||
return splitRegionInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
|
@ -119,6 +164,10 @@ public final class RegionReplicaInfo {
|
|||
.append(regionInfo, that.regionInfo)
|
||||
.append(regionState, that.regionState)
|
||||
.append(serverName, that.serverName)
|
||||
.append(seqNum, that.seqNum)
|
||||
.append(targetServerName, that.targetServerName)
|
||||
.append(mergeRegionInfo, that.mergeRegionInfo)
|
||||
.append(splitRegionInfo, that.splitRegionInfo)
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
|
@ -129,15 +178,24 @@ public final class RegionReplicaInfo {
|
|||
.append(regionInfo)
|
||||
.append(regionState)
|
||||
.append(serverName)
|
||||
.append(seqNum)
|
||||
.append(targetServerName)
|
||||
.append(mergeRegionInfo)
|
||||
.append(splitRegionInfo)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("row", Bytes.toStringBinary(row))
|
||||
.append("regionInfo", regionInfo)
|
||||
.append("regionState", regionState)
|
||||
.append("serverName", serverName)
|
||||
.append("seqNum", seqNum)
|
||||
.append("transitioningOnServerName", targetServerName)
|
||||
.append("merge*", mergeRegionInfo)
|
||||
.append("split*", splitRegionInfo)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
<%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos" %>
|
||||
<%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas" %>
|
||||
<%@ page import="org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota" %>
|
||||
<%@ page import="java.util.stream.Collectors" %>
|
||||
<%!
|
||||
/**
|
||||
* @return An empty region load stamped with the passed in <code>regionInfo</code>
|
||||
|
@ -386,69 +387,100 @@ if (fqtn != null && master.isInitialized()) {
|
|||
<%
|
||||
}
|
||||
}
|
||||
|
||||
String regionInfoColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.REGIONINFO_QUALIFIER_STR;
|
||||
String serverColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SERVER_QUALIFIER_STR;
|
||||
String startCodeColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.STARTCODE_QUALIFIER_STR;
|
||||
String serverNameColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SERVERNAME_QUALIFIER_STR;
|
||||
String seqNumColumnName = HConstants.CATALOG_FAMILY_STR + ":" + HConstants.SEQNUM_QUALIFIER_STR;
|
||||
%>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>RegionName</th>
|
||||
<th>Start Key</th>
|
||||
<th>End Key</th>
|
||||
<th>Replica ID</th>
|
||||
<th>RegionState</th>
|
||||
<th>ServerName</th>
|
||||
</tr>
|
||||
<%
|
||||
final boolean metaScanHasMore;
|
||||
byte[] lastRow = null;
|
||||
try (final MetaBrowser.Results results = metaBrowser.getResults()) {
|
||||
for (final RegionReplicaInfo regionReplicaInfo : results) {
|
||||
lastRow = Optional.ofNullable(regionReplicaInfo)
|
||||
.map(RegionReplicaInfo::getRow)
|
||||
.orElse(null);
|
||||
if (regionReplicaInfo == null) {
|
||||
%>
|
||||
<tr>
|
||||
<td colspan="6">Null result</td>
|
||||
</tr>
|
||||
<%
|
||||
continue;
|
||||
<div style="overflow-x: auto">
|
||||
<table class="table table-striped nowrap">
|
||||
<tr>
|
||||
<th title="Region name, stored in <%= regionInfoColumnName %> column">RegionName</th>
|
||||
<th title="The startKey of this region">Start Key</th>
|
||||
<th title="The endKey of this region">End Key</th>
|
||||
<th title="Region replica id">Replica ID</th>
|
||||
<th title="State of the region while undergoing transitions">RegionState</th>
|
||||
<th title="Server hosting this region replica, stored in <%= serverColumnName %> column">Server</th>
|
||||
<th title="The seqNum for the region at the time the server opened this region replica, stored in <%= seqNumColumnName %>">Sequence Number</th>
|
||||
<th title="The server to which the region is transiting, stored in <%= serverNameColumnName %> column">Target Server</th>
|
||||
<th title="The parents regions if this region is undergoing a merge">info:merge*</th>
|
||||
<th title="The daughter regions if this region is split">info:split*</th>
|
||||
</tr>
|
||||
<%
|
||||
final boolean metaScanHasMore;
|
||||
byte[] lastRow = null;
|
||||
try (final MetaBrowser.Results results = metaBrowser.getResults()) {
|
||||
for (final RegionReplicaInfo regionReplicaInfo : results) {
|
||||
lastRow = Optional.ofNullable(regionReplicaInfo)
|
||||
.map(RegionReplicaInfo::getRow)
|
||||
.orElse(null);
|
||||
if (regionReplicaInfo == null) {
|
||||
%>
|
||||
<tr>
|
||||
<td colspan="6">Null result</td>
|
||||
</tr>
|
||||
<%
|
||||
continue;
|
||||
}
|
||||
|
||||
final String regionNameDisplay = regionReplicaInfo.getRegionName() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getRegionName())
|
||||
: "";
|
||||
final String startKeyDisplay = regionReplicaInfo.getStartKey() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getStartKey())
|
||||
: "";
|
||||
final String endKeyDisplay = regionReplicaInfo.getEndKey() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getEndKey())
|
||||
: "";
|
||||
final String replicaIdDisplay = regionReplicaInfo.getReplicaId() != null
|
||||
? regionReplicaInfo.getReplicaId().toString()
|
||||
: "";
|
||||
final String regionStateDisplay = regionReplicaInfo.getRegionState() != null
|
||||
? regionReplicaInfo.getRegionState().toString()
|
||||
: "";
|
||||
|
||||
final RegionInfo regionInfo = regionReplicaInfo.getRegionInfo();
|
||||
final ServerName serverName = regionReplicaInfo.getServerName();
|
||||
final RegionState.State regionState = regionReplicaInfo.getRegionState();
|
||||
final int rsPort = master.getRegionServerInfoPort(serverName);
|
||||
|
||||
final long seqNum = regionReplicaInfo.getSeqNum();
|
||||
|
||||
final String regionSpanFormat = "<span title=" + HConstants.CATALOG_FAMILY_STR + ":%s>%s</span>";
|
||||
final String targetServerName = regionReplicaInfo.getTargetServerName().toString();
|
||||
final Map<String, RegionInfo> mergeRegions = regionReplicaInfo.getMergeRegionInfo();
|
||||
final String mergeRegionNames = (mergeRegions == null) ? "" :
|
||||
mergeRegions.entrySet().stream()
|
||||
.map(entry -> String.format(regionSpanFormat, entry.getKey(), entry.getValue().getRegionNameAsString()))
|
||||
.collect(Collectors.joining("<br/>"));
|
||||
final Map<String, RegionInfo> splitRegions = regionReplicaInfo.getSplitRegionInfo();
|
||||
final String splitName = (splitRegions == null) ? "" :
|
||||
splitRegions.entrySet().stream()
|
||||
.map(entry -> String.format(regionSpanFormat, entry.getKey(), entry.getValue().getRegionNameAsString()))
|
||||
.collect(Collectors.joining("<br/>"));
|
||||
%>
|
||||
<tr>
|
||||
<td title="<%= regionInfoColumnName %>"><%= regionNameDisplay %></td>
|
||||
<td title="startKey"><%= startKeyDisplay %></td>
|
||||
<td title="endKey"><%= endKeyDisplay %></td>
|
||||
<td title="replicaId"><%= replicaIdDisplay %></td>
|
||||
<td title="regionState"><%= regionStateDisplay %></td>
|
||||
<td title="<%= serverColumnName + "," + startCodeColumnName %>"><%= buildRegionServerLink(serverName, rsPort, regionInfo, regionState) %></td>
|
||||
<td title="<%= seqNumColumnName %>"><%= seqNum %></td>
|
||||
<td title="<%= serverNameColumnName %>"><%= targetServerName %></td>
|
||||
<td><%= mergeRegionNames %></td>
|
||||
<td><%= splitName %></td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
|
||||
metaScanHasMore = results.hasMoreResults();
|
||||
}
|
||||
|
||||
final String regionNameDisplay = regionReplicaInfo.getRegionName() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getRegionName())
|
||||
: "";
|
||||
final String startKeyDisplay = regionReplicaInfo.getStartKey() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getStartKey())
|
||||
: "";
|
||||
final String endKeyDisplay = regionReplicaInfo.getEndKey() != null
|
||||
? Bytes.toStringBinary(regionReplicaInfo.getEndKey())
|
||||
: "";
|
||||
final String replicaIdDisplay = regionReplicaInfo.getReplicaId() != null
|
||||
? regionReplicaInfo.getReplicaId().toString()
|
||||
: "";
|
||||
final String regionStateDisplay = regionReplicaInfo.getRegionState() != null
|
||||
? regionReplicaInfo.getRegionState().toString()
|
||||
: "";
|
||||
|
||||
final RegionInfo regionInfo = regionReplicaInfo.getRegionInfo();
|
||||
final ServerName serverName = regionReplicaInfo.getServerName();
|
||||
final RegionState.State regionState = regionReplicaInfo.getRegionState();
|
||||
final int rsPort = master.getRegionServerInfoPort(serverName);
|
||||
%>
|
||||
<tr>
|
||||
<td><%= regionNameDisplay %></td>
|
||||
<td><%= startKeyDisplay %></td>
|
||||
<td><%= endKeyDisplay %></td>
|
||||
<td><%= replicaIdDisplay %></td>
|
||||
<td><%= regionStateDisplay %></td>
|
||||
<td><%= buildRegionServerLink(serverName, rsPort, regionInfo, regionState) %></td>
|
||||
</tr>
|
||||
<%
|
||||
}
|
||||
|
||||
metaScanHasMore = results.hasMoreResults();
|
||||
}
|
||||
%>
|
||||
</table>
|
||||
%>
|
||||
</table>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<ul class="pagination" style="margin: 20px 0">
|
||||
|
|
|
@ -54,3 +54,7 @@ table.tablesorter thead tr .headerSortUp {
|
|||
table.tablesorter thead tr .headerSortDown {
|
||||
background-image: url(desc.gif);
|
||||
}
|
||||
|
||||
table.nowrap th, table.nowrap td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue