public MergeTableRegionsProcedure(final MasterProcedureEnv env, final RegionInfo[] regionsToMerge, final boolean forcible) throws MergeRegionException { super(env); // Check daughter regions and make sure that we have valid daughter regions // before doing the real work. checkRegionsToMerge(regionsToMerge, forcible); // WARN: make sure there is no parent region of the two merging regions in // hbase:meta If exists, fixing up daughters would cause daughter regions(we // have merged one) online again when we restart master, so we should clear // the parent region to prevent the above case // Since HBASE-7721, we don't need fix up daughters any more. so here do nothing this.regionsToMerge = regionsToMerge; this.mergedRegion = createMergedRegionInfo(regionsToMerge); this.forcible = forcible; }
private static void checkRegionsToMerge(final RegionInfo regionToMergeA, final RegionInfo regionToMergeB, final boolean forcible) throws MergeRegionException { if (!regionToMergeA.getTable().equals(regionToMergeB.getTable())) { throw new MergeRegionException("Can't merge regions from two different tables: " + regionToMergeA + ", " + regionToMergeB); } if (regionToMergeA.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID || regionToMergeB.getReplicaId() != RegionInfo.DEFAULT_REPLICA_ID) { throw new MergeRegionException("Can't merge non-default replicas"); } if (!RegionInfo.areAdjacent(regionToMergeA, regionToMergeB)) { String msg = "Unable to merge not adjacent regions " + regionToMergeA.getShortNameToLog() + ", " + regionToMergeB.getShortNameToLog() + " where forcible = " + forcible; LOG.warn(msg); if (!forcible) { throw new MergeRegionException(msg); } } }
/** * Merge two regions. Asynchronous operation. * @param encodedNameOfRegionA encoded name of region a * @param encodedNameOfRegionB encoded name of region b * @param forcible true if do a compulsory merge, otherwise we will only merge * two adjacent regions * @throws IOException */ public void mergeRegions(final byte[] encodedNameOfRegionA, final byte[] encodedNameOfRegionB, final boolean forcible) throws IOException { MasterKeepAliveConnection master = connection .getKeepAliveMasterService(); try { DispatchMergingRegionsRequest request = RequestConverter .buildDispatchMergingRegionsRequest(encodedNameOfRegionA, encodedNameOfRegionB, forcible); master.dispatchMergingRegions(null, request); } catch (ServiceException se) { IOException ioe = ProtobufUtil.getRemoteException(se); if (ioe instanceof UnknownRegionException) { throw (UnknownRegionException) ioe; } if (ioe instanceof MergeRegionException) { throw (MergeRegionException) ioe; } LOG.error("Unexpected exception: " + se + " from calling HMaster.dispatchMergingRegions"); } catch (DeserializationException de) { LOG.error("Could not parse destination server name: " + de); } finally { master.close(); } }
private static void checkRegionsToMerge(final RegionInfo[] regionsToMerge, final boolean forcible) throws MergeRegionException { // For now, we only merge 2 regions. // It could be extended to more than 2 regions in the future. if (regionsToMerge == null || regionsToMerge.length != 2) { throw new MergeRegionException("Expected to merge 2 regions, got: " + Arrays.toString(regionsToMerge)); } checkRegionsToMerge(regionsToMerge[0], regionsToMerge[1], forcible); }
@Override public DispatchMergingRegionsResponse dispatchMergingRegions( RpcController controller, DispatchMergingRegionsRequest request) throws ServiceException { final byte[] encodedNameOfRegionA = request.getRegionA().getValue() .toByteArray(); final byte[] encodedNameOfRegionB = request.getRegionB().getValue() .toByteArray(); final boolean forcible = request.getForcible(); if (request.getRegionA().getType() != RegionSpecifierType.ENCODED_REGION_NAME || request.getRegionB().getType() != RegionSpecifierType.ENCODED_REGION_NAME) { LOG.warn("mergeRegions specifier type: expected: " + RegionSpecifierType.ENCODED_REGION_NAME + " actual: region_a=" + request.getRegionA().getType() + ", region_b=" + request.getRegionB().getType()); } RegionState regionStateA = assignmentManager.getRegionStates() .getRegionState(Bytes.toString(encodedNameOfRegionA)); RegionState regionStateB = assignmentManager.getRegionStates() .getRegionState(Bytes.toString(encodedNameOfRegionB)); if (regionStateA == null || regionStateB == null) { throw new ServiceException(new UnknownRegionException( Bytes.toStringBinary(regionStateA == null ? encodedNameOfRegionA : encodedNameOfRegionB))); } if (!regionStateA.isOpened() || !regionStateB.isOpened()) { throw new ServiceException(new MergeRegionException( "Unable to merge regions not online " + regionStateA + ", " + regionStateB)); } HRegionInfo regionInfoA = regionStateA.getRegion(); HRegionInfo regionInfoB = regionStateB.getRegion(); if (regionInfoA.compareTo(regionInfoB) == 0) { throw new ServiceException(new MergeRegionException( "Unable to merge a region to itself " + regionInfoA + ", " + regionInfoB)); } if (!forcible && !HRegionInfo.areAdjacent(regionInfoA, regionInfoB)) { throw new ServiceException(new MergeRegionException( "Unable to merge not adjacent regions " + regionInfoA.getRegionNameAsString() + ", " + regionInfoB.getRegionNameAsString() + " where forcible = " + forcible)); } try { dispatchMergingRegions(regionInfoA, regionInfoB, forcible); } catch (IOException ioe) { throw new ServiceException(ioe); } return DispatchMergingRegionsResponse.newBuilder().build(); }
public MergeTableRegionsProcedure(final MasterProcedureEnv env, final RegionInfo regionToMergeA, final RegionInfo regionToMergeB, final boolean forcible) throws MergeRegionException { this(env, new RegionInfo[] {regionToMergeA, regionToMergeB}, forcible); }
@Override public long mergeRegions( final RegionInfo[] regionsToMerge, final boolean forcible, final long nonceGroup, final long nonce) throws IOException { checkInitialized(); assert(regionsToMerge.length == 2); TableName tableName = regionsToMerge[0].getTable(); if (tableName == null || regionsToMerge[1].getTable() == null) { throw new UnknownRegionException ("Can't merge regions without table associated"); } if (!tableName.equals(regionsToMerge[1].getTable())) { throw new IOException ( "Cannot merge regions from two different tables " + regionsToMerge[0].getTable() + " and " + regionsToMerge[1].getTable()); } if (RegionInfo.COMPARATOR.compare(regionsToMerge[0], regionsToMerge[1]) == 0) { throw new MergeRegionException( "Cannot merge a region to itself " + regionsToMerge[0] + ", " + regionsToMerge[1]); } return MasterProcedureUtil.submitProcedure( new MasterProcedureUtil.NonceProcedureRunnable(this, nonceGroup, nonce) { @Override protected void run() throws IOException { getMaster().getMasterCoprocessorHost().preMergeRegions(regionsToMerge); LOG.info(getClientIdAuditPrefix() + " Merge regions " + regionsToMerge[0].getEncodedName() + " and " + regionsToMerge[1].getEncodedName()); submitProcedure(new MergeTableRegionsProcedure(procedureExecutor.getEnvironment(), regionsToMerge, forcible)); getMaster().getMasterCoprocessorHost().postMergeRegions(regionsToMerge); } @Override protected String getDescription() { return "MergeTableProcedure"; } }); }