public void PushPendingChangeOnAnyChildCache(int index, CacheChangeItem cci) { if (cacheChangeItems == null) { cacheChangeItems = new CacheChangeItem[directChildCaches.Count]; } cacheChangeItems[index] = cci; PushPendingChangeOnAnyChildCacheIntern(); }
protected void CheckCascadeRefreshNeeded(CacheDependencyNode node) { CacheChangeItem[] cacheChangeItems = node.cacheChangeItems; if (cacheChangeItems == null) { return; } HashMap <IObjRef, CacheValueAndPrivilege> objRefToCacheValueMap = node.objRefToCacheValueMap; for (int c = cacheChangeItems.Length; c-- > 0;) { CacheChangeItem cci = cacheChangeItems[c]; if (cci == null) { continue; } IList <IObjRef> objectRefsToUpdate = cci.UpdatedObjRefs; IList <Object> objectsToUpdate = cci.UpdatedObjects; for (int a = objectRefsToUpdate.Count; a-- > 0;) { IObjRef objRefToUpdate = objectRefsToUpdate[a]; Object objectToUpdate = objectsToUpdate[a]; CacheValueAndPrivilege cacheValueAndPrivilege = objRefToCacheValueMap.Get(objRefToUpdate); if (cacheValueAndPrivilege == null) { // Current value in childCache is not in our interest here continue; } IEntityMetaData metaData = ((IEntityMetaDataHolder)objectToUpdate).Get__EntityMetaData(); RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length == 0) { continue; } RootCacheValue cacheValue = cacheValueAndPrivilege.cacheValue; IObjRefContainer vhc = (IObjRefContainer)objectToUpdate; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { continue; } // the object which has to be updated has initialized relations. So we have to ensure // that these relations are in the RootCache at the time the target object will be updated. // This is because initialized relations have to remain initialized after update but the relations // may have been updated, too BatchPendingRelations(cacheValue, relationMembers[relationIndex], cacheValue.GetRelation(relationIndex), node); } } } }
protected void ChangeFirstLevelCachesIntern(CacheDependencyNode node, ISet <IObjRef> intermediateDeletes) { List <CacheDependencyNode> childNodes = node.childNodes; for (int a = childNodes.Count; a-- > 0;) { ChangeFirstLevelCachesIntern(childNodes[a], intermediateDeletes); } CacheChangeItem[] cacheChangeItems = node.cacheChangeItems; if (cacheChangeItems == null) { return; } IRootCache parentCache = node.rootCache; // RootCache readlock must be acquired before individual writelock to the child caches due to deadlock reasons Lock parentCacheReadLock = parentCache.ReadLock; parentCacheReadLock.Lock(); try { HashMap <IObjRef, CacheValueAndPrivilege> objRefToCacheValueMap = node.objRefToCacheValueMap; for (int a = cacheChangeItems.Length; a-- > 0;) { CacheChangeItem cci = cacheChangeItems[a]; if (cci == null) { continue; } ChildCache childCache = node.directChildCaches[a]; IList <IObjRef> deletedObjRefs = cci.DeletedObjRefs; IList <Object> objectsToUpdate = cci.UpdatedObjects; IList <IObjRef> objRefsToUpdate = cci.UpdatedObjRefs; IRootCache parent = ((IRootCache)childCache.Parent).CurrentRootCache; Lock writeLock = childCache.WriteLock; writeLock.Lock(); try { if (deletedObjRefs != null && deletedObjRefs.Count > 0) { childCache.Remove(deletedObjRefs); } foreach (IObjRef intermediateDeleteObjRef in intermediateDeletes) { childCache.Remove(intermediateDeleteObjRef); } if (objectsToUpdate != null && objectsToUpdate.Count > 0) { List <IObjRef> objRefsToForget = null; for (int b = objectsToUpdate.Count; b-- > 0;) { Object objectInCache = objectsToUpdate[b]; IObjRef objRefInCache = objRefsToUpdate[b]; // Check if the objects still have their id. They may have lost them concurrently because this // method here may be called from another thread (e.g. UI thread) IEntityMetaData metaData = ((IEntityMetaDataHolder)objectInCache).Get__EntityMetaData(); Object id = metaData.IdMember.GetValue(objectInCache, false); if (id == null) { continue; } CacheValueAndPrivilege cacheValueP = objRefToCacheValueMap.Get(objRefInCache); if (cacheValueP == null) { if (objRefsToForget == null) { objRefsToForget = new List <IObjRef>(); } objRefsToForget.Add(objRefInCache); foreach (PrimitiveMember member in metaData.PrimitiveMembers) { member.SetValue(objectInCache, null); } RelationMember[] relationMembers = metaData.RelationMembers; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { ((IValueHolderContainer)objectInCache).Set__Uninitialized(relationIndex, null); } continue; } if (!parentCache.ApplyValues(objectInCache, childCache, cacheValueP.privilege)) { if (Log.WarnEnabled) { Log.Warn("No entry for object '" + objectInCache + "' found in second level cache"); } } } if (objRefsToForget != null) { childCache.Remove(objRefsToForget); } } } finally { writeLock.Unlock(); } } } finally { parentCacheReadLock.Unlock(); } }
protected void BuildCacheChangeItems(CacheDependencyNode node, List <IObjRef> deletesToSearchInCache, List <IObjRef> changesToSearchInCache, List <IObjRef> changesWithVersion) { List <ChildCache> directChildCaches = node.directChildCaches; for (int flcIndex = directChildCaches.Count; flcIndex-- > 0;) { ChildCache childCache = directChildCaches[flcIndex]; List <IObjRef> objectRefsToDelete = new List <IObjRef>(); List <IObjRef> objectRefsToUpdate = new List <IObjRef>(); List <Object> objectsToUpdate = new List <Object>(); Lock readLock = childCache.ReadLock; readLock.Lock(); try { IList <Object> deletesInCache = childCache.GetObjects(deletesToSearchInCache, CacheDirective.FailEarly | CacheDirective.ReturnMisses); for (int a = deletesToSearchInCache.Count; a-- > 0;) { Object result = deletesInCache[a]; if (result == null) { // not in this cache continue; } objectRefsToDelete.Add(deletesToSearchInCache[a]); } IList <Object> changesInCache = childCache.GetObjects(changesToSearchInCache, CacheDirective.FailEarly | CacheDirective.ReturnMisses); for (int a = changesToSearchInCache.Count; a-- > 0;) { Object result = changesInCache[a]; if (result == null) { // not in this cache continue; } // Attach version to ORI. We can not do this before because then we would have had a // cache miss in the childCache above. We need the version now because our second level cache // has to refresh its entries IObjRef objRefWithVersion = changesWithVersion[a]; node.hardRefObjRefsToLoad.Add(objRefWithVersion); if (result is IDataObject) { IDataObject dataObject = (IDataObject)result; if (dataObject.ToBeUpdated || dataObject.ToBeDeleted) { continue; } } if (objRefWithVersion.Version != null) { IEntityMetaData metaData = ((IEntityMetaDataHolder)result).Get__EntityMetaData(); Object versionInCache = metaData.VersionMember != null?metaData.VersionMember.GetValue(result, false) : null; if (versionInCache != null && ((IComparable)objRefWithVersion.Version).CompareTo(versionInCache) <= 0) { continue; } } objectsToUpdate.Add(result); node.objRefsToLoad.Add(objRefWithVersion); // scanForInitializedObjects(result, alreadyScannedObjects, hardRefOrisToLoad); objectRefsToUpdate.Add(objRefWithVersion); } } finally { readLock.Unlock(); } if (objectRefsToDelete.Count == 0 && objectsToUpdate.Count == 0) { continue; } CacheChangeItem cci = new CacheChangeItem(); cci.Cache = childCache; cci.DeletedObjRefs = objectRefsToDelete; cci.UpdatedObjRefs = objectRefsToUpdate; cci.UpdatedObjects = objectsToUpdate; node.PushPendingChangeOnAnyChildCache(flcIndex, cci); } List <CacheDependencyNode> childNodes = node.childNodes; for (int a = childNodes.Count; a-- > 0;) { BuildCacheChangeItems(childNodes[a], deletesToSearchInCache, changesToSearchInCache, changesWithVersion); } }