/// <summary> /// For Inproc only /// </summary> /// <param name="entry"></param> /// <returns></returns> internal static EventCacheItem ConvertToItem(EventCacheEntry entry) { Byte[] objectValue = null; if (entry != null) { EventCacheItem item = new EventCacheItem(); item.CacheItemPriority = (CacheItemPriority)entry.Priority; if (entry.Value != null) { UserBinaryObject ubObject = entry.Value as UserBinaryObject; if (ubObject != null) { objectValue = ubObject.GetFullObject(); item.Value = objectValue; } else { item.Value = entry.Value; } } return(item); } return(null); }
/// <summary> /// For Inproc only /// </summary> /// <param name="entry"></param> /// <returns></returns> internal static EventCacheItem ConvertToItem(EventCacheEntry entry) { Byte[] objectValue = null; if (entry != null) { EventCacheItem item = new EventCacheItem(); item.CacheItemPriority = (CacheItemPriority)entry.Priority; item.CacheItemVersion = new Caching.CacheItemVersion(entry.Version); item.Group = entry.Group; item.ResyncExpiredItems = entry.ReSyncExpiredItems; item.ResyncProviderName = entry.ReSyncProviderCacheItem; item.SubGroup = entry.SubGroup; if (entry.Value != null) { UserBinaryObject ubObject = entry.Value as UserBinaryObject; if (ubObject != null) { objectValue = ubObject.GetFullObject(); item.Value = objectValue; } else { item.Value = entry.Value; } } return(item); } return(null); }
internal static void RemoveAllEventHandlers(Action <EventRegistrationToken> removeMethod) { object instanceKey = GetInstanceKey(removeMethod); System.Collections.Generic.Internal.List <EventRegistrationToken> tokensToRemove = new System.Collections.Generic.Internal.List <EventRegistrationToken>(); // // The whole add/remove code has to be protected by a reader/writer lock // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time // s_eventCacheRWLock.EnterReadLock(); try { EventCacheEntry registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod); if (registrationTokens == null) { // We have no information regarding this particular instance (IUnknown*/type) - just return // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance return; } try { registrationTokens.LockAcquire(); // Copy all tokens to tokensToRemove array which later we'll call removeMethod on // outside this lock foreach (KeyValuePair <object, EventRegistrationTokenListWithCount> item in registrationTokens.registrationTable) { item.Value.CopyTo(tokensToRemove); } // Clear the table - at this point all event handlers are no longer in the cache // but they are not removed yet registrationTokens.registrationTable.Clear(); #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Cache cleared for managed instance = " + instanceKey + "\n"); #endif } finally { registrationTokens.LockRelease(); } } finally { s_eventCacheRWLock.ExitReadLock(); } // // Remove all handlers outside the lock // #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Start removing all events for instance = " + instanceKey + "\n"); #endif CallRemoveMethods(removeMethod, tokensToRemove); #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Finished removing all events for instance = " + instanceKey + "\n"); #endif }
/// <summary> /// For Inproc only /// </summary> /// <param name="entry"></param> /// <returns></returns> internal static EventCacheItem ConvertToItem(EventCacheEntry entry) { Byte[] objectValue = null; if (entry != null) { EventCacheItem item = new EventCacheItem(); item.CacheItemPriority = (CacheItemPriority)entry.Priority; item.CacheItemVersion = new CacheItemVersion(entry.Version); item.Group = entry.Group; item.SubGroup = entry.SubGroup; if (entry.Value != null) { UserBinaryObject ubObject = entry.Value as UserBinaryObject; if (ubObject != null) { objectValue = ubObject.GetFullObject(); item.SetValue(objectValue); } else { item.SetValue(entry.Value); } } item.EntryType = entry.EntryType; return(item); } return(null); }
public static EventCacheEntry CreateCacheEventEntry(ArrayList listeners, CacheEntry cacheEntry, CacheRuntimeContext context) { EventCacheEntry entry = null; EventDataFilter maxFilter = EventDataFilter.None; return(CreateCacheEventEntry(maxFilter, cacheEntry, context)); }
public override void Deserialize(CompactReader reader) { base.Deserialize(reader); lock (this) { Item = EventCacheEntry.ReadItemInfo(reader); OldItem = EventCacheEntry.ReadItemInfo(reader); } }
public override void Serialize(CompactWriter writer) { base.Serialize(writer); lock (this) { EventCacheEntry.WriteItemInfo(writer, Item); EventCacheEntry.WriteItemInfo(writer, OldItem); } }
private static UserBinaryObject getData(EventCacheEntry entry) { object userValue = entry.Value; if (userValue is UserBinaryObject) { userValue = ((UserBinaryObject)userValue).GetFullObject(); } BitSet flag = entry.Flags; object ubObj = _eventDataFormat.GetClientData(userValue, ref flag, LanguageContext.DOTNET); return(ubObj is UserBinaryObject ? (UserBinaryObject)ubObj : (UserBinaryObject)entry.Value); }
// Get the event registration token table for an event. These are indexed by the remove method of the event. private static EventCacheEntry GetEventRegistrationTokenTableInternal(object instance, Action <EventRegistrationToken> removeMethod, bool createIfNotFound) { Debug.Assert(instance != null); Debug.Assert(removeMethod != null); Debug.Assert(s_eventRegistrations != null); EventCacheKey eventCacheKey; eventCacheKey.target = instance; #if false eventCacheKey.method = removeMethod.Method; #endif RuntimeTypeHandle thDummy; eventCacheKey.method = removeMethod.GetFunctionPointer(out thDummy); try { s_eventRegistrationsLock.Acquire(); EventCacheEntry eventCacheEntry; if (!s_eventRegistrations.TryGetValue(eventCacheKey, out eventCacheEntry)) { if (!createIfNotFound) { // No need to create an entry in this case return(null); } #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Adding (" + instance + "," + removeMethod.Method + ") into cache" + "\n"); #endif eventCacheEntry = new EventCacheEntry(); eventCacheEntry.registrationTable = new ConditionalWeakTable <object, EventRegistrationTokenListWithCount>(); eventCacheEntry.tokenListCount = new TokenListCount(eventCacheKey); eventCacheEntry._lock = new Lock(); s_eventRegistrations.Add(eventCacheKey, eventCacheEntry); } return(eventCacheEntry); } finally { s_eventRegistrationsLock.Release(); } }
public static EventCacheEntry CreateCacheEventEntry(ArrayList listeners, CacheEntry cacheEntry) { EventCacheEntry entry = null; EventDataFilter maxFilter = EventDataFilter.None; foreach (CallbackInfo cbInfo in listeners) { if (cbInfo.DataFilter > maxFilter) { maxFilter = cbInfo.DataFilter; } if (maxFilter == EventDataFilter.DataWithMetadata) { break; } } return(CreateCacheEventEntry(maxFilter, cacheEntry)); }
internal static EventCacheItem ConvertToEventItem(EventCacheEntry entry, EventDataFilter?datafilter) { if (datafilter == EventDataFilter.None || entry == null) { return(null); } EventCacheItem cacheItem = new EventCacheItem(); cacheItem.priority = (int)entry.Priority; UserBinaryObject userBinary = entry.Value as UserBinaryObject; if (userBinary == null) { if (entry.Value is CallbackEntry) { userBinary = ((CallbackEntry)entry.Value).Value as UserBinaryObject; } } if (userBinary != null) { cacheItem.value.AddRange(userBinary.DataList); } //Can be optimized if (datafilter != null) { if (datafilter == EventDataFilter.None) { return(null); } else if (datafilter == EventDataFilter.Metadata) { cacheItem.value.Clear(); } } return(cacheItem); }
internal static EventCacheItem ConvertToEventItem(EventCacheEntry entry, EventDataFilter?datafilter) { if (datafilter == EventDataFilter.None || entry == null) { return(null); } EventCacheItem cacheItem = new EventCacheItem(); cacheItem.group = entry.Group; cacheItem.subGroup = entry.SubGroup; cacheItem.itemVersion = entry.Version; cacheItem.priority = (int)entry.Priority; cacheItem.resyncExpiredItems = entry.ReSyncExpiredItems; cacheItem.resyncProviderName = entry.ReSyncProviderCacheItem; UserBinaryObject userBinary = getData(entry); if (userBinary != null) { cacheItem.value.AddRange(userBinary.DataList); } // Can be optimized if (datafilter != null) { if (datafilter == EventDataFilter.None) { return(null); } else if (datafilter == EventDataFilter.Metadata) { cacheItem.value.Clear(); } } return(cacheItem); }
public static EventCacheEntry CreateCacheEventEntry(EventDataFilter?filter, CacheEntry cacheEntry) { if (filter != EventDataFilter.None && cacheEntry != null) { cacheEntry = (CacheEntry)cacheEntry.Clone(); EventCacheEntry entry = new EventCacheEntry(cacheEntry); entry.Flags = cacheEntry.Flag; if (filter == EventDataFilter.DataWithMetadata) { if (cacheEntry.Value is CallbackEntry) { entry.Value = ((CallbackEntry)cacheEntry.Value).Value; } else { entry.Value = cacheEntry.Value; } } return(entry); } return(null); }
internal static EventCacheItem ConvertToEventItem(EventCacheEntry entry, EventDataFilter?datafilter) { if (datafilter == EventDataFilter.None || entry == null) { return(null); } EventCacheItem cacheItem = new EventCacheItem(); cacheItem.group = entry.Group; cacheItem.subGroup = entry.SubGroup; cacheItem.itemVersion = entry.Version; cacheItem.priority = (int)entry.Priority; cacheItem.resyncExpiredItems = entry.ReSyncExpiredItems; cacheItem.resyncProviderName = entry.ReSyncProviderCacheItem; UserBinaryObject userBinary = getData(entry); if (userBinary != null) { cacheItem.value.AddRange(userBinary.DataList); } cacheItem.itemType = Alachisoft.NCache.Util.MiscUtil.EntryTypeToProtoItemType(entry.EntryType); cacheItem.flagMap = entry.Flags.Data; //Can be optimized if (datafilter != null) { if (datafilter == EventDataFilter.None) { return(null); } } return(cacheItem); }
internal static void AddEventHandler <T>(Func <T, EventRegistrationToken> addMethod, Action <EventRegistrationToken> removeMethod, T handler) { // The instanceKey will be IUnknown * of the target object object instanceKey = GetInstanceKey(removeMethod); // Call addMethod outside of RW lock // At this point we don't need to worry about race conditions and we can avoid deadlocks // if addMethod waits on finalizer thread // If we later throw we need to remove the method EventRegistrationToken token = addMethod(handler); bool tokenAdded = false; try { EventRegistrationTokenListWithCount tokens; // // The whole add/remove code has to be protected by a reader/writer lock // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time // s_eventCacheRWLock.EnterReadLock(); try { // Add the method, and make a note of the delegate -> token mapping. EventCacheEntry registrationTokens = GetOrCreateEventRegistrationTokenTable(instanceKey, removeMethod); try { registrationTokens.LockAcquire(); // // We need to find the key that equals to this handler // Suppose we have 3 handlers A, B, C that are equal (refer to the same object and method), // the first handler (let's say A) will be used as the key and holds all the tokens. // We don't need to hold onto B and C, because the COM object itself will keep them alive, // and they won't die anyway unless the COM object dies or they get unsubscribed. // It may appear that it is fine to hold A, B, C, and add them and their corresponding tokens // into registrationTokens table. However, this is very dangerous, because this COM object // may die, but A, B, C might not get collected yet, and another COM object comes into life // with the same IUnknown address, and we subscribe event B. In this case, the right token // will be added into B's token list, but once we unsubscribe B, we might end up removing // the last token in C, and that may lead to crash. // object key = FindEquivalentKeyUnsafe(registrationTokens.registrationTable, handler, out tokens); if (key == null) { tokens = new EventRegistrationTokenListWithCount(registrationTokens.tokenListCount, token); registrationTokens.registrationTable.Add(handler, tokens); } else { tokens.Push(token); } tokenAdded = true; } finally { registrationTokens.LockRelease(); } } finally { s_eventCacheRWLock.ExitReadLock(); } #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event subscribed for instance = " + instanceKey + ", handler = " + handler + "\n"); #endif } catch (Exception) { // If we've already added the token and go there, we don't need to "UNDO" anything if (!tokenAdded) { // Otherwise, "Undo" addMethod if any exception occurs // There is no need to cleanup our data structure as we haven't added the token yet removeMethod(token); } throw; } }
internal static void RemoveEventHandler <T>(Action <EventRegistrationToken> removeMethod, T handler) { object instanceKey = GetInstanceKey(removeMethod); EventRegistrationToken token; // // The whole add/remove code has to be protected by a reader/writer lock // Add/Remove cannot run at the same time with cache cleanup but Add/Remove can run at the same time // s_eventCacheRWLock.EnterReadLock(); try { EventCacheEntry registrationTokens = GetEventRegistrationTokenTableNoCreate(instanceKey, removeMethod); if (registrationTokens == null) { // We have no information regarding this particular instance (IUnknown*/type) - just return // This is necessary to avoid leaking empty dictionary/conditionalWeakTables for this instance #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] no registrationTokens found for instance=" + instanceKey + ", handler= " + handler + "\n"); #endif return; } try { registrationTokens.LockAcquire(); EventRegistrationTokenListWithCount tokens; // Note: // When unsubscribing events, we allow subscribing the event using a different delegate // (but with the same object/method), so we need to find the first delegate that matches // and unsubscribe it // It actually doesn't matter which delegate - as long as it matches // Note that inside TryGetValueWithValueEquality we assumes that any delegate // with the same value equality would have the same hash code object key = FindEquivalentKeyUnsafe(registrationTokens.registrationTable, handler, out tokens); Debug.Assert((key != null && tokens != null) || (key == null && tokens == null), "key and tokens must be both null or non-null"); if (tokens == null) { // Failure to find a registration for a token is not an error - it's simply a no-op. #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] no token list found for instance=" + instanceKey + ", handler= " + handler + "\n"); #endif return; } // Select a registration token to unregister // Note that we need to always get the last token just in case another COM object // is created at the same address before the entry for the old one goes away. // See comments above s_eventRegistrations for more details bool moreItems = tokens.Pop(out token); // If the last token is removed from token list, we need to remove it from the cache // otherwise FindEquivalentKeyUnsafe may found this empty token list even though there could be other // equivalent keys in there with non-0 token list if (!moreItems) { // Remove it from (handler)->(tokens) // NOTE: We should not check whether registrationTokens has 0 entries and remove it from the cache // (just like managed event implementation), because this might race with the finalizer of // EventRegistrationTokenList registrationTokens.registrationTable.Remove(key); } #if false BCLDebug.Log("INTEROP", "[WinRT_Eventing] Event unsubscribed for managed instance = " + instanceKey + ", handler = " + handler + ", token = " + token.m_value + "\n"); #endif } finally { registrationTokens.LockRelease(); } } finally { s_eventCacheRWLock.ExitReadLock(); } // Call removeMethod outside of RW lock // At this point we don't need to worry about race conditions and we can avoid deadlocks // if removeMethod waits on finalizer thread removeMethod(token); }
public override object RemoveSync(object[] keys, ItemRemoveReason reason, bool notify, OperationContext operationContext) { ArrayList depenedentItemList = new ArrayList(); try { Hashtable totalRemovedItems = new Hashtable(); CacheEntry entry = null; IDictionaryEnumerator ide = null; for (int i = 0; i < keys.Length; i++) { try { if (keys[i] != null) { entry = Internal.Remove(keys[i], reason, false, null, LockAccessType.IGNORE_LOCK, operationContext); } if (entry != null) { totalRemovedItems.Add(keys[i], entry); } } catch (Exception ex) { } } ide = totalRemovedItems.GetEnumerator(); while (ide.MoveNext()) { try { entry = ide.Value as CacheEntry; if (entry != null) { if (entry.Value is CallbackEntry) { EventId eventId = null; OperationID opId = operationContext.OperatoinID; CallbackEntry cbEtnry = (CallbackEntry)entry.Value; EventContext eventContext = null; if (cbEtnry != null && cbEtnry.ItemRemoveCallbackListener != null && cbEtnry.ItemRemoveCallbackListener.Count > 0) { //generate event id if (!operationContext.Contains(OperationContextFieldName.EventContext)) //for atomic operations { eventId = EventId.CreateEventId(opId); } else //for bulk { eventId = ((EventContext)operationContext.GetValueByField(OperationContextFieldName.EventContext)).EventID; } eventId.EventType = EventType.ITEM_REMOVED_CALLBACK; eventContext = new EventContext(); eventContext.Add(EventContextFieldName.EventID, eventId); EventCacheEntry eventCacheEntry = CacheHelper.CreateCacheEventEntry(cbEtnry.ItemRemoveCallbackListener, entry); eventContext.Item = eventCacheEntry; eventContext.Add(EventContextFieldName.ItemRemoveCallbackList, cbEtnry.ItemRemoveCallbackListener.Clone()); //Will always reaise the whole entry for old clients NotifyCustomRemoveCallback(ide.Key, entry, reason, true, operationContext, eventContext); } } } } catch (Exception ex) { } } } catch (Exception) { throw; } return(depenedentItemList); }