/*
 * 2011 January 5
 *
 * The author disclaims copyright to this source code. In place of
 * a legal notice, here is a blessing:
 *
 *    May you do good and not evil.
 *    May you find forgiveness for yourself and forgive others.
 *    May you share freely, never taking more than you give.
 */

/*
 * 2011 February 16
 *
 * This source code is based on the work of Scaevolus (see notice above).
 * It has been slightly modified by Mojang AB to limit the maximum cache
 * size (relevant to extremely big worlds on Linux systems with limited
 * number of file handles). The region files are postfixed with ".mcr"
 * (Minecraft region file) instead of ".data" to differentiate from the
 * original McRegion files.
 *
 */

/*
 * Later changes made by the Glowstone project.
 */

package net.glowstone.io.anvil;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import net.glowstone.GlowServer;
import net.glowstone.util.config.ServerConfig.Key;
import org.bukkit.Bukkit;

/**
 * A simple cache and wrapper for efficiently accessing multiple RegionFiles simultaneously.
 */
public class RegionFileCache {

    private static final int MAX_CACHE_SIZE = ((GlowServer) Bukkit.getServer()).getConfig().getInt(Key.REGION_CACHE_SIZE);

    private static final RemovalListener<File, RegionFile> removalListener = removal -> {
        try {
            removal.getValue().close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    };

    private LoadingCache<File, RegionFile> regions = CacheBuilder.newBuilder()
        .expireAfterAccess(5, TimeUnit.MINUTES)
        .maximumSize(MAX_CACHE_SIZE)
        .removalListener(removalListener)
        .build(new CacheLoader<File, RegionFile>() {
            @Override
            public RegionFile load(File file) throws Exception {
                return new RegionFile(file);
            }
        });

    private final String extension;
    private final File regionDir;

    public RegionFileCache(File basePath, String extension) {
        this.extension = extension;
        regionDir = new File(basePath, "region");
    }

    public RegionFile getRegionFile(int chunkX, int chunkZ) {
        if (!regionDir.isDirectory() && !regionDir.mkdirs()) {
            GlowServer.logger.warning("Failed to create directory: " + regionDir);
        }
        return regions.getUnchecked(new File(regionDir, "r." + (chunkX >> 5) + "." + (chunkZ >> 5) + extension));
    }

    public void clear() throws RejectedExecutionException {
        regions.invalidateAll();
    }

}

@@ -1419,16 +1419,28 @@
 E_SIZE =
+%0A           
  ((GlowS
@@ -1826,16 +1826,20 @@
         
+    
 .expireA
@@ -1878,16 +1878,20 @@
         
+    
 .maximum
@@ -1911,16 +1911,20 @@
 E_SIZE)%0A
+    
         
@@ -1965,16 +1965,20 @@
         
+    
 .build(n
@@ -2026,16 +2026,20 @@
         
+    
 @Overrid
@@ -2040,16 +2040,20 @@
 verride%0A
+    
         
@@ -2121,24 +2121,28 @@
             
+    
 return new R
@@ -2162,34 +2162,42 @@
 e);%0A            
-%7D%0A
+    %7D%0A    
         %7D);%0A%0A   
@@ -2411,32 +2411,370 @@
 egion%22);%0A    %7D%0A%0A
+    /**%0A     * Returns the region file where a chunk is stored, opening it if necessary. Both the region%0A     * file and the directory containing it will be created if they don't exist.%0A     *%0A     * @param chunkX the absolute chunk X coordinate%0A     * @param chunkZ the absolute chunk Z coordinate%0A     * @return the region file%0A     */%0A
     public Regio
@@ -3011,16 +3011,33 @@
 checked(
+%0A                
 new File

Fix CheckStyle issues in io/anvil/RegionFileCache.java (#683)