Java tutorial
/** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.wasp.master.handler; import com.alibaba.wasp.EntityGroupInfo; import com.alibaba.wasp.Server; import com.alibaba.wasp.ServerName; import com.alibaba.wasp.TableNotDisabledException; import com.alibaba.wasp.executor.EventHandler; import com.alibaba.wasp.master.BulkReOpen; import com.alibaba.wasp.master.FMasterServices; import com.alibaba.wasp.meta.FMetaReader; import com.alibaba.wasp.meta.FMetaScanner; import com.alibaba.wasp.meta.FTable; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.util.Bytes; import org.apache.zookeeper.KeeperException; import java.io.IOException; import java.io.InterruptedIOException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.NavigableMap; import java.util.TreeMap; /** * Base class for performing operations against tables. Checks on whether the * process can go forward are done in constructor rather than later on in * {@link #process()}. The idea is to fail fast rather than later down in an * async invocation of {@link #process()} (which currently has no means of * reporting back issues once started). */ public abstract class TableEventHandler extends EventHandler { private static final Log LOG = LogFactory.getLog(TableEventHandler.class); protected final byte[] tableName; protected final String tableNameStr; protected boolean persistedToZk = false; protected final FMasterServices fMasterServices; public TableEventHandler(final byte[] tableName, Server server, FMasterServices fMasterServices, EventType eventType) throws IOException { super(server, eventType); this.tableName = tableName; this.tableNameStr = Bytes.toString(this.tableName); this.fMasterServices = fMasterServices; try { this.fMasterServices.checkTableModifiable(tableName); } catch (TableNotDisabledException ex) { if (isOnlineSchemaChangeAllowed() && eventType.isOnlineSchemaChangeSupported()) { LOG.debug("Ignoring table not disabled exception " + "for supporting online schema changes."); } else { throw ex; } } } private boolean isOnlineSchemaChangeAllowed() { return this.server.getConfiguration().getBoolean("wasp.online.schema.update.enable", false); } @Override public void process() { try { LOG.info("Handling table operation " + eventType + " on table " + tableNameStr); List<EntityGroupInfo> egis = FMetaReader.getTableEntityGroups(server.getConfiguration(), Bytes.toBytes(tableNameStr)); handleTableOperation(egis); if (eventType.isOnlineSchemaChangeSupported() && this.fMasterServices.getAssignmentManager().getZKTable().isEnabledTable(tableNameStr)) { if (reOpenAllEntityGroups(egis)) { LOG.info("Completed table operation " + eventType + " on table " + tableNameStr); } else { LOG.warn("Error on reopening the entityGroups"); } } } catch (IOException e) { LOG.error("Error manipulating table " + tableNameStr, e); } catch (KeeperException e) { LOG.error("Error manipulating table " + tableNameStr, e); } finally { // notify the waiting thread that we're done persisting the request setPersist(); } } public boolean reOpenAllEntityGroups(List<EntityGroupInfo> entityGroups) throws IOException { boolean done = false; LOG.info("Bucketing entityGroups by entityGroup server..."); TreeMap<ServerName, List<EntityGroupInfo>> serverToEntityGroups = Maps.newTreeMap(); NavigableMap<EntityGroupInfo, ServerName> egiHserverMapping = FMetaScanner .allTableEntityGroups(server.getConfiguration(), tableName, false); List<EntityGroupInfo> reEntityGroups = new ArrayList<EntityGroupInfo>(); for (EntityGroupInfo egi : entityGroups) { ServerName egLocation = egiHserverMapping.get(egi); // Skip the offlined split parent EntityGroup if (null == egLocation) { LOG.info("Skip " + egi); continue; } if (!serverToEntityGroups.containsKey(egLocation)) { LinkedList<EntityGroupInfo> egiList = Lists.newLinkedList(); serverToEntityGroups.put(egLocation, egiList); } reEntityGroups.add(egi); serverToEntityGroups.get(egLocation).add(egi); } LOG.info("Reopening " + reEntityGroups.size() + " entityGroups on " + serverToEntityGroups.size() + " fservers."); this.fMasterServices.getAssignmentManager().setEntityGroupsToReopen(reEntityGroups); BulkReOpen bulkReopen = new BulkReOpen(this.server, serverToEntityGroups, this.fMasterServices.getAssignmentManager()); while (true) { try { if (bulkReopen.bulkReOpen()) { done = true; break; } else { LOG.warn("Timeout before reopening all entityGroups"); } } catch (InterruptedException e) { LOG.warn("Reopen was interrupted"); // Preserve the interrupt. Thread.currentThread().interrupt(); break; } } return done; } /** * Table modifications are processed asynchronously, but provide an API for * you to query their status. * * @throws java.io.IOException */ public synchronized void waitForPersist() throws IOException { if (!persistedToZk) { try { wait(); } catch (InterruptedException ie) { throw (IOException) new InterruptedIOException().initCause(ie); } assert persistedToZk; } } private synchronized void setPersist() { if (!persistedToZk) { persistedToZk = true; notify(); } } /** * @return Table Info for this table * @throws java.io.IOException */ FTable getTable() throws IOException { FTable table = FMetaReader.getTable(server.getConfiguration(), tableNameStr); if (table == null) { throw new IOException("Table missing for " + tableNameStr); } return table; } protected abstract void handleTableOperation(List<EntityGroupInfo> entityGroups) throws IOException, KeeperException; }