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     */
018    package org.apache.hadoop.hdfs.server.balancer;
019    
020    import java.util.ArrayList;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    
025    import org.apache.hadoop.hdfs.protocol.Block;
026    import org.apache.hadoop.util.Time;
027    
028    /**
029     * This window makes sure to keep blocks that have been moved within a fixed
030     * time interval (default is 1.5 hour). Old window has blocks that are older;
031     * Current window has blocks that are more recent; Cleanup method triggers the
032     * check if blocks in the old window are more than the fixed time interval. If
033     * yes, purge the old window and then move blocks in current window to old
034     * window.
035     * 
036     * @param <L> Location type
037     */
038    public class MovedBlocks<L> {
039      /** A class for keeping track of a block and its locations */
040      public static class Locations<L> {
041        private final Block block; // the block
042        /** The locations of the replicas of the block. */
043        protected final List<L> locations = new ArrayList<L>(3);
044        
045        public Locations(Block block) {
046          this.block = block;
047        }
048        
049        /** clean block locations */
050        public synchronized void clearLocations() {
051          locations.clear();
052        }
053        
054        /** add a location */
055        public synchronized void addLocation(L loc) {
056          if (!locations.contains(loc)) {
057            locations.add(loc);
058          }
059        }
060        
061        /** @return if the block is located on the given location. */
062        public synchronized boolean isLocatedOn(L loc) {
063          return locations.contains(loc);
064        }
065        
066        /** @return its locations */
067        public synchronized List<L> getLocations() {
068          return locations;
069        }
070        
071        /* @return the block */
072        public Block getBlock() {
073          return block;
074        }
075        
076        /* Return the length of the block */
077        public long getNumBytes() {
078          return block.getNumBytes();
079        }
080      }
081    
082      private static final int CUR_WIN = 0;
083      private static final int OLD_WIN = 1;
084      private static final int NUM_WINS = 2;
085    
086      private final long winTimeInterval;
087      private long lastCleanupTime = Time.monotonicNow();
088      private final List<Map<Block, Locations<L>>> movedBlocks
089          = new ArrayList<Map<Block, Locations<L>>>(NUM_WINS);
090      
091      /** initialize the moved blocks collection */
092      public MovedBlocks(long winTimeInterval) {
093        this.winTimeInterval = winTimeInterval;
094        movedBlocks.add(newMap());
095        movedBlocks.add(newMap());
096      }
097    
098      private Map<Block, Locations<L>> newMap() {
099        return new HashMap<Block, Locations<L>>();
100      }
101    
102      /** add a block thus marking a block to be moved */
103      public synchronized void put(Locations<L> block) {
104        movedBlocks.get(CUR_WIN).put(block.getBlock(), block);
105      }
106    
107      /** @return if a block is marked as moved */
108      public synchronized boolean contains(Block block) {
109        return movedBlocks.get(CUR_WIN).containsKey(block) ||
110          movedBlocks.get(OLD_WIN).containsKey(block);
111      }
112    
113      /** remove old blocks */
114      public synchronized void cleanup() {
115        long curTime = Time.monotonicNow();
116        // check if old win is older than winWidth
117        if (lastCleanupTime + winTimeInterval <= curTime) {
118          // purge the old window
119          movedBlocks.set(OLD_WIN, movedBlocks.get(CUR_WIN));
120          movedBlocks.set(CUR_WIN, newMap());
121          lastCleanupTime = curTime;
122        }
123      }
124    }