Mercurial Hosting > luan
comparison src/luan/modules/http/LuanHandler.java @ 1401:ef1620aa99cb
fix gc issues
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 16 Sep 2019 22:51:41 -0400 |
parents | 221eedb0f54e |
children | 27efb1fcbcb5 |
comparison
equal
deleted
inserted
replaced
1400:221eedb0f54e | 1401:ef1620aa99cb |
---|---|
8 import java.lang.ref.WeakReference; | 8 import java.lang.ref.WeakReference; |
9 import java.lang.reflect.Method; | 9 import java.lang.reflect.Method; |
10 import java.net.BindException; | 10 import java.net.BindException; |
11 import java.util.List; | 11 import java.util.List; |
12 import java.util.ArrayList; | 12 import java.util.ArrayList; |
13 import java.util.Set; | |
14 import java.util.Collections; | |
15 import java.util.concurrent.ConcurrentHashMap; | |
13 import java.util.concurrent.locks.ReadWriteLock; | 16 import java.util.concurrent.locks.ReadWriteLock; |
14 import java.util.concurrent.locks.ReentrantReadWriteLock; | 17 import java.util.concurrent.locks.ReentrantReadWriteLock; |
15 import luan.lib.logging.Logger; | 18 import luan.lib.logging.Logger; |
16 import luan.lib.logging.LoggerFactory; | 19 import luan.lib.logging.LoggerFactory; |
17 import luan.lib.webserver.Request; | 20 import luan.lib.webserver.Request; |
29 import luan.modules.PackageLuan; | 32 import luan.modules.PackageLuan; |
30 import luan.modules.BasicLuan; | 33 import luan.modules.BasicLuan; |
31 import luan.modules.logging.LuanLogger; | 34 import luan.modules.logging.LuanLogger; |
32 | 35 |
33 | 36 |
34 public final class LuanHandler implements Handler, Luan.OnClose { | 37 public final class LuanHandler implements Handler, Closeable { |
35 private static final Logger sysLogger = LoggerFactory.getLogger(LuanHandler.class); | 38 private static final Logger sysLogger = LoggerFactory.getLogger(LuanHandler.class); |
39 | |
40 private static final Set<LuanHandler> dontGc = Collections.newSetFromMap(new ConcurrentHashMap<LuanHandler,Boolean>()); | |
36 | 41 |
37 private final Luan luanInit; | 42 private final Luan luanInit; |
38 private final String domain; | 43 private final String domain; |
39 private final Logger luanLogger; | 44 private final Logger luanLogger; |
40 private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); | 45 private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); |
41 private final List<Reference<Closeable>> onClose = new ArrayList<Reference<Closeable>>(); | |
42 private volatile Luan currentLuan; | 46 private volatile Luan currentLuan; |
43 private volatile boolean isDisabled = false; | 47 private volatile boolean isDisabled = false; |
44 | 48 |
45 private static final Method resetLuanMethod; | 49 private static final Method resetLuanMethod; |
46 private static final Method evalInRootMethod; | 50 private static final Method evalInRootMethod; |
47 private static final Method disableLuanMethod; | 51 private static final Method disableLuanMethod; |
52 private static final Method dontGcMethod; | |
48 static { | 53 static { |
49 try { | 54 try { |
50 resetLuanMethod = LuanHandler.class.getMethod( "reset_luan" ); | 55 resetLuanMethod = LuanHandler.Fns.class.getMethod( "reset_luan" ); |
51 evalInRootMethod = LuanHandler.class.getMethod( "eval_in_root", String.class ); | 56 evalInRootMethod = LuanHandler.Fns.class.getMethod( "eval_in_root", String.class ); |
52 disableLuanMethod = LuanHandler.class.getMethod( "disable_luan" ); | 57 disableLuanMethod = LuanHandler.Fns.class.getMethod( "disable_luan" ); |
58 dontGcMethod = LuanHandler.Fns.class.getMethod( "dont_gc" ); | |
53 } catch(NoSuchMethodException e) { | 59 } catch(NoSuchMethodException e) { |
54 throw new RuntimeException(e); | 60 throw new RuntimeException(e); |
55 } | 61 } |
56 } | 62 } |
57 | 63 |
58 public LuanHandler(Luan luanInit,String domain) { | 64 public LuanHandler(Luan luanInit,String domain) { |
59 this.luanInit = luanInit; | 65 this.luanInit = luanInit; |
60 this.domain = domain; | 66 this.domain = domain; |
61 this.luanLogger = luanInit.getLogger(LuanHandler.class); | 67 this.luanLogger = luanInit.getLogger(LuanHandler.class); |
62 try { | 68 try { |
69 Fns fns = new Fns(this); | |
63 LuanTable Http = (LuanTable)luanInit.require("luan:http/Http.luan"); | 70 LuanTable Http = (LuanTable)luanInit.require("luan:http/Http.luan"); |
64 if( Http.get("reset_luan") == null ) | 71 if( Http.get("reset_luan") == null ) |
65 Http.put( "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,this) ); | 72 Http.put( "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,fns) ); |
66 Http.put( "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,this) ); | 73 Http.put( "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,fns) ); |
67 Http.put( "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,this) ); | 74 Http.put( "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,fns) ); |
75 Http.put( "dont_gc", new LuanJavaFunction(luanInit,dontGcMethod,fns) ); | |
68 } catch(LuanException e) { | 76 } catch(LuanException e) { |
69 throw new RuntimeException(e); | 77 throw new RuntimeException(e); |
70 } | 78 } |
79 sysLogger.info("new "+domain); | |
71 currentLuan = newLuan(); | 80 currentLuan = newLuan(); |
72 sysLogger.info("new "+domain); | |
73 } | 81 } |
74 | 82 |
75 protected void finalize() throws Throwable { | 83 protected void finalize() throws Throwable { |
76 sysLogger.info("gc "+domain); | 84 sysLogger.info("gc "+domain); |
77 } | 85 } |
78 | 86 |
79 private Luan newLuan() { | 87 private Luan newLuan() { |
80 Luan luan; | 88 Luan luan; |
81 synchronized(luanInit) { | 89 synchronized(luanInit) { |
82 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 90 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); |
83 luan = (Luan)cloner.clone(luanInit); | 91 luan = (Luan)cloner.clone(luanInit); |
84 } | 92 } |
85 luan.onClose = this; | |
86 try { | 93 try { |
87 PackageLuan.load(luan,"site:/init.luan"); | 94 PackageLuan.load(luan,"site:/init.luan"); |
88 } catch(LuanException e) { | 95 } catch(LuanException e) { |
89 //e.printStackTrace(); | 96 //e.printStackTrace(); |
90 String err = e.getLuanStackTraceString(); | 97 String err = e.getLuanStackTraceString(); |
124 rwLock.readLock().unlock(); | 131 rwLock.readLock().unlock(); |
125 thread.setName(oldName); | 132 thread.setName(oldName); |
126 } | 133 } |
127 } | 134 } |
128 | 135 |
129 public void onClose(Closeable c) { | |
130 synchronized(onClose) { | |
131 onClose.add(new WeakReference<Closeable>(c)); | |
132 } | |
133 } | |
134 | |
135 public void close() { | 136 public void close() { |
136 synchronized(onClose) { | 137 Object obj = dontGc.remove(this); |
137 for( Reference<Closeable> ref : onClose ) { | 138 //sysLogger.info("close "+domain+" "+(obj!=null)); |
138 Closeable c = ref.get(); | |
139 if( c != null ) { | |
140 try { | |
141 c.close(); | |
142 } catch(IOException e) { | |
143 luanLogger.error(c.toString(),e); | |
144 } | |
145 } | |
146 } | |
147 onClose.clear(); | |
148 } | |
149 } | 139 } |
150 | 140 |
151 public Object call_rpc(String fnName,Object... args) throws LuanException { | 141 public Object call_rpc(String fnName,Object... args) throws LuanException { |
152 rwLock.readLock().lock(); | 142 rwLock.readLock().lock(); |
153 try { | 143 try { |
166 } finally { | 156 } finally { |
167 rwLock.readLock().unlock(); | 157 rwLock.readLock().unlock(); |
168 } | 158 } |
169 } | 159 } |
170 | 160 |
171 public void reset_luan() { | 161 public static void start(Server server) throws Exception { |
162 try { | |
163 server.start(); | |
164 } catch(BindException e) { | |
165 throw new LuanException(e.toString()); | |
166 } | |
167 } | |
168 | |
169 private void reset_luan() { | |
172 new Thread() {public void run(){ | 170 new Thread() {public void run(){ |
173 rwLock.writeLock().lock(); | 171 rwLock.writeLock().lock(); |
174 try { | 172 try { |
175 close(); | 173 close(); |
176 currentLuan = newLuan(); | 174 currentLuan = newLuan(); |
178 rwLock.writeLock().unlock(); | 176 rwLock.writeLock().unlock(); |
179 } | 177 } |
180 }}.start(); | 178 }}.start(); |
181 } | 179 } |
182 | 180 |
183 public void disable_luan() { | 181 private void disable_luan() { |
184 isDisabled = true; | 182 isDisabled = true; |
185 } | 183 } |
186 | 184 |
187 public void eval_in_root(String text) throws LuanException { | 185 private void eval_in_root(String text) throws LuanException { |
188 Luan luan; | 186 Luan luan; |
189 synchronized(luanInit) { | 187 synchronized(luanInit) { |
190 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 188 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); |
191 luan = (Luan)cloner.clone(currentLuan); | 189 luan = (Luan)cloner.clone(currentLuan); |
192 } | 190 } |
193 luan.load(text,"<eval_in_root>",null).call(); | 191 luan.load(text,"<eval_in_root>",null).call(); |
194 currentLuan.onClose = null; | |
195 luan.onClose = this; | |
196 currentLuan = luan; | 192 currentLuan = luan; |
197 } | 193 } |
198 | 194 |
199 public static void start(Server server) throws Exception { | 195 private void dont_gc() { |
200 try { | 196 dontGc.add(this); |
201 server.start(); | 197 //sysLogger.info("dont_gc "+domain); |
202 } catch(BindException e) { | 198 } |
203 throw new LuanException(e.toString()); | 199 |
204 } | 200 public static final class Fns { |
205 } | 201 private final Reference<LuanHandler> ref; |
206 | 202 |
203 private Fns(LuanHandler lh) { | |
204 this.ref = new WeakReference<LuanHandler>(lh); | |
205 } | |
206 | |
207 private LuanHandler lh() throws LuanException { | |
208 LuanHandler lh = ref.get(); | |
209 if( lh == null ) | |
210 throw new LuanException("HTTP handler has been garbage collected"); | |
211 return lh; | |
212 } | |
213 | |
214 public void reset_luan() throws LuanException { | |
215 lh().reset_luan(); | |
216 } | |
217 | |
218 public void disable_luan() throws LuanException { | |
219 lh().disable_luan(); | |
220 } | |
221 | |
222 public void eval_in_root(String text) throws LuanException { | |
223 lh().eval_in_root(text); | |
224 } | |
225 | |
226 public void dont_gc() throws LuanException { | |
227 lh().dont_gc(); | |
228 } | |
229 } | |
207 | 230 |
208 | 231 |
209 // from HttpServicer | 232 // from HttpServicer |
210 | 233 |
211 private Response service(Request request,boolean notFound) | 234 private Response service(Request request,boolean notFound) |
287 private void enableLoad(String... mods) throws LuanException { | 310 private void enableLoad(String... mods) throws LuanException { |
288 LuanTable loaded = PackageLuan.loaded(currentLuan); | 311 LuanTable loaded = PackageLuan.loaded(currentLuan); |
289 for( String mod : mods ) { | 312 for( String mod : mods ) { |
290 if( loaded.rawGet(mod) == null ) { | 313 if( loaded.rawGet(mod) == null ) { |
291 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); | 314 LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); |
292 currentLuan.onClose = null; | |
293 currentLuan = (Luan)cloner.clone(currentLuan); | 315 currentLuan = (Luan)cloner.clone(currentLuan); |
294 currentLuan.onClose = this; | |
295 break; | 316 break; |
296 } | 317 } |
297 } | 318 } |
298 } | 319 } |
299 | 320 |