001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.fs;
019
020import java.util.Iterator;
021import java.util.Map.Entry;
022import java.util.NavigableMap;
023import java.util.NoSuchElementException;
024import java.util.TreeMap;
025
026import com.google.common.base.Preconditions;
027import org.apache.hadoop.classification.InterfaceAudience;
028
029/**
030 * Stores global storage statistics objects.
031 */
032@InterfaceAudience.Public
033public enum GlobalStorageStatistics {
034  /**
035   * The GlobalStorageStatistics singleton.
036   */
037  INSTANCE;
038
039  /**
040   * A map of all global StorageStatistics objects, indexed by name.
041   */
042  private final NavigableMap<String, StorageStatistics> map = new TreeMap<>();
043
044  /**
045   * A callback API for creating new StorageStatistics instances.
046   */
047  public interface StorageStatisticsProvider {
048    StorageStatistics provide();
049  }
050
051  /**
052   * Get the StorageStatistics object with the given name.
053   *
054   * @param name        The storage statistics object name.
055   * @return            The StorageStatistics object with the given name, or
056   *                      null if there is none.
057   */
058  public synchronized StorageStatistics get(String name) {
059    return name == null ? null : map.get(name);
060  }
061
062  /**
063   * Create or return the StorageStatistics object with the given name.
064   *
065   * @param name        The storage statistics object name.
066   * @param provider    An object which can create a new StorageStatistics
067   *                      object if needed.
068   * @return            The StorageStatistics object with the given name.
069   * @throws RuntimeException  If the StorageStatisticsProvider provides a new
070   *                           StorageStatistics object with the wrong name.
071   */
072  public synchronized StorageStatistics put(String name,
073      StorageStatisticsProvider provider) {
074    Preconditions.checkNotNull(name,
075        "Storage statistics can not have a null name!");
076    StorageStatistics stats = map.get(name);
077    if (stats != null) {
078      return stats;
079    }
080    stats = provider.provide();
081    if (!stats.getName().equals(name)) {
082      throw new RuntimeException("StorageStatisticsProvider for " + name +
083          " provided a StorageStatistics object for " + stats.getName() +
084          " instead.");
085    }
086    map.put(name, stats);
087    return stats;
088  }
089
090  /**
091   * Get an iterator that we can use to iterate throw all the global storage
092   * statistics objects.
093   */
094  synchronized public Iterator<StorageStatistics> iterator() {
095    Entry<String, StorageStatistics> first = map.firstEntry();
096    return new StorageIterator((first == null) ? null : first.getValue());
097  }
098
099  private class StorageIterator implements Iterator<StorageStatistics> {
100    private StorageStatistics next = null;
101
102    StorageIterator(StorageStatistics first) {
103      this.next = first;
104    }
105
106    @Override
107    public boolean hasNext() {
108      return (next != null);
109    }
110
111    @Override
112    public StorageStatistics next() {
113      if (next == null) {
114        throw new NoSuchElementException();
115      }
116      synchronized (GlobalStorageStatistics.this) {
117        StorageStatistics cur = next;
118        Entry<String, StorageStatistics> nextEntry =
119            map.higherEntry(cur.getName());
120        next = (nextEntry == null) ? null : nextEntry.getValue();
121        return cur;
122      }
123    }
124
125    @Override
126    public void remove() {
127      throw new UnsupportedOperationException();
128    }
129  }
130}