ncache.java

来自「一款Java实现的HTTP代理服务器」· Java 代码 · 共 620 行 · 第 1/2 页

JAVA
620
字号
	String newName = getEntryName (ent.getId (), true); 	File nFile = new File (newName);	synchronized (dirLock) {	    if (f.exists ()) {		if (f.isFile ()) {		    logger.logWarn ("Wanted cachedir is a file!");		}		// good situation...	    } else {		f.mkdir ();	    }		    boolean bool = cfile.renameTo (nFile);	}	cfile = new File (newName);		ent.setSize (cfile.length ());	ent.setCacheTime (System.currentTimeMillis ());	NCacheEntry<K, V> nent = (NCacheEntry<K, V>)ent;	storeHook (nent);		K realKey = ent.getKey ();	FiledKey<K> fk = new FiledKey<K> ();	fk.storeKey (this, ent, realKey);	w.lock ();	try {	    nent.setKey (fk);	    remove (realKey);	    htab.put (fk, ent);	    currentSize += ent.getSize ();	    vec.add (ent);	} finally {	    w.unlock ();	}		changed = true;    }    private void storeHook (NCacheEntry<K, V> nent) {	V hook = nent.getDataHook (this);	if (hook != null) {	    FiledHook<V> fh = new FiledHook<V> ();	    fh.storeHook (this, nent, hook);	    nent.setFiledDataHook (fh);	}    }    /** Signal that a cache entry have changed.     */    public void entryChanged (CacheEntry<K, V> ent, K newKey, V newHook) {	NCacheEntry<K, V> nent = (NCacheEntry<K, V>)ent;	FiledHook<V> fh = new FiledHook<V> ();	fh.storeHook (this, nent, newHook);	nent.setFiledDataHook (fh);	FiledKey<K> fk = new FiledKey<K> ();	fk.storeKey (this, nent, newKey);		changed = true;	    }    private void removeHook (String base, String extension) {	String hookName = base + extension;	// remove possible hook before file...	File hfile = new File (hookName);	if (hfile.exists ())	    hfile.delete ();    }        /** Remove the Entry with key k from the cache.     * @param k the key for the CacheEntry.     */    public void remove (K k) {	CacheEntry<K, V> rent;	w.lock ();	try {	    if (k == null) {		// Odd, but seems to happen. Probably removed 		// by someone else before enumeration gets to it.		return;    	    }	    FiledKey fk = new MemoryKey<K> (k);	    rent = htab.get (fk);	    if (rent != null) {		// remove entries while it is still in htab.		vec.remove (rent);		currentSize -= rent.getSize ();		htab.remove (fk);	    }	} finally {	    w.unlock ();	}			if (rent != null) {	    // this removes the key => htab.remove can not work..	    String entryName = getEntryName (rent);	    removeHook (entryName, ".hook");	    removeHook (entryName, ".key");	    NCacheEntry<K, V> nent = (NCacheEntry<K, V>)rent;	    nent.setKey (null);	    rent.setDataHook (null);	    File cfile = new File (entryName);	    if (cfile.exists ()) {		File p = cfile.getParentFile ();		cfile.delete ();		// Until NT does rename in a nice manner check for tempdir.		synchronized (dirLock) {		    if (p.exists () && !p.equals (tempdir)) {		    			String ls[] = p.list ();			if (ls != null && ls.length == 0)			    p.delete();		    }		}	    }	}    }    /** Clear the Cache from files.      */    public void clear () {	ArrayList<FiledKey<K>> ls;	w.lock ();	try {	    ls = new ArrayList<FiledKey<K>> (htab.keySet ());	    for (FiledKey<K> k : ls)		remove (k.getData ());	    vec.clear (); // just to be safe.	    currentSize = 0;	    changed = true;	} finally {	    w.unlock ();	}    }    /** Get the CacheEntries in the cache.     *  Note! some entries may be invalid if you have a corruct cache.     * @return an Enumeration of the CacheEntries.     */        public Collection<CacheEntry<K, V>> getEntries () {	return htab.values ();    }    /** Read the info from an old cache.     */    @SuppressWarnings( "unchecked" )    private void readCacheIndex () {	fileNo = 0;	currentSize = 0;	htab = new HashMap<FiledKey<K>, CacheEntry<K, V>> ();	vec = new ArrayList<CacheEntry<K, V>> ();	try {	    String name = dir + File.separator + CACHEINDEX;	    FileInputStream fis = new FileInputStream (name);	    ObjectInputStream is = 		new ObjectInputStream (new GZIPInputStream (fis));	    fileNo = is.readLong ();	    currentSize = is.readLong ();	    int size = is.readInt ();	    Map<FiledKey<K>, CacheEntry<K, V>> hh = 		new HashMap<FiledKey<K>, CacheEntry<K, V>> ((int)(size * 1.2));	    for (int i = 0; i < size; i++) {		FiledKey<K> fk = (FiledKey<K>)is.readObject ();		fk.setCache (this);		NCacheEntry<K, V> entry = (NCacheEntry<K, V>)is.readObject ();		entry.setKey (fk);		hh.put (fk, entry);	    }	    htab = hh;	    vec = (List<CacheEntry<K, V>>)is.readObject ();	    is.close ();	} catch (IOException e) {	    logger.logWarn ("Couldnt read " + 			    dir + File.separator + CACHEINDEX + 			    ", This is bad( but not serius).\n" + 			    "Treating as empty. " + e);	} catch (ClassNotFoundException e) {	    logger.logError("Couldn't find classes: " + e);	}    }        /** Make sure that the cache is written to the disk.     */    public void flush () {	writeCacheIndex ();    }    /** Store the cache to disk so we can reuse it later.     */    private void writeCacheIndex () {	try {	    String name = dir + File.separator + CACHEINDEX;	    	    FileOutputStream fos = new FileOutputStream (name);	    ObjectOutputStream os = 		new ObjectOutputStream (new GZIPOutputStream (fos));	    	    r.lock ();	    try {		os.writeLong (fileNo);		os.writeLong (currentSize);		os.writeInt (htab.size ());		for (Map.Entry<FiledKey<K>, CacheEntry<K, V>> me : 			 htab.entrySet ()) {		    os.writeObject (me.getKey ());		    os.writeObject (me.getValue ());		    		}		os.writeObject (vec);	    } finally {		r.unlock ();	    }	    os.close ();	} catch (IOException e) {	    logger.logWarn ("Couldnt write " + dir + File.separator + 			    CACHEINDEX + ", This is serious!\n" + e);	}	    }    /** Loop in a cleaning loop.     */    public void run () {	Thread.currentThread ().setPriority (Thread. MIN_PRIORITY);	while (running) {	    try {		Thread.sleep (cleanLoopTime);	    } catch (InterruptedException e) {		//System.err.println ("Cache interrupted");	    }	    if (!running)		continue;	    	    // actually for a busy cache this will lag...	    // but I dont care for now... 	    long milis = System.currentTimeMillis ();	    Collection<CacheEntry<K, V>> entries;	    r.lock ();	    try {		entries = new ArrayList<CacheEntry<K, V>> (htab.values ());	    } finally {		r.unlock ();	    }	    for (CacheEntry<K, V> ce : entries) {		long exp = ce.getExpires ();		if (exp < milis) 		    remove (ce.getKey ());	    }	    // IF SIZE IS TO BIG REMOVE A RANDOM AMOUNT OF OBJECTS.	    // What we have to be careful about: we must not remove the same	    // elements two times in a row, this method remove the "oldest" in 	    // a sense.	    if (getCurrentSize () > getMaxSize ())		changed = true;	    while (getCurrentSize () > getMaxSize ()) {		w.lock (); 		try {		    remove (vec.get (0).getKey ());		} finally {		    w.unlock ();		}	    }	    	    if (changed) {		writeCacheIndex ();		changed = false;	    }	}    }    public void stop () {	running = false;	if (cleaner != null) {	    try {		cleaner.interrupt ();		cleaner.join ();	    } catch (InterruptedException e) {		// ignore	    }	}    }    /** Configure the cache system from the given config.     * @param config the properties describing the cache settings.     */    public void setup (Logger logger, SProperties config) {	if (config == null)	    return;	String cachedir = 	    config.getProperty ("directory", "/tmp/rabbit/cache/");	setCacheDir (cachedir);	String cmsize = config.getProperty ("maxsize", "10");	try {	    setMaxSize (Long.parseLong (cmsize) * 1024 * 1024);     // in MB	} catch (NumberFormatException e) { 	    logger.logWarn ("Bad number for cache maxsize: '" + cmsize + "'");	}	String ctime = config.getProperty ("cachetime", "24");	try {	    setCacheTime (Long.parseLong (ctime) * 1000 * 60 * 60); // in hours.	} catch (NumberFormatException e) { 	    logger.logWarn ("Bad number for cache cachetime: '" + ctime + "'");	}	String ct = config.getProperty ("cleanloop", "60");	try {	    setCleanLoopTime (Integer.parseInt (ct) * 1000); // in seconds.	} catch (NumberFormatException e) { 	    logger.logWarn ("Bad number for cache cleanloop: '" + ct + "'");	}    }}

⌨️ 快捷键说明

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