Mercurial > hg > digilib
view common/src/main/java/digilib/io/DocuDirCache.java @ 1236:e8862382a8f2
fix for number of files in directory cache.
author | robcast |
---|---|
date | Mon, 13 Jan 2014 14:13:05 +0100 |
parents | c8e7f5552849 |
children | 5d02e7f08917 |
line wrap: on
line source
package digilib.io; /* * #%L * DocuDirCache.java * * Digital Image Library servlet components * * %% * Copyright (C) 2003 - 2014 MPIWG Berlin * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Lesser Public License for more details. * * You should have received a copy of the GNU General Lesser Public * License along with this program. If not, see * <http://www.gnu.org/licenses/lgpl-3.0.html>. * #L% * Author: Robert Casties (robcast@berlios.de) * Created on 03.03.2003 */ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicInteger; import org.apache.log4j.Logger; import digilib.conf.DigilibConfiguration; import digilib.io.FileOps.FileClass; /** * @author casties */ public class DocuDirCache { /** general logger for this class */ protected static Logger logger = Logger.getLogger(DocuDirCache.class); /** HashMap of directories */ protected ConcurrentMap<String, DocuDirectory> map = new ConcurrentHashMap<String, DocuDirectory>(); /** allowed file class (image/text) */ protected FileClass fileClass = null; /** number of files in the whole cache (approximate) */ protected AtomicInteger numFiles = new AtomicInteger(0); /** number of cache hits */ protected AtomicInteger hits = new AtomicInteger(0); /** number of cache misses */ protected AtomicInteger misses = new AtomicInteger(0); /** * Constructor with array of base directory names and file class. * * @param bd * base directory names * @param fc * @param dlConfig */ public DocuDirCache(FileClass fc, DigilibConfiguration dlConfig) { this.fileClass = fc; } /** * Constructor with array of base directory names. * * @param bd * base directory names */ public DocuDirCache() { // default file class is CLASS_IMAGE fileClass = FileClass.IMAGE; } /** * The number of directories in the cache. * * @return */ public int size() { return (map != null) ? map.size() : 0; } /** * Add a DocuDirectory to the cache. * Always returns the correct Object from the cache, * either newdir one or another one. * * @param newdir * @return dir */ public DocuDirectory put(DocuDirectory newdir) { String s = newdir.getDirName(); logger.debug("DocuDirCache.put for "+s+" in "+this); DocuDirectory olddir = map.putIfAbsent(s, newdir); if (olddir != null) { logger.warn("Duplicate key in DocuDirCache.put -- ignoring!"); return olddir; } numFiles.addAndGet(newdir.size()); return newdir; } /** * Add a directory to the cache and check its parents. * Always returns the correct Object from the cache, * either newDir one or another one. * * @param newDir * @return dir */ public DocuDirectory putDir(DocuDirectory newDir) { DocuDirectory dd = put(newDir); if (dd.getParent() == null) { // no parent link yet String parent = FileOps.parent(newDir.getDirName()); if (parent != "") { // check the parent in the cache DocuDirectory pd = map.get(parent); if (pd == null) { // the parent is unknown pd = DocuDirectoryFactory.getDocuDirectoryInstance(parent, fileClass); pd = putDir(pd); } newDir.setParent(pd); } } return dd; } /** * Returns the DocuDirent with the pathname <code>fn</code> and the index * <code>in</code>. * * If <code>fn</code> is a file then the corresponding DocuDirent is * returned and the index is ignored. * * @param fn * digilib pathname * @param in * file index * @param fc * file class * @return * @deprecated Use {@link #getFile(String fn, int in)} instead. */ public DocuDirent getFile(String fn, int in, FileClass fc) { return getFile(fn, in); } /** * Returns the DocuDirent with the pathname <code>fn</code> and the index * <code>in</code> and the class <code>fc</code>. * * If <code>fn</code> is a file then the corresponding DocuDirent is * returned and the index is ignored. * * @param fn * digilib pathname * @param in * file index * @param fc * file class * @return */ public DocuDirent getFile(String fn, int in) { DocuDirectory dd; // file number is 1-based, vector index is 0-based int n = in - 1; // first, assume fn is a directory and look in the cache dd = map.get(fn); if (dd == null) { // cache miss misses.incrementAndGet(); /* * try fn as a directory */ dd = DocuDirectoryFactory.getDocuDirectoryInstance(fn, fileClass); if (dd.isValid()) { // add to the cache dd.refresh(); dd = putDir(dd); } else { /* * maybe it's a file */ // get the parent directory string (like we store it in the cache) String d = FileOps.parent(fn); // try it in the cache // logger.debug(fn + " is a file in dir " + d); dd = map.get(d); if (dd == null) { // try to read from disk dd = DocuDirectoryFactory.getDocuDirectoryInstance(d, fileClass); if (dd.isValid()) { // add to the cache // logger.debug(dd + " is valid"); dd.refresh(); dd = putDir(dd); } else { // invalid path return null; } } else { // it was not a real cache miss misses.decrementAndGet(); } // get the file's index n = dd.indexOf(FileOps.filename(fn)); } } else { // cache hit hits.incrementAndGet(); } dd.refresh(); if (dd.isValid()) { try { return dd.get(n); } catch (IndexOutOfBoundsException e) { // logger.debug(fn + " not found in directory"); } } return null; } /** * Returns the DocuDirectory indicated by the pathname <code>fn</code>. * * If <code>fn</code> is a file then its parent directory is returned. * * @param fn * digilib pathname * @return */ public DocuDirectory getDirectory(String fn) { DocuDirectory dd; // first, assume fn is a directory and look in the cache dd = map.get(fn); if (dd == null) { // cache miss misses.incrementAndGet(); // see if it's a directory dd = DocuDirectoryFactory.getDocuDirectoryInstance(fn, fileClass); if (dd.isValid()) { // add to the cache dd.refresh(); dd = putDir(dd); } else { // try the parent directory in the cache String pn = FileOps.parent(fn); dd = map.get(pn); if (dd == null) { // try to read from disk dd = DocuDirectoryFactory.getDocuDirectoryInstance(pn, fileClass); if (dd.isValid()) { // add to the cache dd.refresh(); dd = putDir(dd); } else { // invalid path return null; } } else { // not a real cache miss then misses.decrementAndGet(); } } } else { // cache hit hits.incrementAndGet(); } dd.refresh(); if (dd.isValid()) { return dd; } return null; } /** * @return long */ public int getNumFiles() { return numFiles.get(); } /** * @return long */ public int getHits() { return hits.get(); } /** * @return long */ public int getMisses() { return misses.get(); } /** * @return */ public FileClass getFileClass() { return fileClass; } /** * @param fileClasses */ public void setFileClass(FileClass fileClass) { this.fileClass = fileClass; } }