diff 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
line wrap: on
line diff
--- a/src/luan/modules/http/LuanHandler.java	Fri Sep 13 05:05:51 2019 -0600
+++ b/src/luan/modules/http/LuanHandler.java	Mon Sep 16 22:51:41 2019 -0400
@@ -10,6 +10,9 @@
 import java.net.BindException;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Set;
+import java.util.Collections;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 import luan.lib.logging.Logger;
@@ -31,25 +34,28 @@
 import luan.modules.logging.LuanLogger;
 
 
-public final class LuanHandler implements Handler, Luan.OnClose {
+public final class LuanHandler implements Handler, Closeable {
 	private static final Logger sysLogger = LoggerFactory.getLogger(LuanHandler.class);
 
+	private static final Set<LuanHandler> dontGc = Collections.newSetFromMap(new ConcurrentHashMap<LuanHandler,Boolean>());
+
 	private final Luan luanInit;
 	private final String domain;
 	private final Logger luanLogger;
 	private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
-	private final List<Reference<Closeable>> onClose = new ArrayList<Reference<Closeable>>();
 	private volatile Luan currentLuan;
 	private volatile boolean isDisabled = false;
 
 	private static final Method resetLuanMethod;
 	private static final Method evalInRootMethod;
 	private static final Method disableLuanMethod;
+	private static final Method dontGcMethod;
 	static {
 		try {
-			resetLuanMethod = LuanHandler.class.getMethod( "reset_luan" );
-			evalInRootMethod = LuanHandler.class.getMethod( "eval_in_root", String.class );
-			disableLuanMethod = LuanHandler.class.getMethod( "disable_luan" );
+			resetLuanMethod = LuanHandler.Fns.class.getMethod( "reset_luan" );
+			evalInRootMethod = LuanHandler.Fns.class.getMethod( "eval_in_root", String.class );
+			disableLuanMethod = LuanHandler.Fns.class.getMethod( "disable_luan" );
+			dontGcMethod = LuanHandler.Fns.class.getMethod( "dont_gc" );
 		} catch(NoSuchMethodException e) {
 			throw new RuntimeException(e);
 		}
@@ -60,20 +66,22 @@
 		this.domain = domain;
 		this.luanLogger = luanInit.getLogger(LuanHandler.class);
 		try {
+			Fns fns = new Fns(this);
 			LuanTable Http = (LuanTable)luanInit.require("luan:http/Http.luan");
 			if( Http.get("reset_luan") == null )
-				Http.put( "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,this) );
-			Http.put( "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,this) );
-			Http.put( "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,this) );
+				Http.put( "reset_luan", new LuanJavaFunction(luanInit,resetLuanMethod,fns) );
+			Http.put( "eval_in_root", new LuanJavaFunction(luanInit,evalInRootMethod,fns) );
+			Http.put( "disable_luan", new LuanJavaFunction(luanInit,disableLuanMethod,fns) );
+			Http.put( "dont_gc", new LuanJavaFunction(luanInit,dontGcMethod,fns) );
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
+		sysLogger.info("new "+domain);
 		currentLuan = newLuan();
-		sysLogger.info("new "+domain);
 	}
 
 	protected void finalize() throws Throwable {
-		sysLogger.info("gc  "+domain);
+		sysLogger.info("gc "+domain);
 	}
 
 	private Luan newLuan() {
@@ -82,7 +90,6 @@
 			LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
 			luan = (Luan)cloner.clone(luanInit);
 		}
-		luan.onClose = this;
 		try {
 			PackageLuan.load(luan,"site:/init.luan");
 		} catch(LuanException e) {
@@ -126,26 +133,9 @@
 		}
 	}
 
-	public void onClose(Closeable c) {
-		synchronized(onClose) {
-			onClose.add(new WeakReference<Closeable>(c));
-		}
-	}
-
 	public void close() {
-		synchronized(onClose) {
-			for( Reference<Closeable> ref : onClose ) {
-				Closeable c = ref.get();
-				if( c != null ) {
-					try {
-						c.close();
-					} catch(IOException e) {
-						luanLogger.error(c.toString(),e);
-					}
-				}
-			}
-			onClose.clear();
-		}
+		Object obj = dontGc.remove(this);
+		//sysLogger.info("close "+domain+" "+(obj!=null));
 	}
 
 	public Object call_rpc(String fnName,Object... args) throws LuanException {
@@ -168,7 +158,15 @@
 		}
 	}
 
-	public void reset_luan() {
+	public static void start(Server server) throws Exception {
+		try {
+			server.start();
+		} catch(BindException e) {
+			throw new LuanException(e.toString());
+		}
+	}
+
+	private void reset_luan() {
 		new Thread() {public void run(){
 			rwLock.writeLock().lock();
 			try {
@@ -180,32 +178,57 @@
 		}}.start();
 	}
 
-	public void disable_luan() {
+	private void disable_luan() {
 		isDisabled = true;
 	}
 
-	public void eval_in_root(String text) throws LuanException {
+	private void eval_in_root(String text) throws LuanException {
 		Luan luan;
 		synchronized(luanInit) {
 			LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
 			luan = (Luan)cloner.clone(currentLuan);
 		}
 		luan.load(text,"<eval_in_root>",null).call();
-		currentLuan.onClose = null;
-		luan.onClose = this;
 		currentLuan = luan;
 	}
 
-	public static void start(Server server) throws Exception {
-		try {
-			server.start();
-		} catch(BindException e) {
-			throw new LuanException(e.toString());
+	private void dont_gc() {
+		dontGc.add(this);
+		//sysLogger.info("dont_gc "+domain);
+	}
+
+	public static final class Fns {
+		private final Reference<LuanHandler> ref;
+
+		private Fns(LuanHandler lh) {
+			this.ref = new WeakReference<LuanHandler>(lh);
+		}
+
+		private LuanHandler lh() throws LuanException {
+			LuanHandler lh = ref.get();
+			if( lh == null )
+				throw new LuanException("HTTP handler has been garbage collected");
+			return lh;
+		}
+
+		public void reset_luan() throws LuanException {
+			lh().reset_luan();
+		}
+
+		public void disable_luan() throws LuanException {
+			lh().disable_luan();
+		}
+
+		public void eval_in_root(String text) throws LuanException {
+			lh().eval_in_root(text);
+		}
+
+		public void dont_gc() throws LuanException {
+			lh().dont_gc();
 		}
 	}
 
 
-
 	// from HttpServicer
 
 	private Response service(Request request,boolean notFound)
@@ -289,9 +312,7 @@
 		for( String mod : mods ) {
 			if( loaded.rawGet(mod) == null ) {
 				LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
-				currentLuan.onClose = null;
 				currentLuan = (Luan)cloner.clone(currentLuan);
-				currentLuan.onClose = this;
 				break;
 			}
 		}