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 org.apache.bookkeeper.meta; import java.io.IOException; import java.net.URI; import java.util.List; import java.util.Objects; import lombok.extern.slf4j.Slf4j; import org.apache.bookkeeper.common.util.ReflectionUtils; import org.apache.bookkeeper.conf.AbstractConfiguration; import org.apache.bookkeeper.meta.LayoutManager.LedgerLayoutExistsException; import org.apache.bookkeeper.meta.zk.ZKMetadataDriverBase; import org.apache.commons.configuration.ConfigurationException; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZKUtil; import org.apache.zookeeper.ZooKeeper; /** * Abstract ledger manager factory based on zookeeper, which provides common * methods such as format and validateAndNukeExistingCluster. */ @Slf4j public abstract class AbstractZkLedgerManagerFactory implements LedgerManagerFactory { protected ZooKeeper zk; @SuppressWarnings("deprecation") @Override public void format(AbstractConfiguration<?> conf, LayoutManager layoutManager) throws InterruptedException, KeeperException, IOException { try (AbstractZkLedgerManager ledgerManager = (AbstractZkLedgerManager) newLedgerManager()) { String ledgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); List<String> children = zk.getChildren(ledgersRootPath, false); for (String child : children) { if (!AbstractZkLedgerManager.isSpecialZnode(child) && ledgerManager.isLedgerParentNode(child)) { ZKUtil.deleteRecursive(zk, ledgersRootPath + "/" + child); } } } Class<? extends LedgerManagerFactory> factoryClass; try { factoryClass = conf.getLedgerManagerFactoryClass(); } catch (ConfigurationException e) { throw new IOException("Failed to get ledger manager factory class from configuration : ", e); } layoutManager.deleteLedgerLayout(); // Create new layout information again. createNewLMFactory(conf, layoutManager, factoryClass); } @Override public boolean validateAndNukeExistingCluster(AbstractConfiguration<?> conf, LayoutManager layoutManager) throws InterruptedException, KeeperException, IOException { String zkLedgersRootPath = ZKMetadataDriverBase.resolveZkLedgersRootPath(conf); String zkServers = ZKMetadataDriverBase.resolveZkServers(conf); AbstractZkLedgerManager zkLedgerManager = (AbstractZkLedgerManager) newLedgerManager(); /* * before proceeding with nuking existing cluster, make sure there * are no unexpected znodes under ledgersRootPath */ List<String> ledgersRootPathChildrenList = zk.getChildren(zkLedgersRootPath, false); for (String ledgersRootPathChildren : ledgersRootPathChildrenList) { if ((!AbstractZkLedgerManager.isSpecialZnode(ledgersRootPathChildren)) && (!zkLedgerManager.isLedgerParentNode(ledgersRootPathChildren))) { log.error("Found unexpected znode : {} under ledgersRootPath : {} so exiting nuke operation", ledgersRootPathChildren, zkLedgersRootPath); return false; } } // formatting ledgermanager deletes ledger znodes format(conf, layoutManager); // now delete all the special nodes recursively ledgersRootPathChildrenList = zk.getChildren(zkLedgersRootPath, false); for (String ledgersRootPathChildren : ledgersRootPathChildrenList) { if (AbstractZkLedgerManager.isSpecialZnode(ledgersRootPathChildren)) { ZKUtil.deleteRecursive(zk, zkLedgersRootPath + "/" + ledgersRootPathChildren); } else { log.error("Found unexpected znode : {} under ledgersRootPath : {} so exiting nuke operation", ledgersRootPathChildren, zkLedgersRootPath); return false; } } // finally deleting the ledgers rootpath zk.delete(zkLedgersRootPath, -1); log.info("Successfully nuked existing cluster, ZKServers: {} ledger root path: {}", zkServers, zkLedgersRootPath); return true; } // v1 layout static final int V1 = 1; /** * Create new Ledger Manager Factory. * * @param conf * Configuration Object. * @param layoutManager * layout manager * @return new ledger manager factory * @throws IOException */ @SuppressWarnings("deprecation") public static LedgerManagerFactory newLedgerManagerFactory(final AbstractConfiguration<?> conf, LayoutManager layoutManager) throws IOException, InterruptedException { String metadataServiceUriStr; try { metadataServiceUriStr = conf.getMetadataServiceUri(); } catch (ConfigurationException e) { log.error("Failed to retrieve metadata service uri from configuration", e); throw new IOException("Failed to retrieve metadata service uri from configuration", e); } Class<? extends LedgerManagerFactory> factoryClass; String ledgerRootPath; // `metadataServiceUri` can be null when constructing bookkeeper client using an external zookeeper client. if (null == metadataServiceUriStr) { // try { factoryClass = conf.getLedgerManagerFactoryClass(); } catch (ConfigurationException e) { log.error("Failed to get ledger manager factory class when using an external zookeeper client", e); throw new IOException( "Failed to get ledger manager factory class when using an external zookeeper client", e); } ledgerRootPath = conf.getZkLedgersRootPath(); } else { URI metadataServiceUri = URI.create(metadataServiceUriStr); factoryClass = ZKMetadataDriverBase.resolveLedgerManagerFactory(metadataServiceUri); ledgerRootPath = metadataServiceUri.getPath(); } if (null == ledgerRootPath || ledgerRootPath.length() == 0) { throw new IOException("Empty Ledger Root Path."); } // if layoutManager is null, return the default ledger manager if (layoutManager == null) { return new FlatLedgerManagerFactory().initialize(conf, null, FlatLedgerManagerFactory.CUR_VERSION); } LedgerManagerFactory lmFactory; // check that the configured ledger manager is // compatible with the existing layout LedgerLayout layout = layoutManager.readLedgerLayout(); if (layout == null) { // no existing layout lmFactory = createNewLMFactory(conf, layoutManager, factoryClass); return lmFactory.initialize(conf, layoutManager, lmFactory.getCurrentVersion()); } if (log.isDebugEnabled()) { log.debug("read ledger layout {}", layout); } // there is existing layout, we need to look into the layout. // handle pre V2 layout if (layout.getLayoutFormatVersion() <= V1) { // pre V2 layout we use type of ledger manager String lmType = conf.getLedgerManagerType(); if (lmType != null && !layout.getManagerFactoryClass().equals(lmType)) { throw new IOException("Configured layout " + lmType + " does not match existing layout " + layout.getManagerFactoryClass()); } // create the ledger manager if (FlatLedgerManagerFactory.NAME.equals(layout.getManagerFactoryClass())) { lmFactory = new FlatLedgerManagerFactory(); } else if (HierarchicalLedgerManagerFactory.NAME.equals(layout.getManagerFactoryClass())) { lmFactory = new HierarchicalLedgerManagerFactory(); } else { throw new IOException("Unknown ledger manager type: " + lmType); } return lmFactory.initialize(conf, layoutManager, layout.getManagerVersion()); } // handle V2 layout case if (factoryClass != null && !isSameLedgerManagerFactory(conf, layout.getManagerFactoryClass(), factoryClass.getName()) && conf.getProperty(AbstractConfiguration.LEDGER_MANAGER_FACTORY_DISABLE_CLASS_CHECK) == null) { // Disable should ONLY happen during compatibility testing. throw new IOException("Configured layout " + factoryClass.getName() + " does not match existing layout " + layout.getManagerFactoryClass()); } if (factoryClass == null) { // no factory specified in configuration try { Class<?> theCls = Class.forName(layout.getManagerFactoryClass()); if (!LedgerManagerFactory.class.isAssignableFrom(theCls)) { throw new IOException("Wrong ledger manager factory " + layout.getManagerFactoryClass()); } factoryClass = theCls.asSubclass(LedgerManagerFactory.class); } catch (ClassNotFoundException | IOException e) { factoryClass = attemptToResolveShadedLedgerManagerFactory(conf, layout.getManagerFactoryClass(), e); } } // instantiate a factory lmFactory = ReflectionUtils.newInstance(factoryClass); return lmFactory.initialize(conf, layoutManager, layout.getManagerVersion()); } private static String normalizedLedgerManagerFactoryClassName(String factoryClass, String shadedClassPrefix, boolean isShadedClassAllowed) { if (isShadedClassAllowed) { if (null == factoryClass || null == shadedClassPrefix) { return factoryClass; } else { return factoryClass.replace(shadedClassPrefix, ""); } } else { return factoryClass; } } private static boolean isSameLedgerManagerFactory(AbstractConfiguration<?> conf, String leftFactoryClass, String rightFactoryClass) { leftFactoryClass = normalizedLedgerManagerFactoryClassName(leftFactoryClass, conf.getShadedLedgerManagerFactoryClassPrefix(), conf.isShadedLedgerManagerFactoryClassAllowed()); rightFactoryClass = normalizedLedgerManagerFactoryClassName(rightFactoryClass, conf.getShadedLedgerManagerFactoryClassPrefix(), conf.isShadedLedgerManagerFactoryClassAllowed()); return Objects.equals(leftFactoryClass, rightFactoryClass); } private static Class<? extends LedgerManagerFactory> attemptToResolveShadedLedgerManagerFactory( AbstractConfiguration<?> conf, String lmfClassName, Throwable cause) throws IOException { if (conf.isShadedLedgerManagerFactoryClassAllowed()) { String shadedPrefix = conf.getShadedLedgerManagerFactoryClassPrefix(); log.warn("Failed to instantiate ledger manager factory {}, trying its shaded class {}{}", lmfClassName, shadedPrefix, lmfClassName); // try shading class try { return resolveShadedLedgerManagerFactory(lmfClassName, shadedPrefix); } catch (ClassNotFoundException cnfe) { throw new IOException("Failed to instantiate ledger manager factory " + lmfClassName + " and its shaded class " + shadedPrefix + lmfClassName, cnfe); } } else { throw new IOException("Failed to instantiate ledger manager factory " + lmfClassName, cause); } } private static Class<? extends LedgerManagerFactory> resolveShadedLedgerManagerFactory(String lmfClassName, String shadedClassPrefix) throws ClassNotFoundException, IOException { if (null == lmfClassName) { return null; } else { // this is to address the issue when using the dlog shaded jar Class<?> theCls = Class.forName(shadedClassPrefix + lmfClassName); if (!LedgerManagerFactory.class.isAssignableFrom(theCls)) { throw new IOException("Wrong shaded ledger manager factory : " + shadedClassPrefix + lmfClassName); } return theCls.asSubclass(LedgerManagerFactory.class); } } /** * Creates the new layout and stores in zookeeper and returns the * LedgerManagerFactory instance. */ @SuppressWarnings("deprecation") protected static LedgerManagerFactory createNewLMFactory(final AbstractConfiguration conf, final LayoutManager layoutManager, Class<? extends LedgerManagerFactory> factoryClass) throws IOException, InterruptedException { LedgerManagerFactory lmFactory; LedgerLayout layout; // use default ledger manager factory if no one provided if (factoryClass == null) { // for backward compatibility, check manager type String lmType = conf.getLedgerManagerType(); if (lmType == null) { factoryClass = HierarchicalLedgerManagerFactory.class; } else { if (FlatLedgerManagerFactory.NAME.equals(lmType)) { factoryClass = FlatLedgerManagerFactory.class; } else if (HierarchicalLedgerManagerFactory.NAME.equals(lmType)) { factoryClass = HierarchicalLedgerManagerFactory.class; } else if (LongHierarchicalLedgerManagerFactory.NAME.equals(lmType)) { factoryClass = LongHierarchicalLedgerManagerFactory.class; } else { throw new IOException("Unknown ledger manager type: " + lmType); } } } lmFactory = ReflectionUtils.newInstance(factoryClass); layout = new LedgerLayout(factoryClass.getName(), lmFactory.getCurrentVersion()); try { layoutManager.storeLedgerLayout(layout); } catch (LedgerLayoutExistsException e) { LedgerLayout layout2 = layoutManager.readLedgerLayout(); if (!layout2.equals(layout)) { throw new IOException("Contention writing to layout to zookeeper, " + " other layout " + layout2 + " is incompatible with our " + "layout " + layout); } } return lmFactory; } }