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 null
070   *                           object or a new StorageStatistics object with the
071   *                           wrong name.
072   */
073  public synchronized StorageStatistics put(String name,
074      StorageStatisticsProvider provider) {
075    Preconditions.checkNotNull(name,
076        "Storage statistics can not have a null name!");
077    StorageStatistics stats = map.get(name);
078    if (stats != null) {
079      return stats;
080    }
081    stats = provider.provide();
082    if (stats == null) {
083      throw new RuntimeException("StorageStatisticsProvider for " + name +
084          " should not provide a null StorageStatistics object.");
085    }
086    if (!stats.getName().equals(name)) {
087      throw new RuntimeException("StorageStatisticsProvider for " + name +
088          " provided a StorageStatistics object for " + stats.getName() +
089          " instead.");
090    }
091    map.put(name, stats);
092    return stats;
093  }
094
095  /**
096   * Reset all global storage statistics.
097   */
098  public synchronized void reset() {
099    for (StorageStatistics statistics : map.values()) {
100      statistics.reset();
101    }
102  }
103
104  /**
105   * Get an iterator that we can use to iterate throw all the global storage
106   * statistics objects.
107   */
108  synchronized public Iterator<StorageStatistics> iterator() {
109    Entry<String, StorageStatistics> first = map.firstEntry();
110    return new StorageIterator((first == null) ? null : first.getValue());
111  }
112
113  private class StorageIterator implements Iterator<StorageStatistics> {
114    private StorageStatistics next = null;
115
116    StorageIterator(StorageStatistics first) {
117      this.next = first;
118    }
119
120    @Override
121    public boolean hasNext() {
122      return (next != null);
123    }
124
125    @Override
126    public StorageStatistics next() {
127      if (next == null) {
128        throw new NoSuchElementException();
129      }
130      synchronized (GlobalStorageStatistics.this) {
131        StorageStatistics cur = next;
132        Entry<String, StorageStatistics> nextEntry =
133            map.higherEntry(cur.getName());
134        next = (nextEntry == null) ? null : nextEntry.getValue();
135        return cur;
136      }
137    }
138
139    @Override
140    public void remove() {
141      throw new UnsupportedOperationException();
142    }
143  }
144}