Return-Path: X-Original-To: apmail-lucene-lucene-net-commits-archive@www.apache.org Delivered-To: apmail-lucene-lucene-net-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 20D377341 for ; Sat, 27 Aug 2011 23:16:31 +0000 (UTC) Received: (qmail 62483 invoked by uid 500); 27 Aug 2011 23:16:30 -0000 Delivered-To: apmail-lucene-lucene-net-commits-archive@lucene.apache.org Received: (qmail 62411 invoked by uid 500); 27 Aug 2011 23:16:30 -0000 Mailing-List: contact lucene-net-commits-help@lucene.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: lucene-net-dev@lucene.apache.org Delivered-To: mailing list lucene-net-commits@lucene.apache.org Received: (qmail 62404 invoked by uid 99); 27 Aug 2011 23:16:29 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 27 Aug 2011 23:16:29 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 27 Aug 2011 23:16:26 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 9EF4623888E7; Sat, 27 Aug 2011 23:16:04 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Date: Sat, 27 Aug 2011 23:16:04 -0000 To: lucene-net-commits@lucene.apache.org From: digy@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110827231604.9EF4623888E7@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Subject: [Lucene.Net] svn commit: r1162458 - in /incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util: CloseableThreadLocal-old.cs CloseableThreadLocal.cs Author: digy Date: Sat Aug 27 23:16:04 2011 New Revision: 1162458 URL: http://svn.apache.org/viewvc?rev=1162458&view=rev Log: [LUCENENET-358] New Implementation of CloseableThreadLocal for 2.9.4g Added: incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal-old.cs Modified: incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal.cs Added: incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal-old.cs URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal-old.cs?rev=1162458&view=auto ============================================================================== --- incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal-old.cs (added) +++ incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal-old.cs Sat Aug 27 23:16:04 2011 @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; + +namespace Lucene.Net.Util +{ + + /// Java's builtin ThreadLocal has a serious flaw: + /// it can take an arbitrarily long amount of time to + /// dereference the things you had stored in it, even once the + /// ThreadLocal instance itself is no longer referenced. + /// This is because there is single, master map stored for + /// each thread, which all ThreadLocals share, and that + /// master map only periodically purges "stale" entries. + /// + /// While not technically a memory leak, because eventually + /// the memory will be reclaimed, it can take a long time + /// and you can easily hit OutOfMemoryError because from the + /// GC's standpoint the stale entries are not reclaimaible. + /// + /// This class works around that, by only enrolling + /// WeakReference values into the ThreadLocal, and + /// separately holding a hard reference to each stored + /// value. When you call {@link #close}, these hard + /// references are cleared and then GC is freely able to + /// reclaim space by objects stored in it. + /// + + public class CloseableThreadLocal + { + + [ThreadStatic] + static Support.WeakDictionary, T> slots; + + public virtual T InitialValue() + { + return default(T); + } + + public virtual T Get() + { + T value; + + if (slots == null) + { + value = InitialValue(); + if (value != null) + Set(value); + + return value; + } + + if (slots.ContainsKey(this)) + { + return slots[this]; + } + else + { + value = InitialValue(); + slots[this] = value; + return value; + } + } + + public virtual void Set(T object_Renamed) + { + if (slots == null) + slots = new Support.WeakDictionary, T>(); + + slots[this] = object_Renamed; + } + + public virtual void Close() + { + if(slots != null) + slots.Remove(this); + } + } +} \ No newline at end of file Modified: incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal.cs URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal.cs?rev=1162458&r1=1162457&r2=1162458&view=diff ============================================================================== --- incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal.cs (original) +++ incubator/lucene.net/branches/Lucene.Net_2_9_4g/src/core/Util/CloseableThreadLocal.cs Sat Aug 27 23:16:04 2011 @@ -16,79 +16,146 @@ */ using System; +using System.Collections.Generic; +using System.Threading; namespace Lucene.Net.Util { - - /// Java's builtin ThreadLocal has a serious flaw: - /// it can take an arbitrarily long amount of time to - /// dereference the things you had stored in it, even once the - /// ThreadLocal instance itself is no longer referenced. - /// This is because there is single, master map stored for - /// each thread, which all ThreadLocals share, and that - /// master map only periodically purges "stale" entries. - /// - /// While not technically a memory leak, because eventually - /// the memory will be reclaimed, it can take a long time - /// and you can easily hit OutOfMemoryError because from the - /// GC's standpoint the stale entries are not reclaimaible. - /// - /// This class works around that, by only enrolling - /// WeakReference values into the ThreadLocal, and - /// separately holding a hard reference to each stored - /// value. When you call {@link #close}, these hard - /// references are cleared and then GC is freely able to - /// reclaim space by objects stored in it. - /// - - public class CloseableThreadLocal - { - - [ThreadStatic] - static Support.WeakDictionary, T> slots; - - public virtual T InitialValue() - { - return default(T); - } - public virtual T Get() + /// Java's builtin ThreadLocal has a serious flaw: + /// it can take an arbitrarily long amount of time to + /// dereference the things you had stored in it, even once the + /// ThreadLocal instance itself is no longer referenced. + /// This is because there is single, master map stored for + /// each thread, which all ThreadLocals share, and that + /// master map only periodically purges "stale" entries. + /// + /// While not technically a memory leak, because eventually + /// the memory will be reclaimed, it can take a long time + /// and you can easily hit OutOfMemoryError because from the + /// GC's standpoint the stale entries are not reclaimaible. + /// + /// This class works around that, by only enrolling + /// WeakReference values into the ThreadLocal, and + /// separately holding a hard reference to each stored + /// value. When you call {@link #close}, these hard + /// references are cleared and then GC is freely able to + /// reclaim space by objects stored in it. + /// + /// + + public class CloseableThreadLocal where T : class + { + private ThreadLocal t = new ThreadLocal(); + + private Dictionary hardRefs = new Dictionary(); + + + public virtual T InitialValue() { - T value; + return null; + } - if (slots == null) + public virtual T Get() + { + WeakReference weakRef = t.Get(); + if (weakRef == null) { - value = InitialValue(); - if (value != null) - Set(value); - - return value; + T iv = InitialValue(); + if (iv != null) + { + Set(iv); + return iv; + } + else + return null; } + else + { + return (T)weakRef.Get(); + } + } + + public virtual void Set(T @object) + { + t.Set(new WeakReference(@object)); - if (slots.ContainsKey(this)) + lock (hardRefs) { - return slots[this]; + //hardRefs[Thread.CurrentThread] = @object; + hardRefs.Add(Thread.CurrentThread,@object); + + // Purge dead threads + foreach (var thread in new List(hardRefs.Keys)) + { + if (!thread.IsAlive) + hardRefs.Remove(thread); + } + } - else + } + + public virtual void Close() + { + // Clear the hard refs; then, the only remaining refs to + // all values we were storing are weak (unless somewhere + // else is still using them) and so GC may reclaim them: + hardRefs = null; + // Take care of the current thread right now; others will be + // taken care of via the WeakReferences. + if (t != null) { - value = InitialValue(); - slots[this] = value; - return value; + t.Remove(); } + t = null; + } + } + + internal static class CloseableThreadLocalExtensions + { + public static void Set(this ThreadLocal t, T val) + { + t.Value = val; + } + + public static T Get(this ThreadLocal t) + { + return t.Value; } - - public virtual void Set(T object_Renamed) - { - if (slots == null) - slots = new Support.WeakDictionary, T>(); - - slots[this] = object_Renamed; - } - - public virtual void Close() - { - if(slots != null) - slots.Remove(this); - } - } + + public static void Remove(this ThreadLocal t) + { + t.Dispose(); + } + + public static object Get(this WeakReference w) + { + return w.Target; + } + } + + + // {{DIGY}} + // This causes security exception in Medium Trust + // TestCase: Lucene.Net.Support.TestMediumTrust.TestIndexAndSearch + //class WeakReference : WeakReference where T : class + //{ + // public WeakReference(T target) : base(target) + // { + // } + + // public WeakReference(T target, bool trackResurrection) : base(target, trackResurrection) + // { + // } + + // public new T Target + // { + // get { return (T)base.Target; } + // } + + // public T Get() + // { + // return (T)base.Target; + // } + //} } \ No newline at end of file