You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by mh...@apache.org on 2011/08/11 07:36:38 UTC

[Lucene.Net] svn commit: r1156492 - in /incubator/lucene.net/branches/Lucene.Net_4e: src/Lucene.Net/ src/Lucene.Net/Analysis/ src/Lucene.Net/Analysis/TokenAttributes/ src/Lucene.Net/Support/ src/Lucene.Net/Support/Threading/ test/Lucene.Net.Test/ test/Lucene.Net.Te...

Author: mherndon
Date: Thu Aug 11 05:36:38 2011
New Revision: 1156492

URL: http://svn.apache.org/viewvc?rev=1156492&view=rev
Log:
porting the analyzer abstract class and created a prototype of a ThreadLocal<T> that *should work for silverlight. Windows Mobile 7's version of silverlight does not have the [ThreadStatic] attribute, Thread.GetData/SetData or ConcurrentDictionary<T>. So a port of .NET 4's ThreadLocal<T> should help alleviate issues with that. Suggestions on testing stratagies would be appreciated.

Added:
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/Analyzer.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloseable.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/LocalDataStoreSlot.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadData.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadLocalOfT.cs
    incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs
    incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ThreadLocalTest.cs
Modified:
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/ITermToBytesRefAttribute.cs
    incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj
    incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Lucene.Net.Test.csproj

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/Analyzer.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/Analyzer.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/Analyzer.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/Analyzer.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,169 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="Analyzer.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Analysis
+{
+    using System;
+    using System.IO;
+    using System.Reflection;
+    using Lucene.Net.Support;
+    using Lucene.Net.Support.Threading;
+
+    /// <summary>
+    /// TODO: update
+    /// </summary>
+    public abstract class Analyzer : IDisposable
+    {
+        private ThreadLocal<TokenStream> threadLocalTokenStream;
+        private bool disposed = false;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Analyzer"/> class.
+        /// </summary>
+        protected Analyzer()
+        {
+            if (this.AssertSealed() == false)
+                throw new TypeLoadException(
+                    string.Format(
+                         "{0} can not be used. It must be sealed or at least seal" +
+                         " the TokenStream and ResuableTokenStream methods",
+                         this.GetType().Name));
+        }
+
+
+        /// <summary>
+        /// Gets or sets the previous token stream.
+        /// </summary>
+        /// <value>The previous token stream. Returns null if the value has not been set.</value>
+        /// <exception cref="ObjectDisposedException">
+        ///     Thrown when <see cref="Analyzer"/> is already disposed.
+        /// </exception>
+        protected TokenStream PreviousTokenStream
+        {
+            get
+            {
+                if (this.disposed)
+                    throw new ObjectDisposedException(
+                        string.Format(
+                             "This analyzer '{0}' has already been disposed",
+                             this.GetType().FullName));
+
+                if (!this.threadLocalTokenStream.IsValueCreated)
+                    return null;
+                return this.threadLocalTokenStream.Value;
+            }
+
+            set
+            {
+                if (this.disposed)
+                    throw new ObjectDisposedException(
+                        string.Format(
+                             "This analyzer '{0}' has already been disposed",
+                             this.GetType().FullName));
+
+                this.threadLocalTokenStream.Value = value;
+            }
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            this.disposed = true;
+            this.threadLocalTokenStream.Dispose();
+            this.threadLocalTokenStream = null;
+        }
+
+
+        /// <summary>
+        /// Gets the offset gap.
+        /// </summary>
+        /// <returns>An instance of <see cref="Int32"/>.</returns>
+        public virtual int GetOffsetGap()
+        {
+            return 0;
+        }
+
+        /// <summary>
+        /// Gets the position increment gap.
+        /// </summary>
+        /// <param name="fieldName">Name of the field.</param>
+        /// <returns>An instance of <see cref="Int32"/>.</returns>
+        public virtual int GetPositionIncrementGap(string fieldName)
+        {
+            return 0;
+        }
+
+        /// <summary>
+        /// Tokens the stream.
+        /// </summary>
+        /// <param name="fieldName">Name of the field.</param>
+        /// <param name="reader">The reader.</param>
+        /// <returns>
+        /// An instance of <see cref="TokenStream"/>.
+        /// </returns>
+        public abstract TokenStream TokenStream(string fieldName, TextReader reader);
+
+        /// <summary>
+        /// Reusable the token stream.
+        /// </summary>
+        /// <param name="fieldName">Name of the field.</param>
+        /// <param name="reader">The reader.</param>
+        /// <returns>
+        /// An instance of <see cref="TokenStream"/>.
+        /// </returns>
+        public TokenStream ReusableTokenStream(string fieldName, TextReader reader)
+        {
+            return this.TokenStream(fieldName, reader);
+        }
+
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+        }
+
+        // this was ported from lucene, but I'm not convinced this is best way
+        // to handle this kind of design decision.
+        private bool AssertSealed()
+        {
+            Type type = this.GetType();
+
+            if (type.IsSealed || type.IsAbstract)
+                return true;
+
+            BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
+            MethodInfo tokenStreamMethod = type.GetMethod("TokenStream", flags);
+            MethodInfo reuseableTokenStreamMethod = type.GetMethod("ReusableTokenStreamMethod", flags);
+
+
+            if (tokenStreamMethod != null && !tokenStreamMethod.IsFinal)
+                return false;
+
+            return reuseableTokenStreamMethod == null || reuseableTokenStreamMethod.IsFinal;
+        }
+    }
+}
\ No newline at end of file

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/ITermToBytesRefAttribute.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/ITermToBytesRefAttribute.cs?rev=1156492&r1=1156491&r2=1156492&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/ITermToBytesRefAttribute.cs (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Analysis/TokenAttributes/ITermToBytesRefAttribute.cs Thu Aug 11 05:36:38 2011
@@ -46,7 +46,7 @@ namespace Lucene.Net.Analysis.TokenAttri
     ///         while(attribute.IncrementToken())
     ///         {
     ///             int hash attribute.FillBytesRef();
-    ///             if(isInteresting(bytes)) 
+    ///             if (isInteresting(bytes)) 
     ///             {
     ///                 // do something with it.
     ///                 Use(new BytesRef(bytes));

Modified: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj?rev=1156492&r1=1156491&r2=1156492&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Lucene.Net.csproj Thu Aug 11 05:36:38 2011
@@ -45,6 +45,7 @@
     <Reference Include="System.Xml.Serialization" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Analysis\Analyzer.cs" />
     <Compile Include="Analysis\Token.cs" />
     <Compile Include="Analysis\TokenAttributes\CharTermAttribute.cs" />
     <Compile Include="Analysis\TokenAttributes\ICharTermAttribute.cs" />
@@ -69,6 +70,10 @@
     <Compile Include="Support\BaseDictionaryOfTKeyTValue.cs" />
     <Compile Include="Support\ICloneable.cs" />
     <Compile Include="Support\DictionaryExtensions.cs" />
+    <Compile Include="Support\ICloseable.cs" />
+    <Compile Include="Support\Threading\LocalDataStoreSlot.cs" />
+    <Compile Include="Support\Threading\ThreadData.cs" />
+    <Compile Include="Support\Threading\ThreadLocalOfT.cs" />
     <Compile Include="Support\WeakDictionaryOfTKeyTValue.cs" />
     <Compile Include="Support\WeakKeyComparerOfT.cs" />
     <Compile Include="Support\WeakKeyReferenceOfT.cs" />

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloseable.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloseable.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloseable.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/ICloseable.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,39 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="ICloseable.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Support
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+
+    /// <summary>
+    /// TODO: update
+    /// </summary>
+    public interface ICloseable
+    {
+        /// <summary>
+        /// Closes this instance.
+        /// </summary>
+        void Close();
+    }
+}

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/LocalDataStoreSlot.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/LocalDataStoreSlot.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/LocalDataStoreSlot.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/LocalDataStoreSlot.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,115 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="LocalDataStoreSlot.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Support.Threading
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+
+    /// <summary>
+    /// Encapsulates a memory slot to store local data. This class cannot be inherited.
+    /// This currently only supports Threading Slots.
+    /// </summary>
+    public sealed class LocalDataStoreSlot
+    {
+        private static readonly object syncRoot = new object();
+        private static bool[] bitmap;
+
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="LocalDataStoreSlot"/> class.
+        /// </summary>
+        /// <param name="isThreadLocal">if set to <c>true</c> [in thread].</param>
+        internal LocalDataStoreSlot(bool isThreadLocal)
+        {
+            if (!isThreadLocal)
+                throw new NotImplementedException("Only saving to a thread is currently supported");
+
+            this.IsThreadLocal = true;
+
+            lock (syncRoot)
+            {
+                int i;
+                bool[] bitmapCopy = bitmap;
+
+                if (bitmapCopy != null)
+                {
+                    // find a slot that has been closed, assign the index
+                    for (i = 0; i < bitmapCopy.Length; ++i)
+                    {
+                        if (!bitmapCopy[i])
+                        {
+                            this.SlotId = i;
+                            bitmapCopy[i] = true;
+                            return;
+                        }
+                    }
+
+                    // if a slot was not open, expand bitmap 2 places
+                    bool[] newBitmap = new bool[i + 2];
+                    Array.Copy(bitmapCopy, newBitmap, newBitmap.Length);
+                    bitmapCopy = newBitmap;
+                }
+                else
+                {
+                   // create a new bitmap
+                   bitmapCopy = new bool[2];
+                   i = 0;
+                }
+
+                // assign slot
+                bitmapCopy[i] = true;
+                this.SlotId = i;
+                bitmap = bitmapCopy;
+            }
+        }
+
+        /// <summary>
+        /// Finalizes an instance of the <see cref="LocalDataStoreSlot"/> class. 
+        /// Releases unmanaged resources and performs other cleanup operations before the
+        /// <see cref="LocalDataStoreSlot"/> is reclaimed by garbage collection.
+        /// </summary>
+        ~LocalDataStoreSlot()
+        {
+            lock (syncRoot)
+            {
+                ThreadData.FreeLocalSlotData(this.SlotId, this.IsThreadLocal);
+                bitmap[this.SlotId] = false;
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the slot index.
+        /// </summary>
+        /// <value>The index of the slot.</value>
+        internal int SlotId { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is thread local.
+        /// </summary>
+        /// <value>
+        ///     <c>true</c> if this instance is thread local; otherwise, <c>false</c>.
+        /// </value>
+        internal bool IsThreadLocal { get; set; }
+    }
+}
\ No newline at end of file

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadData.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadData.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadData.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadData.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,208 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="ThreadData.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Support.Threading
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+    using System.Threading;
+
+    /// <summary>
+    /// Provides Simulated GetData &amp; SetData functionality for Threads. 
+    /// </summary>
+    /// <remarks>
+    ///    <para>
+    ///     <see cref="ThreadData"/> is meant to provide functionality for storing data
+    ///     in a thread similar to the way the full .NET framework does. 
+    ///    </para>
+    ///    <note>
+    ///     Silverlight does not support the <c>GetData(LocalDataStoreSlot)</c> / 
+    ///     <c>SetData(LocalDataStoreSlot, object)</c> for threads.  The Windows 
+    ///     Mobile 7 version of Silverlight 4 does not even support the 
+    ///     <c>ThreadStatic</c> attribute much less the generic <c>ConcurrentDictionary</c>.  
+    ///    </note>
+    /// </remarks>
+    public static class ThreadData
+    {
+        private static readonly WeakDictionary<Thread, object[]> threadSlots = new WeakDictionary<Thread, object[]>();
+        private static readonly object slotsSyncRoot = new object();
+        private static readonly object hashSyncRoot = new object();
+        private static Dictionary<string, object> hash;
+
+
+
+        /// <summary>
+        /// Gets the hash.
+        /// </summary>
+        /// <value>The hash.</value>
+        private static Dictionary<string, object> Hash
+        {
+            get
+            {
+                lock (hashSyncRoot)
+                {
+                    if (hash == null) 
+                        hash = new Dictionary<string, object>();
+                }
+
+                return hash;
+            }
+        }
+
+        /// <summary>
+        /// Allocates the data slot.
+        /// </summary>
+        /// <returns>
+        /// An instance of <see cref="LocalDataStoreSlot"/>.
+        /// </returns>
+        public static LocalDataStoreSlot AllocateDataSlot()
+        {
+            return new LocalDataStoreSlot(true);
+        }
+
+        /// <summary>
+        /// Allocates the named data slot.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <returns>
+        /// An instance of <see cref="LocalDataStoreSlot"/>.
+        /// </returns>
+        public static LocalDataStoreSlot AllocateNamedDataSlot(string name)
+        {
+            LocalDataStoreSlot slot;
+            lock (hashSyncRoot)
+            {
+                hash = Hash;
+                object value;
+                if (hash.TryGetValue(name, out value))
+                {
+                    throw new ArgumentException("Named data slot already exists", "name");
+                }
+
+                slot = AllocateDataSlot();
+                hash.Add(name, slot);
+            }
+
+            return slot;
+        }
+
+        /// <summary>
+        /// Frees the named data slot.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        public static void FreeNamedDataSlot(string name)
+        {
+            lock (hashSyncRoot)
+            {
+                var store = Hash;
+                object value = null;
+                if (store.TryGetValue(name, out value))
+                {
+                    store.Remove(name);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets the data.
+        /// </summary>
+        /// <param name="slot">The slot.</param>
+        /// <returns>An instance of <see cref="Object"/>.</returns>
+        public static object GetData(LocalDataStoreSlot slot)
+        {
+            if (slot == null)
+                throw new ArgumentNullException("slot");
+
+            object data = null;
+            lock (slotsSyncRoot)
+            {
+                object[] slots = null;
+                threadSlots.TryGetValue(Thread.CurrentThread, out slots);
+
+                if (slots != null && slot.SlotId < slots.Length)
+                    data = slots[slot.SlotId];
+            }
+
+            return data;
+        }
+
+        /// <summary>
+        /// Frees the local slot data.
+        /// </summary>
+        /// <param name="slot">The slot.</param>
+        /// <param name="isThread">if set to <c>true</c> [is thread].</param>
+        public static void FreeLocalSlotData(int slot, bool isThread)
+        {
+            lock (slotsSyncRoot)
+            {
+                object[] slots = null;
+                var current = Thread.CurrentThread;
+                threadSlots.TryGetValue(Thread.CurrentThread, out slots);
+
+                if (slots != null && slot < slots.Length)
+                {
+                    // TODO: write an extension method for arrays to RemoveAt();
+                    object[] copy = new object[slots.Length - 1];
+                    if (slot > 0)
+                        Array.Copy(slots, 0, copy, 0, slot);
+
+                    if (slot < (slots.Length - 1))
+                        Array.Copy(slots, slot + 1, copy, slot, (slots.Length - slot - 1));
+
+                    slots = copy;
+
+                    threadSlots[current] = slots;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Sets the data.
+        /// </summary>
+        /// <param name="slot">The slot.</param>
+        /// <param name="data">The data.</param>
+        public static void SetData(LocalDataStoreSlot slot, object data)
+        {
+            lock (slotsSyncRoot)
+            {
+                object[] slots = null;
+                if (!threadSlots.TryGetValue(Thread.CurrentThread, out slots))
+                    threadSlots[Thread.CurrentThread] = slots = new object[slot.SlotId + 2];
+                else if (slot.SlotId >= slots.Length)
+                {
+                    object[] copy = new object[slot.SlotId + 2];
+                    int cap = slots.Length;
+                    if (copy.Length < cap)
+                        cap = copy.Length;
+
+                    // TODO: create a static method for CopyTo
+                    Array.Copy(slots, slots.GetLowerBound(0), copy, copy.GetLowerBound(0), cap);
+
+                    threadSlots[Thread.CurrentThread] = slots = copy;
+                }
+
+                slots[slot.SlotId] = data;
+            }
+        }
+    }
+}
\ No newline at end of file

Added: incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadLocalOfT.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadLocalOfT.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadLocalOfT.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/src/Lucene.Net/Support/Threading/ThreadLocalOfT.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,221 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="ThreadLocalOfT.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Support.Threading
+{
+    using System;
+
+
+    /// <summary>
+    /// Provides thread-local storage of data.
+    /// </summary>
+    /// <typeparam name="T">The type of data to be stored.</typeparam>
+    public class ThreadLocal<T> : IDisposable
+    {
+        private LocalDataStoreSlot slot;
+        private Exception cachedException;
+        private bool disposed = false;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ThreadLocal&lt;T&gt;"/> class.
+        /// </summary>
+        public ThreadLocal()
+        {
+            this.Factory = () => {
+                return default(T);
+            };
+
+            this.slot = ThreadData.AllocateDataSlot();
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ThreadLocal&lt;T&gt;"/> class.
+        /// </summary>
+        /// <param name="valueFactory">The value factory.</param>
+        public ThreadLocal(Func<T> valueFactory)
+        {
+            this.Factory = valueFactory;
+            this.slot = ThreadData.AllocateDataSlot();
+        }
+
+
+
+        /// <summary>
+        /// Gets or sets the value. 
+        /// </summary>
+        /// <remarks>
+        ///     <para>
+        ///     If the value will attempt to auto initialize using the supplied 
+        ///     <see cref="Func{T}" /> <c>valueFactory</c> or default constructor.
+        ///     If an exception is thrown, it is cached and rethrown each time this 
+        ///     property is attempted to be accessed.
+        ///     </para>
+        /// </remarks>
+        /// <value>The value.</value>
+        /// <exception cref="ObjectDisposedException">
+        ///     Thrown when <see cref="ThreadLocal{T}" /> is already disposed. 
+        /// </exception>
+        /// <exception cref="InvalidOperationException">
+        ///     The initialization function attempted to reference Value recursively.
+        /// </exception>
+        public T Value
+        {
+            get
+            {
+                if (this.disposed)
+                    throw new ObjectDisposedException("This instance is already disposed");
+
+                if (this.cachedException != null)
+                    throw this.cachedException;
+            
+                return this.FetchValue();
+            }
+
+            set
+            {
+                if (this.disposed)
+                    throw new ObjectDisposedException("This instance is already disposed");
+
+                if (this.cachedException != null)
+                    throw this.cachedException;
+
+                var state = this.GetState();
+                state.Initialized = true;
+                state.FetchValue = () => value;
+            }
+        }
+
+
+        /// <summary>
+        /// Gets a value indicating whether the value has been created.
+        /// </summary>
+        /// <value>
+        ///     <c>true</c> if the value is created; otherwise, <c>false</c>.
+        /// </value>
+        /// <exception cref="ObjectDisposedException">
+        ///     Thrown when <see cref="ThreadLocal{T}" /> is already disposed. 
+        /// </exception>
+        public bool IsValueCreated
+        {
+            get
+            {
+                if (this.disposed)
+                    throw new ObjectDisposedException("This instance is already disposed");
+
+                if (this.cachedException != null)
+                    throw this.cachedException;
+
+                return this.IsThreadLocalInitialized;
+            }
+        }
+
+        private Func<T> Factory { get; set; }
+
+        private bool IsThreadLocalInitialized
+        {
+            get
+            {
+                var state = this.GetState();
+                return state.Initialized;
+            }
+        }
+
+        /// <summary>
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+        /// </summary>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            this.disposed = true;
+        }
+
+        /// <summary>
+        /// Releases unmanaged and - optionally - managed resources
+        /// </summary>
+        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                this.Factory = null;
+                ThreadData.FreeLocalSlotData(this.slot.SlotId, this.slot.IsThreadLocal);
+                this.slot = null;
+            }
+        }
+
+        private T FetchValue()
+        {
+            var state = this.GetState();
+            if (state.Initializing)
+                throw new InvalidOperationException("The initialization function attempted to reference Value recursively");
+
+            return state.FetchValue();
+        }
+
+      
+
+        private ValueState GetState()
+        {
+            var state = ThreadData.GetData(this.slot) as ValueState;
+            if (state == null)
+            {
+                state = this.CreateState();
+                ThreadData.SetData(this.slot, state);
+            }
+
+            return state;
+        }
+
+        private ValueState CreateState()
+        {
+            var factory = this.Factory;
+            var state = new ValueState();
+            state.FetchValue = () => {
+                state.Initializing = true;
+                try
+                {
+                    T value = factory();
+                    state.Initializing = false;
+                    state.Initialized = true;
+                    state.FetchValue = () => { return value; };
+
+                    return value;
+                }
+                catch (Exception ex)
+                {
+                    this.cachedException = ex;
+                    throw;
+                }
+            };
+
+            return state;
+        }
+
+        private class ValueState
+        {
+            public bool Initializing { get; set; }
+
+            public bool Initialized { get; set; }
+
+            public Func<T> FetchValue { get; set; }
+        }
+    }
+}
\ No newline at end of file

Modified: incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Lucene.Net.Test.csproj
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Lucene.Net.Test.csproj?rev=1156492&r1=1156491&r2=1156492&view=diff
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Lucene.Net.Test.csproj (original)
+++ incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Lucene.Net.Test.csproj Thu Aug 11 05:36:38 2011
@@ -69,6 +69,8 @@
     <Compile Include="Internal\ReferenceType.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Support\DictionaryExtensionsTest.cs" />
+    <Compile Include="Support\ICloneable.cs" />
+    <Compile Include="Support\ThreadLocalTest.cs" />
     <Compile Include="Support\WeakDictionaryOfTKeyTValueTest.cs" />
     <Compile Include="Support\WeakReferenceOfTTest.cs" />
     <Compile Include="Util\ArrayUtilTest.cs" />

Added: incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ICloneable.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,37 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="ICloneable.cs">
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Lucene.Net.Support
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public interface ICloneable<out T> : ICloneable
+    {
+        new T Clone();
+    }
+}

Added: incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ThreadLocalTest.cs
URL: http://svn.apache.org/viewvc/incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ThreadLocalTest.cs?rev=1156492&view=auto
==============================================================================
--- incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ThreadLocalTest.cs (added)
+++ incubator/lucene.net/branches/Lucene.Net_4e/test/Lucene.Net.Test/Support/ThreadLocalTest.cs Thu Aug 11 05:36:38 2011
@@ -0,0 +1,64 @@
+// -----------------------------------------------------------------------
+// <copyright company="Apache" file="ThreadLocalTest.cs" >
+//
+//      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.
+//
+// </copyright>
+// -----------------------------------------------------------------------
+
+using Lucene.Net.Support.Threading;
+
+namespace Lucene.Net.Support
+{
+#if NUNIT
+    using NUnit.Framework;
+    using Extensions.NUnit;
+#else
+    using Gallio.Framework;
+    using MbUnit.Framework;
+#endif
+    using System;
+    using System.Collections.Generic;
+    using System.Linq;
+    using System.Text;
+    using System.Threading;
+
+
+    [TestFixture]
+    [Category(TestCategories.Unit)]
+    [Parallelizable]
+    public class ThreadLocalTest
+    {
+        private Threading.ThreadLocal<string> local;
+            
+        [Test]
+        public void ProofOfConcept()
+        {
+           int i = 0;
+           this.local = new Threading.ThreadLocal<string>(() => {
+               i++;
+               return i.ToString();
+           });
+
+           Console.WriteLine(this.local.Value);
+           Thread t = new Thread(() => {
+               Console.WriteLine(local.Value);
+           });
+           t.Start();
+           t.Join(2000);
+        }
+    }
+}