changeset 1264:d41997776788

fix onClose issues
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 25 Sep 2018 17:03:57 -0600
parents 382c444a6c77
children 3f4644246e39
files src/luan/LuanState.java src/luan/host/Backup.java src/luan/host/WebHandler.java src/luan/modules/http/LuanHandler.java
diffstat 4 files changed, 169 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/LuanState.java	Mon Sep 24 22:06:25 2018 -0600
+++ b/src/luan/LuanState.java	Tue Sep 25 17:03:57 2018 -0600
@@ -2,10 +2,6 @@
 
 import java.io.Closeable;
 import java.io.IOException;
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.ArrayList;
 import java.util.Map;
 import java.util.HashMap;
 import org.slf4j.Logger;
@@ -20,9 +16,13 @@
 
 	public LuanJavaOk javaOk;
 	private Map registry;
-	private final List<Reference<Closeable>> onClose = new ArrayList<Reference<Closeable>>();
 	public boolean isLocked = false;
 
+	public interface OnClose extends Closeable {
+		public void onClose(Closeable c);
+	}
+	public OnClose onClose;
+
 	public LuanState() {
 		javaOk = new LuanJavaOk();
 		registry = new HashMap();
@@ -47,25 +47,8 @@
 	}
 
 	public void onClose(Closeable c) {
-		onClose.add(new WeakReference<Closeable>(c));
-	}
-
-	public void close() {
-		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();
-	}
-
-	protected void finalize() throws Throwable {
-		close();
+		if( onClose != null )
+			onClose.onClose(c);
 	}
 
 	public final Object eval(String cmd,Object... args) throws LuanException {
--- a/src/luan/host/Backup.java	Mon Sep 24 22:06:25 2018 -0600
+++ b/src/luan/host/Backup.java	Tue Sep 25 17:03:57 2018 -0600
@@ -1,9 +1,12 @@
 package luan.host;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.lucene.index.SnapshotDeletionPolicy;
@@ -64,6 +67,24 @@
 				luceneInstances = (LuanTable)WebHandler.runLuan( from.getName(), getLucenes, "getLucenes" );
 			} else {
 				luan = new LuanState();
+				luan.onClose = new LuanState.OnClose() {
+					private final List<Closeable> onClose = new ArrayList<Closeable>();
+
+					public void onClose(Closeable c) {
+						onClose.add(c);
+					}
+				
+					public void close() {
+						for( Closeable c : onClose ) {
+							try {
+								c.close();
+							} catch(IOException e) {
+								logger.error(c.toString(),e);
+							}
+						}
+						onClose.clear();
+					}
+				};
 				WebHandler.initLuan( luan, from.toString(), from.getName() );
 				PackageLuan.load(luan,"site:/init.luan");
 				luceneInstances = (LuanTable)luan.eval(getLucenes);
@@ -92,7 +113,7 @@
 			}
 		}
 		if( luan != null )
-			luan.close();
+			luan.onClose.close();
 	}
 
 	public static void backup(File sitesDir,File backupDir) throws IOException {
--- a/src/luan/host/WebHandler.java	Mon Sep 24 22:06:25 2018 -0600
+++ b/src/luan/host/WebHandler.java	Tue Sep 25 17:03:57 2018 -0600
@@ -32,12 +32,10 @@
 	private static final Logger logger = LoggerFactory.getLogger(WebHandler.class);
 
 	private static class LuanRef {
-		private final LuanState luan;
 		private final Handler handler;
 		private final LuanHandler luanHandler;
 
-		private LuanRef(LuanState luan,Handler handler,LuanHandler luanHandler) {
-			this.luan = luan;
+		private LuanRef(Handler handler,LuanHandler luanHandler) {
 			this.handler = handler;
 			this.luanHandler = luanHandler;
 		}
@@ -46,11 +44,11 @@
 	private static final ReferenceQueue<LuanRef> queue = new ReferenceQueue<LuanRef>();
 
 	private static class MyReference extends SoftReference<LuanRef> {
-		private LuanState luan;
+		private LuanHandler luanHandler;
 
 		private MyReference(LuanRef lr) {
 			super(lr,queue);
-			this.luan = lr.luan;
+			this.luanHandler = lr.luanHandler;
 		}
 	}
 
@@ -60,8 +58,8 @@
 			if( ref == null )
 				return;
 			//logger.info("sweep");
-			ref.luan.close();
-			ref.luan = null;
+			ref.luanHandler.close();
+			ref.luanHandler = null;
 		}
 	}
 
@@ -175,7 +173,7 @@
 		String logDir = dir + "/site/private/local/logs/web";
 		new File(logDir).mkdirs();
 
-		return new LuanRef(luan,handler,luanHandler);
+		return new LuanRef(handler,luanHandler);
 	}
 
 	public static void removeHandler(String domain) throws Exception {
@@ -183,7 +181,7 @@
 			Reference<LuanRef> ref = siteMap.remove(domain);
 			LuanRef lr = ref==null ? null : ref.get();
 			if( lr != null ) {
-				lr.luan.close();
+				lr.luanHandler.close();
 			}
 		}
 	}
--- 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 {