// ----------------------------------------------------------------------- // // // 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. // // // ----------------------------------------------------------------------- namespace Lucene.Net.Support.Threading { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; /// /// Provides Simulated GetData & SetData functionality for Threads. /// /// /// /// is meant to provide functionality for storing data /// in a thread similar to the way the full .NET framework does. /// /// /// Silverlight does not support the GetData(LocalDataStoreSlot) / /// SetData(LocalDataStoreSlot, object) for threads. The Windows /// Mobile 7 version of Silverlight 4 does not even support the /// ThreadStatic attribute much less the generic ConcurrentDictionary. /// /// public static class ThreadData { private static readonly WeakDictionary threadSlots = new WeakDictionary(); private static readonly object slotsSyncRoot = new object(); private static readonly object hashSyncRoot = new object(); private static Dictionary hash; /// /// Gets the hash. /// /// The hash. private static Dictionary Hash { get { lock (hashSyncRoot) { if (hash == null) hash = new Dictionary(); } return hash; } } /// /// Allocates the data slot. /// /// /// An instance of . /// public static LocalDataStoreSlot AllocateDataSlot() { return new LocalDataStoreSlot(true); } /// /// Allocates the named data slot. /// /// The name. /// /// An instance of . /// 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; } /// /// Frees the named data slot. /// /// The name. public static void FreeNamedDataSlot(string name) { lock (hashSyncRoot) { var store = Hash; object value = null; if (store.TryGetValue(name, out value)) { store.Remove(name); } } } /// /// Gets the data. /// /// The slot. /// An instance of . 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; } /// /// Frees the local slot data. /// /// The slot. /// if set to true [is thread]. /// /// Thrown when is true since the /// storing data outside a thread context is currently not supported. /// public static void FreeLocalSlotData(int slot, bool isThread) { if (!isThread) throw new NotImplementedException("FreeLocalSlotData currently only supports thread contexts"); 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; } } } /// /// Sets the data. /// /// The slot. /// The data. 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; } } } }