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 + -
显示快捷键?