/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.worker.block.evictor; import alluxio.worker.block.BlockMetadataManagerView; import alluxio.worker.block.BlockStoreLocation; import alluxio.worker.block.allocator.Allocator; import alluxio.worker.block.meta.BlockMeta; import alluxio.worker.block.meta.StorageDirView; import alluxio.worker.block.meta.StorageTierView; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.annotation.concurrent.NotThreadSafe; /** * Implementation of an evictor which follows the least recently used algorithm. It discards the * least recently used item based on its access. */ @NotThreadSafe public class LRUEvictor extends AbstractEvictor { private static final int LINKED_HASH_MAP_INIT_CAPACITY = 200; private static final float LINKED_HASH_MAP_INIT_LOAD_FACTOR = 0.75f; private static final boolean LINKED_HASH_MAP_ACCESS_ORDERED = true; private static final boolean UNUSED_MAP_VALUE = true; /** * Access-ordered {@link java.util.LinkedHashMap} from blockId to {@link #UNUSED_MAP_VALUE}(just a * placeholder to occupy the value), acts as a LRU double linked list where most recently accessed * element is put at the tail while least recently accessed element is put at the head. */ protected Map<Long, Boolean> mLRUCache = Collections.synchronizedMap(new LinkedHashMap<Long, Boolean>(LINKED_HASH_MAP_INIT_CAPACITY, LINKED_HASH_MAP_INIT_LOAD_FACTOR, LINKED_HASH_MAP_ACCESS_ORDERED)); /** * Creates a new instance of {@link LRUEvictor}. * * @param view a view of block metadata information * @param allocator an allocation policy */ public LRUEvictor(BlockMetadataManagerView view, Allocator allocator) { super(view, allocator); // preload existing blocks loaded by StorageDir to Evictor for (StorageTierView tierView : mManagerView.getTierViews()) { for (StorageDirView dirView : tierView.getDirViews()) { for (BlockMeta blockMeta : dirView.getEvictableBlocks()) { // all blocks with initial view mLRUCache.put(blockMeta.getBlockId(), UNUSED_MAP_VALUE); } } } } @Override protected Iterator<Long> getBlockIterator() { List<Long> blocks = new ArrayList<>(mLRUCache.keySet()); return blocks.iterator(); } @Override public void onAccessBlock(long sessionId, long blockId) { mLRUCache.put(blockId, UNUSED_MAP_VALUE); } @Override public void onCommitBlock(long sessionId, long blockId, BlockStoreLocation location) { // Since the temp block has been committed, update Evictor about the new added blocks mLRUCache.put(blockId, UNUSED_MAP_VALUE); } @Override public void onRemoveBlockByClient(long sessionId, long blockId) { mLRUCache.remove(blockId); } @Override public void onRemoveBlockByWorker(long sessionId, long blockId) { mLRUCache.remove(blockId); } @Override protected void onRemoveBlockFromIterator(long blockId) { mLRUCache.remove(blockId); } }