001 package railo.runtime; 002 003 import java.util.Collections; 004 import java.util.HashMap; 005 import java.util.Iterator; 006 import java.util.Map; 007 import java.util.Map.Entry; 008 009 import railo.commons.collections.LongKeyList; 010 import railo.commons.lang.SizeOf; 011 import railo.commons.lang.SystemOut; 012 import railo.runtime.config.ConfigImpl; 013 import railo.runtime.dump.DumpData; 014 import railo.runtime.dump.DumpProperties; 015 import railo.runtime.dump.DumpTable; 016 import railo.runtime.dump.DumpUtil; 017 import railo.runtime.dump.Dumpable; 018 import railo.runtime.dump.SimpleDumpData; 019 import railo.runtime.type.Sizeable; 020 import railo.runtime.type.dt.DateTimeImpl; 021 import railo.runtime.type.util.ArrayUtil; 022 023 /** 024 * pool to handle pages 025 */ 026 public final class PageSourcePool implements Dumpable,Sizeable { 027 028 private Map<Object,PageSource> pageSources=Collections.synchronizedMap(new HashMap<Object, PageSource>()); 029 //timeout timeout for files 030 private long timeout; 031 //max size of the pool cache 032 private int maxSize; 033 034 /** 035 * constructor of the class 036 */ 037 public PageSourcePool() { 038 this.timeout=10000; 039 this.maxSize=1000; 040 } 041 042 /** 043 * return pages matching to key 044 * @param key key for the page 045 * @param updateAccesTime define if do update access time 046 * @return page 047 */ 048 public PageSource getPageSource(Object key,boolean updateAccesTime) { 049 Object o=pageSources.get(key); 050 if(o==null) return null; 051 052 PageSource ps=(PageSource) o; 053 if(updateAccesTime)ps.setLastAccessTime(); 054 return ps; 055 } 056 057 058 /** 059 * sts a page object to the page pool 060 * @param key key reference to store page object 061 * @param ps pagesource to store 062 */ 063 public void setPage(Object key, PageSource ps) { 064 ps.setLastAccessTime(); 065 pageSources.put(key,ps); 066 } 067 068 /** 069 * returns if page object exists 070 * @param key key reference to a page object 071 * @return has page object or not 072 */ 073 public boolean exists(Object key) { 074 return pageSources.containsKey(key); 075 } 076 077 /** 078 * @return returns a array of all keys in the page pool 079 */ 080 public Object[] keys() { 081 return ArrayUtil.keys(pageSources); 082 } 083 084 /** 085 * removes a page from the page pool 086 * @param key key reference to page object 087 * @return page object matching to key reference 088 */ 089 public boolean remove(Object key) { 090 return pageSources.remove(key)!=null; 091 } 092 093 /** 094 * @return returns the size of the pool 095 */ 096 public int size() { 097 return pageSources.size(); 098 } 099 100 /** 101 * @return returns if pool is empty or not 102 */ 103 public boolean isEmpty() { 104 return pageSources.isEmpty(); 105 } 106 107 /** 108 * clear unused pages from page pool 109 */ 110 public void clearUnused(ConfigImpl config) { 111 112 SystemOut.printDate(config.getOutWriter(),"PagePool: "+size()+">("+maxSize+")"); 113 if(size()>maxSize) { 114 Object[] keys=keys(); 115 LongKeyList list=new LongKeyList(); 116 for(int i=0;i<keys.length;i++) { 117 PageSource ps= getPageSource(keys[i],false); 118 long updateTime=ps.getLastAccessTime(); 119 if(updateTime+timeout<System.currentTimeMillis()) { 120 long add=((ps.getAccessCount()-1)*10000); 121 if(add>timeout)add=timeout; 122 list.add(updateTime+add,keys[i]); 123 } 124 } 125 while(size()>maxSize) { 126 Object key = list.shift(); 127 if(key==null)break; 128 remove(key); 129 } 130 } 131 } 132 133 /** 134 * @see railo.runtime.dump.Dumpable#toDumpData(railo.runtime.PageContext, int) 135 */ 136 public DumpData toDumpData(PageContext pageContext,int maxlevel, DumpProperties dp) { 137 maxlevel--; 138 Iterator<Object> it = pageSources.keySet().iterator(); 139 140 141 DumpTable table = new DumpTable("#FFCC00","#FFFF00","#000000"); 142 table.setTitle("Page Source Pool"); 143 table.appendRow(1,new SimpleDumpData("Count"),new SimpleDumpData(pageSources.size())); 144 while(it.hasNext()) { 145 PageSource ps= pageSources.get(it.next()); 146 DumpTable inner = new DumpTable("#FFCC00","#FFFF00","#000000"); 147 inner.setWidth("100%"); 148 inner.appendRow(1,new SimpleDumpData("source"),new SimpleDumpData(ps.getDisplayPath())); 149 inner.appendRow(1,new SimpleDumpData("last access"),DumpUtil.toDumpData(new DateTimeImpl(pageContext,ps.getLastAccessTime(),false), pageContext,maxlevel,dp)); 150 inner.appendRow(1,new SimpleDumpData("access count"),new SimpleDumpData(ps.getAccessCount())); 151 table.appendRow(1,new SimpleDumpData("Sources"),inner); 152 } 153 return table; 154 } 155 156 /** 157 * remove all Page from Pool using this classloader 158 * @param cl 159 */ 160 public void clearPages(ClassLoader cl) { 161 synchronized(pageSources){ 162 Iterator<Entry<Object, PageSource>> it = this.pageSources.entrySet().iterator(); 163 PageSourceImpl entry; 164 while(it.hasNext()) { 165 entry = (PageSourceImpl) it.next().getValue(); 166 if(cl!=null)entry.clear(cl); 167 else entry.clear(); 168 } 169 } 170 } 171 172 public void clear() { 173 pageSources.clear(); 174 } 175 176 @Override 177 public long sizeOf() { 178 return SizeOf.size(this.timeout) 179 +SizeOf.size(this.maxSize) 180 +SizeOf.size(this.pageSources); 181 } 182 }