Mercurial Hosting > luan
changeset 1401:ef1620aa99cb
fix gc issues
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 16 Sep 2019 22:51:41 -0400 |
parents | 221eedb0f54e |
children | 27efb1fcbcb5 |
files | conv.txt examples/blog/src/lib/Db.luan src/luan/Luan.java src/luan/lib/webserver/handlers/DomainHandler.java src/luan/modules/ThreadLuan.java src/luan/modules/http/LuanHandler.java src/luan/modules/http/tools/Luan_threads.luan |
diffstat | 7 files changed, 114 insertions(+), 130 deletions(-) [+] |
line wrap: on
line diff
--- a/conv.txt Fri Sep 13 05:05:51 2019 -0600 +++ b/conv.txt Mon Sep 16 22:51:41 2019 -0400 @@ -1,3 +1,5 @@ +Thread.schedule + Lucene.index stringify
--- a/examples/blog/src/lib/Db.luan Fri Sep 13 05:05:51 2019 -0600 +++ b/examples/blog/src/lib/Db.luan Mon Sep 16 22:51:41 2019 -0400 @@ -38,6 +38,6 @@ Db.db = Db.new("site:/private/local/lucene") Db.db.restore_from_postgres() -Thread.schedule( Db.db.check, { delay=0, repeating_delay=Time.period{minutes=1}, daemon = true } ) +Thread.schedule( Db.db.check, { delay=0, repeating_delay=Time.period{minutes=1}, id="blog-db-check" } ) return Db
--- a/src/luan/Luan.java Fri Sep 13 05:05:51 2019 -0600 +++ b/src/luan/Luan.java Mon Sep 16 22:51:41 2019 -0400 @@ -1,7 +1,6 @@ package luan; import java.lang.reflect.Array; -import java.io.Closeable; import java.util.List; import java.util.ArrayList; import java.util.Map; @@ -26,11 +25,6 @@ private Map registry; private boolean isLocked = false; - public interface OnClose extends Closeable { - public void onClose(Closeable c); - } - public OnClose onClose; - public Luan() { registry = new HashMap(); } @@ -71,11 +65,6 @@ return registry; } - public void onClose(Closeable c) { - if( onClose != null ) - onClose.onClose(c); - } - public Object eval(String cmd,Object... args) throws LuanException { return load(cmd,"eval").call(args); }
--- a/src/luan/lib/webserver/handlers/DomainHandler.java Fri Sep 13 05:05:51 2019 -0600 +++ b/src/luan/lib/webserver/handlers/DomainHandler.java Mon Sep 16 22:51:41 2019 -0400 @@ -3,7 +3,7 @@ import java.io.Closeable; import java.io.IOException; import java.lang.ref.Reference; -import java.lang.ref.WeakReference; +//import java.lang.ref.WeakReference; import java.lang.ref.SoftReference; import java.lang.ref.ReferenceQueue; import java.util.Map; @@ -22,25 +22,6 @@ public Handler newHandler(String domain); } - private static class Ref { - private final Handler handler; - - private Ref(Handler handler) { - this.handler = handler; - } - } - - private final ReferenceQueue<Ref> queue = new ReferenceQueue<Ref>(); - - private class MyReference extends WeakReference<Ref> { - private Handler handler; - - private MyReference(Ref r) { - super(r,queue); - this.handler = r.handler; - } - } - private static void close(Handler handler) { if( handler instanceof Closeable ) { try { @@ -51,18 +32,7 @@ } } - private void sweep() { - while(true) { - MyReference ref = (MyReference)queue.poll(); - if( ref == null ) - return; - //logger.info("sweep"); - close(ref.handler); - ref.handler = null; - } - } - - private final Map<String,MyReference> map = new HashMap<String,MyReference>(); + private final Map<String,Reference<Handler>> map = new HashMap<String,Reference<Handler>>(); private final Factory factory; @@ -81,37 +51,31 @@ } public Handler getHandler(String domain) { - Ref r = getRef(domain); - return r==null ? null : r.handler; + domain = domain.toLowerCase(); + synchronized(map) { + Reference<Handler> ref = map.get(domain); + Handler handler = ref==null ? null : ref.get(); + if( handler == null ) { + //if(ref!=null) logger.info("gc "+domain); + handler = factory.newHandler(domain); + if( handler == null ) + return null; + map.put(domain,new SoftReference<Handler>(handler)); + } + return handler; + } } public void removeHandler(String domain) { + logger.info("removeHandler "+domain); domain = domain.toLowerCase(); synchronized(map) { - Reference<Ref> ref = map.remove(domain); - Ref r = ref==null ? null : ref.get(); - if( r != null ) { - close(r.handler); + Reference<Handler> ref = map.remove(domain); + Handler handler = ref==null ? null : ref.get(); + if( handler != null ) { + close(handler); } } } - private Ref getRef(String domain) { - domain = domain.toLowerCase(); - synchronized(map) { - Reference<Ref> ref = map.get(domain); - Ref r = ref==null ? null : ref.get(); - if( r == null ) { - //if(ref!=null) logger.info("gc "+domain); - sweep(); - Handler handler = factory.newHandler(domain); - if( handler == null ) - return null; - r = new Ref(handler); - map.put(domain,new MyReference(r)); - } - return r; - } - } - }
--- a/src/luan/modules/ThreadLuan.java Fri Sep 13 05:05:51 2019 -0600 +++ b/src/luan/modules/ThreadLuan.java Mon Sep 16 22:51:41 2019 -0400 @@ -6,11 +6,14 @@ import java.util.Map; import java.util.HashMap; import java.util.LinkedHashMap; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantLock; @@ -21,9 +24,13 @@ import luan.LuanException; import luan.LuanCloner; import luan.LuanCloneable; +import luan.lib.logging.Logger; +import luan.lib.logging.LoggerFactory; public final class ThreadLuan { + private static final Logger logger = LoggerFactory.getLogger(ThreadLuan.class); + private static final Executor exec = Executors.newCachedThreadPool(); public static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); @@ -45,6 +52,8 @@ exec.execute(runnable(newFn)); } + private static Map<String,Reference<ScheduledFuture>> scheduleds = new ConcurrentHashMap<String,Reference<ScheduledFuture>>(); + public static void schedule(LuanFunction fn,LuanTable options) throws LuanException { @@ -52,12 +61,19 @@ Number delay = Utils.removeNumber(map,"delay"); Number repeatingDelay = Utils.removeNumber(map,"repeating_delay"); Number repeatingRate = Utils.removeNumber(map,"repeating_rate"); - boolean daemon = Boolean.TRUE.equals(Utils.removeBoolean(map,"daemon")); - final boolean runOnClose = Boolean.TRUE.equals(Utils.removeBoolean(map,"run_on_close")); + String id = Utils.removeString(map,"id"); if( repeatingDelay!=null && repeatingRate!=null ) throw new LuanException("can't define both repeating_delay and repeating_rate"); boolean repeating = repeatingDelay!=null || repeatingRate!=null; Utils.checkEmpty(map); + if( id != null ) { + Reference<ScheduledFuture> ref = scheduleds.remove(id); + if( ref != null ) { + ScheduledFuture sf = ref.get(); + if( sf != null ) + sf.cancel(false); + } + } Luan luan = fn.luan(); LuanCloner cloner = new LuanCloner(LuanCloner.Type.COMPLETE); final Luan newLuan = (Luan)cloner.clone(luan); @@ -74,26 +90,18 @@ sf = scheduler.scheduleWithFixedDelay(r,delay.longValue(),repeatingRate.longValue(),TimeUnit.MILLISECONDS); } else if( delay != null ) { sf = scheduler.schedule(r,delay.longValue(),TimeUnit.MILLISECONDS); - } else if( runOnClose ) { - Closeable c = new Closeable(){public void close(){ - scheduler.schedule(r,0L,TimeUnit.MILLISECONDS); - }}; - luan.registry().put(c,c); // prevent gc - luan.onClose(c); - return; } else { scheduler.schedule(r,0L,TimeUnit.MILLISECONDS); return; } - Closeable c = new Closeable(){public void close(){ - boolean b = sf.cancel(false); - if( runOnClose ) - scheduler.schedule(r,0L,TimeUnit.MILLISECONDS); - }}; - if( !daemon ) - newLuan.registry().put(luan,luan); // prevent gc - luan.registry().put(c,c); // prevent gc - luan.onClose(c); + Object c = new Object() { + protected void finalize() throws Throwable { + sf.cancel(false); + } + }; + luan.registry().put(c,c); // cancel on gc + if( id != null ) + scheduleds.put(id,new WeakReference<ScheduledFuture>(sf)); } /*
--- 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; } }
--- a/src/luan/modules/http/tools/Luan_threads.luan Fri Sep 13 05:05:51 2019 -0600 +++ b/src/luan/modules/http/tools/Luan_threads.luan Mon Sep 16 22:51:41 2019 -0400 @@ -42,7 +42,7 @@ <ul> <% for i, el in Luan.ipairs(luan_trace) do - local line = LuanException.toString(el); + local line = LuanException.toLuanString(el); %><li><%=line%></li><% end %>