/* * 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.accumulo.server.fs; import java.util.concurrent.ConcurrentHashMap; import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.server.client.HdfsZooInstance; import org.apache.accumulo.server.conf.ServerConfigurationFactory; import org.apache.accumulo.server.conf.TableConfiguration; /** * A {@link VolumeChooser} that delegates to another volume chooser based on the presence of an experimental table property, * {@link Property#TABLE_VOLUME_CHOOSER}. If it isn't found, defaults back to {@link RandomVolumeChooser}. */ public class PerTableVolumeChooser implements VolumeChooser { private final VolumeChooser fallbackVolumeChooser = new RandomVolumeChooser(); // TODO Add hint of expected size to construction, see ACCUMULO-3410 /* Track VolumeChooser instances so they can keep state. */ private final ConcurrentHashMap<String,VolumeChooser> tableSpecificChooser = new ConcurrentHashMap<>(); // TODO has to be lazily initialized currently because of the reliance on HdfsZooInstance. see ACCUMULO-3411 private volatile ServerConfigurationFactory serverConfs; @Override public String choose(VolumeChooserEnvironment env, String[] options) { VolumeChooser chooser = null; if (env.hasTableId()) { // This local variable is an intentional component of the single-check idiom. ServerConfigurationFactory localConf = serverConfs; if (localConf == null) { // If we're under contention when first getting here we'll throw away some initializations. localConf = new ServerConfigurationFactory(HdfsZooInstance.getInstance()); serverConfs = localConf; } final TableConfiguration tableConf = localConf.getTableConfiguration(env.getTableId()); chooser = tableSpecificChooser.get(env.getTableId()); if (chooser == null) { VolumeChooser temp = Property.createTableInstanceFromPropertyName(tableConf, Property.TABLE_VOLUME_CHOOSER, VolumeChooser.class, fallbackVolumeChooser); chooser = tableSpecificChooser.putIfAbsent(env.getTableId(), temp); if (chooser == null) { chooser = temp; // Otherwise, someone else beat us to initializing; use theirs. } } else if (!(chooser.getClass().getName().equals(tableConf.get(Property.TABLE_VOLUME_CHOOSER)))) { // the configuration for this table's chooser has been updated. In the case of failure to instantiate we'll repeat here next call. // TODO stricter definition of when the updated property is used, ref ACCUMULO-3412 VolumeChooser temp = Property.createTableInstanceFromPropertyName(tableConf, Property.TABLE_VOLUME_CHOOSER, VolumeChooser.class, fallbackVolumeChooser); VolumeChooser last = tableSpecificChooser.replace(env.getTableId(), temp); if (chooser.equals(last)) { chooser = temp; } else { // Someone else beat us to updating; use theirs. chooser = last; } } } else { chooser = fallbackVolumeChooser; } return chooser.choose(env, options); } }