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 & 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<T>"/> class.
+ /// </summary>
+ public ThreadLocal()
+ {
+ this.Factory = () => {
+ return default(T);
+ };
+
+ this.slot = ThreadData.AllocateDataSlot();
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ThreadLocal<T>"/> 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);
+ }
+ }
+}