diff src/luan/modules/http/LuanHandler.java @ 1264:d41997776788

fix onClose issues
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 25 Sep 2018 17:03:57 -0600
parents 382c444a6c77
children 3f4644246e39
line wrap: on
line diff
--- a/src/luan/modules/http/LuanHandler.java	Mon Sep 24 22:06:25 2018 -0600
+++ b/src/luan/modules/http/LuanHandler.java	Tue Sep 25 17:03:57 2018 -0600
@@ -4,8 +4,14 @@
 import java.io.Writer;
 import java.io.PrintWriter;
 import java.io.IOException;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
 import java.lang.reflect.Method;
 import java.net.BindException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import luan.webserver.Request;
@@ -24,10 +30,114 @@
 import luan.modules.BasicLuan;
 
 
-public final class LuanHandler implements Handler, Closeable {
+public final class LuanHandler implements Handler {
+
+	private class Instance implements LuanState.OnClose {
+		private final List<Reference<Closeable>> onClose;
+		private final LuanState luan;
+		private final ReadWriteLock lock = new ReentrantReadWriteLock();
+
+		Instance() {
+			onClose = new ArrayList<Reference<Closeable>>();
+			LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
+			luan = (LuanState)cloner.clone(luanInit);
+			luan.onClose = this;
+			try {
+				PackageLuan.load(luan,"site:/init.luan");
+			} catch(LuanException e) {
+				String err = e.getLuanStackTraceString();
+				logger.error(err);
+			}
+		}
+
+		Response handle(Request request,String modName) {
+			Thread thread = Thread.currentThread();
+			String oldName = thread.getName();
+			thread.setName(request.headers.get("host")+request.path);
+			lock.readLock().lock();
+			try {
+				return HttpServicer.service(luan,request,modName);
+			} finally {
+				lock.readLock().unlock();
+				thread.setName(oldName);
+			}
+		}
+
+		Object call_rpc(String fnName,Object... args) throws LuanException {
+			lock.readLock().lock();
+			try {
+				LuanFunction fn;
+				LuanState luan = this.luan;
+				synchronized(luan) {
+					PackageLuan.enableLoad(luan,"luan:Rpc.luan");
+					LuanTable rpc = (LuanTable)PackageLuan.require(luan,"luan:Rpc.luan");
+					LuanTable fns = (LuanTable)rpc.get(luan,"functions");
+					fn = (LuanFunction)fns.get(luan,fnName);
+					if( fn == null )
+						throw new LuanException( "function not found: " + fnName );
+					LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
+					luan = (LuanState)cloner.clone(luan);
+					fn = (LuanFunction)cloner.get(fn);
+				}
+				return fn.call(luan,args);
+			} finally {
+				lock.readLock().unlock();
+			}
+		}
+
+		public Object runLuan(String sourceText,String sourceName) throws LuanException {
+			lock.readLock().lock();
+			try {
+				LuanFunction fn = Luan.load(sourceText,sourceName);
+				synchronized(luan) {
+					LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
+					LuanState luan = (LuanState)cloner.clone(this.luan);
+					return fn.call(luan);
+				}
+			} finally {
+				lock.readLock().unlock();
+			}
+		}
+
+		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) {
+							logger.error(c.toString(),e);
+						}
+					}
+				}
+				onClose.clear();
+			}
+		}
+
+		Instance cloneInstance() {
+			synchronized(luan) {
+				return new Instance(this);
+			}
+		}
+
+		private Instance(Instance instance) {
+			onClose = instance.onClose;
+			LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
+			luan = (LuanState)cloner.clone(instance.luan);
+			luan.onClose = this;
+		}
+	}
+
 	private final LuanState luanInit;
 	private final Logger logger;
-	private volatile LuanState luan;
+	private volatile Instance instance;
 
 	private static final Method resetLuanMethod;
 	private static final Method evalInRootMethod;
@@ -52,25 +162,13 @@
 		} catch(LuanException e) {
 			throw new RuntimeException(e);
 		}
-		setLuan();
-		luanInit.onClose(this);
+		instance = new Instance();
 	}
-
+/*
 	public LuanState getLuan() {
 		return luan;
 	}
-
-	private void setLuan() {
-		LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
-		luan = (LuanState)cloner.clone(luanInit);
-		try {
-			PackageLuan.load(luan,"site:/init.luan");
-		} catch(LuanException e) {
-			String err = e.getLuanStackTraceString();
-			logger.error(err);
-		}
-	}
-
+*/
 	@Override public Response handle(Request request) {
 		if( request.path.endsWith("/") )
 			return null;
@@ -79,60 +177,39 @@
 	}
 
 	Response handle(Request request,String modName) {
-		Thread thread = Thread.currentThread();
-		String oldName = thread.getName();
-		thread.setName(request.headers.get("host")+request.path);
-		try {
-			return HttpServicer.service(luan,request,modName);
-		} finally {
-			thread.setName(oldName);
-		}
+		return instance.handle(request,modName);
 	}
 
 	public void close() {
-		synchronized(luan) {
-			luan.close();
-		}
+		instance.close();
 	}
 
 	public Object call_rpc(String fnName,Object... args) throws LuanException {
-		LuanFunction fn;
-		LuanState luan = this.luan;
-		synchronized(luan) {
-			PackageLuan.enableLoad(luan,"luan:Rpc.luan");
-			LuanTable rpc = (LuanTable)PackageLuan.require(luan,"luan:Rpc.luan");
-			LuanTable fns = (LuanTable)rpc.get(luan,"functions");
-			fn = (LuanFunction)fns.get(luan,fnName);
-			if( fn == null )
-				throw new LuanException( "function not found: " + fnName );
-			LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
-			luan = (LuanState)cloner.clone(luan);
-			fn = (LuanFunction)cloner.get(fn);
-		}
-		return fn.call(luan,args);
+		return instance.call_rpc(fnName,args);
 	}
 
 	public void reset_luan() {
-		setLuan();
+		new Thread() {
+			public void run() {
+				instance.lock.writeLock().lock();
+				try {
+					instance.close();
+					instance = new Instance();
+				} finally {
+					instance.lock.writeLock().unlock();
+				}
+			}
+		}.start();
 	}
 
 	public Object runLuan(String sourceText,String sourceName) throws LuanException {
-		LuanFunction fn = Luan.load(sourceText,sourceName);
-		synchronized(luan) {
-			LuanCloner cloner = new LuanCloner(LuanCloner.Type.INCREMENTAL);
-			LuanState luan = (LuanState)cloner.clone(this.luan);
-			return fn.call(luan);
-		}
+		return instance.runLuan(sourceText,sourceName);
 	}
 
 	public void eval_in_root(String text) throws LuanException {
-		LuanState luan;
-		synchronized(this.luan) {
-			LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE);
-			luan = (LuanState)cloner.clone(this.luan);
-		}
-		BasicLuan.load(text,"<eval_in_root>",null).call(luan);
-		this.luan = luan;
+		Instance newInstance = this.instance.cloneInstance();
+		BasicLuan.load(text,"<eval_in_root>",null).call(newInstance.luan);
+		this.instance = newInstance;
 	}
 
 	public static void start(Server server) throws Exception {