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 org.apache.hadoop.classification.InterfaceAudience;
027
028/**
029 * Stores global storage statistics objects.
030 */
031@InterfaceAudience.Public
032public enum GlobalStorageStatistics {
033  /**
034   * The GlobalStorageStatistics singleton.
035   */
036  INSTANCE;
037
038  /**
039   * A map of all global StorageStatistics objects, indexed by name.
040   */
041  private final NavigableMap<String, StorageStatistics> map = new TreeMap<>();
042
043  /**
044   * A callback API for creating new StorageStatistics instances.
045   */
046  public interface StorageStatisticsProvider {
047    StorageStatistics provide();
048  }
049
050  /**
051   * Get the StorageStatistics object with the given name.
052   *
053   * @param name        The storage statistics object name.
054   * @return            The StorageStatistics object with the given name, or
055   *                      null if there is none.
056   */
057  public synchronized StorageStatistics get(String name) {
058    return map.get(name);
059  }
060
061  /**
062   * Create or return the StorageStatistics object with the given name.
063   *
064   * @param name        The storage statistics object name.
065   * @param provider    An object which can create a new StorageStatistics
066   *                      object if needed.
067   * @return            The StorageStatistics object with the given name.
068   * @throws RuntimeException  If the StorageStatisticsProvider provides a null
069   *                           object or a new StorageStatistics object with the
070   *                           wrong name.
071   */
072  public synchronized StorageStatistics put(String name,
073      StorageStatisticsProvider provider) {
074    StorageStatistics stats = map.get(name);
075    if (stats != null) {
076      return stats;
077    }
078    stats = provider.provide();
079    if (stats == null) {
080      throw new RuntimeException("StorageStatisticsProvider for " + name +
081          " should not provide a null StorageStatistics object.");
082    }
083    if (!stats.getName().equals(name)) {
084      throw new RuntimeException("StorageStatisticsProvider for " + name +
085          " provided a StorageStatistics object for " + stats.getName() +
086          " instead.");
087    }
088    map.put(name, stats);
089    return stats;
090  }
091
092  /**
093   * Reset all global storage statistics.
094   */
095  public synchronized void reset() {
096    for (StorageStatistics statistics : map.values()) {
097      statistics.reset();
098    }
099  }
100
101  /**
102   * Get an iterator that we can use to iterate throw all the global storage
103   * statistics objects.
104   */
105  synchronized public Iterator<StorageStatistics> iterator() {
106    Entry<String, StorageStatistics> first = map.firstEntry();
107    return new StorageIterator((first == null) ? null : first.getValue());
108  }
109
110  private class StorageIterator implements Iterator<StorageStatistics> {
111    private StorageStatistics next = null;
112
113    StorageIterator(StorageStatistics first) {
114      this.next = first;
115    }
116
117    @Override
118    public boolean hasNext() {
119      return (next != null);
120    }
121
122    @Override
123    public StorageStatistics next() {
124      if (next == null) {
125        throw new NoSuchElementException();
126      }
127      synchronized (GlobalStorageStatistics.this) {
128        StorageStatistics cur = next;
129        Entry<String, StorageStatistics> nextEntry =
130            map.higherEntry(cur.getName());
131        next = (nextEntry == null) ? null : nextEntry.getValue();
132        return cur;
133      }
134    }
135
136    @Override
137    public void remove() {
138      throw new UnsupportedOperationException();
139    }
140  }
141}