You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi,
Please give us a way to implement our custom UpdateTimestampsCache or consider early release of #2129 and #2115. There is a real performance issue.
I made an workaround...
I know that its not a good idea working with readonly fields.
Also I really do not understand why we lock "[MethodImpl(MethodImplOptions.Synchronized)]" retrieve operations with "IsUpdate" and "AreUpToDate" methods.
Below implementation has no lock and no concurrency issue, every second level select operation checks "UpdateTimestamp" from redis at the same time.
I think we need a lock just for "writing cache provider" and somehow key based could be awesome.
publicstaticclassSessionFactoryExtension{publicstaticvoidFixUpdateTimestampsCacheLockIssue(thisISessionFactorysessionFactory){varsettings=typeof(SessionFactoryImpl).GetField("settings",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(sessionFactory)asSettings;varproperties=typeof(SessionFactoryImpl).GetField("properties",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(sessionFactory)asIDictionary<string,string>;varentityPersisters=typeof(SessionFactoryImpl).GetField("entityPersisters",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(sessionFactory)asIDictionary<string,IEntityPersister>;varcacheableSpaces=entityPersisters.Where(x =>x.Value.HasCache).SelectMany(x =>x.Value.PropertySpaces).ToHashSet();varupdateTimestampsCache=newCustomUpdateTimestampsCache(settings,properties,cacheableSpaces);sessionFactory.GetType().GetField("updateTimestampsCache",BindingFlags.Instance|BindingFlags.NonPublic).SetValue(sessionFactory,updateTimestampsCache);varqueryCache=((SessionFactoryImpl)sessionFactory).QueryCache;queryCache.GetType().GetField("_updateTimestampsCache",BindingFlags.Instance|BindingFlags.NonPublic).SetValue(queryCache,updateTimestampsCache);}}publicclassCustomUpdateTimestampsCache:NHibernate.Cache.UpdateTimestampsCache{protectedreadonlyISet<string>CacheableSpaces;protectedreadonlyNHibernate.Cache.CacheBaseUpdateTimestamps;publicCustomUpdateTimestampsCache(Settingssettings,IDictionary<string,string>props,ISet<string>cacheableSpaces):base(settings,props){CacheableSpaces=cacheableSpaces;UpdateTimestamps=typeof(NHibernate.Cache.UpdateTimestampsCache).GetField("_updateTimestamps",BindingFlags.Instance|BindingFlags.NonPublic).GetValue(thisasNHibernate.Cache.UpdateTimestampsCache)asNHibernate.Cache.CacheBase;}
#region Invalidate
publicoverridevoidInvalidate(IReadOnlyCollection<string>spaces){spaces=spaces.Where(x =>CacheableSpaces.Contains(x)).ToList();if(spaces.Count>0){base.Invalidate(spaces);}}publicoverridevoidPreInvalidate(IReadOnlyCollection<string>spaces){spaces=spaces.Where(x =>CacheableSpaces.Contains(x)).ToList();if(spaces.Count>0){base.PreInvalidate(spaces);}}publicoverrideTaskInvalidateAsync(IReadOnlyCollection<string>spaces,CancellationTokencancellationToken){if(cancellationToken.IsCancellationRequested){returnTask.FromCanceled<object>(cancellationToken);}spaces=spaces.Where(x =>CacheableSpaces.Contains(x)).ToList();if(spaces.Count==0){returnTask.CompletedTask;}returnbase.InvalidateAsync(spaces,cancellationToken);}publicoverrideTaskPreInvalidateAsync(IReadOnlyCollection<string>spaces,CancellationTokencancellationToken){if(cancellationToken.IsCancellationRequested){returnTask.FromCanceled<object>(cancellationToken);}spaces=spaces.Where(x =>CacheableSpaces.Contains(x)).ToList();if(spaces.Count==0){returnTask.CompletedTask;}returnbase.PreInvalidateAsync(spaces,cancellationToken);}
#endregion
#region IsUpToDate
publicoverrideboolIsUpToDate(ISet<string>spaces,longtimestamp){if(spaces.Count==0)returntrue;else{varlastUpdates=UpdateTimestamps.GetMany(spaces.ToArray<object>());returnlastUpdates.All(lastUpdate =>!IsOutdated(lastUpdateaslong?,timestamp));}}publicoverridebool[]AreUpToDate(ISet<string>[]spaces,long[]timestamps){if(spaces.Sum(x =>x.Count)==0)returnArray.Empty<bool>();else{varallSpaces=newHashSet<string>();foreach(varspinspaces){allSpaces.UnionWith(sp);}if(allSpaces.Count==0)returnArrayHelper.Fill(true,spaces.Length);varkeys=allSpaces.ToArray<object>();varindex=0;varlastUpdatesBySpace=UpdateTimestamps.GetMany(keys).ToDictionary(u =>keys[index++], u =>uaslong?);varresults=newbool[spaces.Length];for(vari=0;i<spaces.Length;i++){vartimestamp=timestamps[i];results[i]=spaces[i].All(space =>!IsOutdated(lastUpdatesBySpace[space],timestamp));}returnresults;}}publicoverrideasyncTask<bool>IsUpToDateAsync(ISet<string>spaces,longtimestamp,CancellationTokencancellationToken){if(spaces.Count==0)returntrue;elsereturnawaitbase.IsUpToDateAsync(spaces,timestamp,cancellationToken);}publicoverrideasyncTask<bool[]>AreUpToDateAsync(ISet<string>[]spaces,long[]timestamps,CancellationTokencancellationToken){if(spaces?.Sum(x =>x.Count)==0)returnArray.Empty<bool>();elsereturnawaitbase.AreUpToDateAsync(spaces,timestamps,cancellationToken);}
#endregion
privatestaticboolIsOutdated(long?lastUpdate,longtimestamp){if(!lastUpdate.HasValue){//the last update timestamp was lost from the cache//(or there were no updates since startup!)//NOTE: commented out, since users found the "safe" behavior// counter-intuitive when testing, and we couldn't deal// with all the forum posts :-(//updateTimestamps.put( space, new Long( updateTimestamps.nextTimestamp() ) )//result = false; // safer//OR: put a timestamp there, to avoid subsequent expensive// lookups to a distributed cache - this is no good, since// it is non-threadsafe (could hammer effect of an actual// invalidation), and because this is not the way our// preferred distributed caches work (they work by// replication)//updateTimestamps.put( space, new Long(Long.MIN_VALUE) )}else{if(lastUpdate>=timestamp){returntrue;}}returnfalse;}}
The text was updated successfully, but these errors were encountered:
Hi,
Please give us a way to implement our custom UpdateTimestampsCache or consider early release of #2129 and #2115. There is a real performance issue.
I made an workaround...
I know that its not a good idea working with readonly fields.
Also I really do not understand why we lock "[MethodImpl(MethodImplOptions.Synchronized)]" retrieve operations with "IsUpdate" and "AreUpToDate" methods.
Below implementation has no lock and no concurrency issue, every second level select operation checks "UpdateTimestamp" from redis at the same time.
I think we need a lock just for "writing cache provider" and somehow key based could be awesome.
Java Implementation no lock
The text was updated successfully, but these errors were encountered: