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