cachestore.java

来自「很棒的web服务器源代码」· Java 代码 · 共 1,263 行 · 第 1/3 页

JAVA
1,263
字号
			    "resized generation!!";			throw new InvalidCacheException(msg);		    }		}	    } else {		// failed! unload a generation on disk and create a new		// generation if the storelimit and the max number of 		// generations have not been reached.		if ((state.getStoreCount() < (storelimit - generationlimit)) 		    && (state.getNbGeneration() < max_generation)) {		    // unload the oldest loaded generation until		    // we can create a new generation		    while (new_cg == null) {			CacheGeneration older_cg = getLRULoadedGeneration();			if (older_cg == null) {			    String msg = 				"No Generation Loaded but store limit reached";			    throw new InvalidCacheException(msg);			}			synchronized(this) {			    unloadGeneration(older_cg);			    // Create a new generation			    new_cg = addNewGeneration();			}		    }		} else {		    // we can't create a new generation so empty the oldest		    // generation		    CacheGeneration older_cg = null;		    synchronized(this) {			older_cg = getLRUGeneration();			if (older_cg == null) {			    String msg = "No Generation Loaded"+				" but store limit reached";			    throw new InvalidCacheException(msg);			}			older_cg.emptyGeneration();			long cg_limit = older_cg.getByteLimit();			generationlimit = 			    ((generationlimit * (max_generation - 1)) 			     + cg_limit) / max_generation;			generations.toHead(older_cg);			setGenerationFile(older_cg);		    }		    getSweeper().collectStored(older_cg);		    new_cg = older_cg;		}		// finally add the resource in the new generation		if (! new_cg.addResource(cr, size, oldsize)) {		    // resize generation		    resizeGeneration(new_cg, cr);		    // try again		    if (! new_cg.addResource(cr, size, oldsize)) {			String msg = "Unable to add a cachedResource in a "+			    "resized generation!!";			throw new InvalidCacheException(msg);		    }		    return true;		}	    }	} else {	    CacheGeneration new_cg = null;	    synchronized (this) {		new_cg = addNewGeneration();	    }	    if (new_cg == null) {		String msg = "Unable create the first generation!!";		throw new InvalidCacheException(msg);	    }	    if (! new_cg.addResource(cr, size, oldsize)) {		// resize generation		resizeGeneration(new_cg, cr);		// try again		if (! new_cg.addResource(cr, size, oldsize)) {		    String msg = "Unable to add a cachedResource in a "+			"resized generation!!";		    throw new InvalidCacheException(msg);		}		return true;	    }	}	return false;    }    /**     * Get a beautiful file number, eg :     * <ul>     * <li>2 => 002 if size == 3     * <li>50 => 0050 if size == 4     * <li>5000 => 5000 if size < 4     * @param nb the file number     * @param size the 'size' of the number     * @return a String     */    private String getFileNumber(int nb, int size) {	//compute the number of '0' to add	int cpt = 0;	int nb2 = nb;	if (nb2 == 0) {	    cpt = 1;	} else {	    while (nb2 > 0) {		nb2 = nb2/10;		cpt++;	    }	}	//number of '0' to add = size - cpt;	int zero2add = size - cpt;	StringBuffer buffer = new StringBuffer();	for (int i = 0 ; i < zero2add ; i++) {	    buffer.append("0");	}	buffer.append(Integer.toString(nb));	return buffer.toString();	    }    private File[] getGenerationFiles() 	throws InvalidCacheException    {	FilenameFilter filter = new FilenameFilter() {	    /**	     * Accept file like gen-xxxx (xxxx is a number)	     */	    public boolean accept(File dir, String name) {		return (name.startsWith(GENERATION_FILENAME));	    }	};	if (cache_dir == null) {	    throw new InvalidCacheException("No Cache Directory!!");	} else if (! cache_dir.exists()) {	    cache_dir.mkdirs();	}	return cache_dir.listFiles(filter);    }    /**     * allocate a new name for the next generation file.     * @return a File, used to dump the generation     * @exception InvalidCacheException if the cache is corrupted     */    private synchronized void setGenerationFile(CacheGeneration gen) 	throws InvalidCacheException    {	int current_generation = state.incrCurrentGeneration();	File file = new File(cache_dir, GENERATION_FILENAME+			getFileNumber(current_generation, 4));	if (debug) {	    System.err.println(file);	}	gen.setGenerationFile(file);	gen.setId(current_generation);    }    /**     * allocate a new name for the next cached resource. This method     * create some directories if needed.     * @return a File, used to dump the entry     */    protected File getNewEntryFile() {	int curnum;	synchronized (this) {	    curnum = state.incrEntryNum();	}	int filenum = curnum / nb_dir;	int dirnum  = curnum % nb_dir;	File dir = dirs[dirnum];	return new File(dir, getFileNumber(filenum, 4));    }    public String toString() {	StringBuffer buffer = new StringBuffer();	buffer.append(">>> CacheStore [")	    .append(cache_dir.getAbsolutePath()).append("] <<<");	buffer.append("\n  Store limit          : ").append(storelimit);	buffer.append("\n  Byte limit           : ").append(bytelimit);	buffer.append("\n  CR limit             : ").append(cr_limit);	buffer.append(state);	return buffer.toString();    }    /**     * Check the subdirectories. Create them if necessary.     */    protected void checkDirs() {	dirs = new File[nb_dir];	for (int i = 0 ; i < nb_dir ; i++) {	    dirs[i] = new File(cache_dir, getFileNumber(i, 3));	    if (! dirs[i].exists()) {		dirs[i].mkdirs();	    }	}    }    /**     * Clean the Cache directory, remove unused files.     * @return the number of files deleted.     */    protected int cleanCacheDir() {	// first, store all the known files	Hashtable       entryfiles = new Hashtable();	CacheGeneration cg         = (CacheGeneration) generations.getHead();	while (cg != null) {	    Enumeration enum = cg.getFiles();	    while (enum.hasMoreElements()) {		entryfiles.put(enum.nextElement(), Boolean.TRUE);	    }	    cg = getNextGeneration(cg);	}	// check all files found in dirs	int cpt = 0;	for (int i = 0 ; i < dirs.length ; i++) {	    File files[] = dirs[i].listFiles();	    if (files != null) {		for (int j = 0 ; j < files.length ; j++) {		    if (entryfiles.get(files[j]) == null) {			if (files[j].delete()) {			    cpt++;			    if (debug) {				System.out.println(files[j]+						   " not used, removed");			    }			}		    }		}	    }	}	return cpt;    }    /**     * update the mode of the sweeper according to the state of the      * cache store,      */    protected void updateSweeperPriority() {	long byteCount         = state.getByteCount();	long storeCount        = state.getStoreCount();	long crCount           = state.getCrCount();	CacheSweeper sweeper   = getSweeper();	// over the limit of cached resource usage, stop and clean	if (byteCount > bytelimit) {	    sweeper.setState(CacheSweeper.STATE_FORCE_CLEAN_GENERATIONS);	} else if (byteCount > (long)((float) bytelimit * gc_kept_ratio)) {	    // near the limit, start loosely to remove resources	    sweeper.setState(CacheSweeper.STATE_CLEAN_GENERATIONS);	} else if (storeCount > storelimit) {	    // to many on the disk, remove then asap	    sweeper.setState(CacheSweeper.STATE_FORCE_CLEAN_STORED);	} else {	    // normal operation, remove in a smooth way the deleted resources	    sweeper.setState(CacheSweeper.STATE_CLEAN_STORED);	}    }    /**     * Compact our generations     * The algorithm is the following,     * If the number of generation is the maximum number allowed,      * then a check is done from the the generation after the MRU one     * and if the sum of two generation can fit into one, it is done, and     * the generation is removed from the list     */    protected void compactGenerations() {	if (debug)	    System.out.println("*** trying to compact generations");	// limit not reached? exit ASAP	if (state.getNbGeneration() < max_generation)	    return;	if (debug)	    System.out.println("*** compact: Max reached, compacting...");	CacheGeneration gen = getMRUGeneration();	CacheGeneration nextGen;	gen = getNextGeneration(gen);	while (gen != null) {	    if (debug) {		System.out.println("*** compact: working on generation " + 				   gen.getId());	    }	    nextGen = getNextGeneration(gen);	    // last one, exit	    if (nextGen == null) {		break;	    }	    if ((gen.getCachedByteCount() + nextGen.getCachedByteCount()) <		gen.getByteLimit()) {		// do the dirty work now...		synchronized (generations) {		    if (debug) {			System.out.println("*** compact: merging ("+					   gen.getId() + ") and ("+					   nextGen.getId()+")");		    }		    generations.remove(nextGen);		    gen.copyInto(nextGen);		    nextGen.deleteGenerationFile();		    state.decrGenerationNum();		}	    }	    gen = getNextGeneration(gen);	}    }	        /**     * used for debugging, display some internal information about the state      * of the cache     */    protected synchronized void checkState() {	long byteCount         = state.getByteCount();	long storeCount        = state.getStoreCount();	long crCount           = state.getCrCount();	int  entryNum          = state.getEntryNum();	int  nbGeneration      = state.getNbGeneration();	int  currentGeneration = state.getCurrentGeneration();	double ratio = (((double) byteCount/ bytelimit) * 100);	String rt = String.valueOf(ratio);	if (rt.length() > 5)	    rt = rt.substring(0,5);	System.out.println("  Ratio (BC/BL)*100    : "+rt+" %");    	System.out.println(">>> Generations <<<");	CacheGeneration cg = getMRUGeneration();	System.out.println("  Id  | Loaded  | CR cnt   | BT lim   | "+			   "BT cnt   | ST cnt   | ratio");	System.out.println(" ---------------------------------------------"+			   "---------------------------");	long bc = 0;	long sc = 0;	while (cg != null) {	    long gbc = cg.getCachedByteCount();	    long gsc = cg.getStoredByteCount();	    long gbl = cg.getByteLimit();	    bc += gbc;	    sc += gsc;	    double percent = (((double)gbc / gbl) * 100);	    String pc = String.valueOf(percent);	    if (pc.length() > 5)		pc = pc.substring(0,5);	    System.out.print("  "+getFileNumber(cg.getId(),2));	    System.out.print("  |  "+cg.isLoaded()+" ");	    System.out.print("  | "+getFileNumber((int)cg.getCRCount(), 7));	    System.out.print("  | "+getFileNumber((int)gbl, 7));	    System.out.print("  | "+getFileNumber((int)gbc,7));	    System.out.print("  | "+getFileNumber((int)gsc,7));	    System.out.println("  | "+pc+" %");	    cg = getNextGeneration(cg);	}	System.out.println(">>> Check State <<<");	System.out.println("  Byte Count  <= Byte Limit    : "+			   ( byteCount <= bytelimit ));	System.out.println("  Store Count <= Store Limit   : "+			   ( storeCount <= storelimit ));	System.out.println("  CR Count    <= CR Limit      : "+			   ( crCount <= cr_limit ));	System.out.println("  Byte Count  <= Store Count   : "+			   ( byteCount <= storeCount ));	System.out.println("  CR Count    <= Entry Num     : "+			   ( crCount <= entryNum ));	System.out.println("  Current gen >= Number of gen : "+			   ( currentGeneration >= nbGeneration ));	System.out.println("  Generations SC == Store SC   : "+			   (sc == storeCount));	System.out.println("  Generations BC == Store BC   : "+ 			   (bc == byteCount));    }    /**     * initialize this CacheStore, and get some infos from the parent,     * aka the cache filter     * @param filter a CacheFilter, our parent     * @exception InvalidCacheException if the cache not initialized     */    public void initialize(CacheFilter filter) 	throws InvalidCacheException    {	this.filter = filter;	props = filter.props;	cache_dir = props.getFile(CACHE_DIRECTORY_P, null);	if (cache_dir == null) {	    cache_dir = new File(System.getProperty("user.dir"));	    cache_dir = new File(cache_dir, ".web-cache");	}	// the capacity of the cache, defaulting to 20Mo	bytelimit = props.getLong(CacheFilter.CACHE_SIZE_P, 20971520);	// the store capacity of the cache, defaulting to 20Mo + 10%	storelimit = props.getLong(STORE_SIZE_P, 23068672);	// the delay between two store sync	sync_delay = props.getLong(SYNCHRONIZATION_DELAY_P, 60000);	// the delay between two attempts to compact the database	gencomp_delay = props.getLong(GENERATION_COMPACT_DELAY_P, 60000);	// the garbage collection flag	garbageCollectionEnabled =	    props.getBoolean(GARBAGE_COLLECTION_ENABLED_P, true);	// the threshold (as in an LRU-threshold cache policy	threshold = props.getDouble(FILE_SIZE_RATIO_P, 0.1);	// the gc limit	gc_kept_ratio = props.getDouble(GARBAGE_COLLECTION_THRESHOLD_P, 0.80);	// the maximal number of generations	max_generation = props.getInteger(MAX_GENERATIONS_P, 10);	// the generation limit size	generationlimit = bytelimit / max_generation;	// debug flag	debug = props.getBoolean(CacheFilter.DEBUG_P, false);	//load	cr_limit = props.getInteger(MAX_CACHED_RESOURCES_P, 50000); 	// load the store state	this.statefile = new File(cache_dir, "state");	loadState();	// check the subdirectories	checkDirs();	// load the generations...	System.out.println("Loading generations...");	loadGenerations();	// clean	System.out.println("Cleaning cache directories...");	int cleaned = cleanCacheDir();	if (cleaned > 0) {	    System.out.println(cleaned+" unused files deleted.");	}    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?