Caching in ASP.NET looks like it uses some kind of associative array:
// Insert some data into the cache:
Cache.Insert("TestCache", someValue);
// Retrieve the data like normal:
someValue = Cache.Get("TestCache");
// But, can be done associatively ...
someValue = Cache["TestCache"];
// Also, null checks can be performed to see if cache exists yet:
if(Cache["TestCache"] == null) {
Cache.Insert(PerformComplicatedFunctionThatNeedsCaching());
}
someValue = Cache["TestCache"];
As you can see, performing a null check on the cache object is very useful.
But I would like to implement a cache clear function that can clear cache values
where I don't know the whole key name. As there seems to be an associative
array here, it should be possible (?)
Can anyone help me work out a way of looping through the stored cache keys and
performing simple logic on them? Here's what I'm after:
static void DeleteMatchingCacheKey(string keyName) {
// This foreach implementation doesn't work by the way ...
foreach(Cache as c) {
if(c.Key.Contains(keyName)) {
Cache.Remove(c);
}
}
}
Don't use a foreach loop when removing items from any collection type- the foreach loop relies on using an enumerator which will NOT allow you to remove items from the collection (the enumerator will throw an exception if the collection it is iterating over has items added or removed from it).
Use a simple while to loop over the cache keys instead:
int i = 0;
while (i < Cache.Keys.Length){
if (Cache.Keys(i).Contains(keyName){
Cache.Remove(Cache.Keys(i))
}
else{
i ++;
}
}
An other way to do it in .net core:
var keys = _cache.Get<List<string>>(keyName);
foreach (var key in keys)
{
_cache.Remove(key);
}
Related
My function
public IQueryable<T> getAllPositions<T>(RedisDbs redisDbKey)
{
List<T> positions = new List<T>();
List<string> keys = new List<string>();
foreach (var key in _redisServer.Keys((int)redisDbKey))
{
keys.Add(key.ToString());
}
var sportEventRet = _redis.GetDatabase((int)redisDbKey).JsonMultiGetAsync(keys.ToArray());
foreach (var sportEvent in sportEventRet.Result)
{
var redisValue = (RedisValue)sportEvent;
if(!redisValue.IsNull)
{
var positionEntity = JsonConvert.DeserializeObject<T>(redisValue, jsonSerializerSettings);
positions.Add(positionEntity);
}
}
return positions.AsQueryable();
}
Called as
IQueryable<IPosition> union = redisClient.getAllPositions<Position>(RedisDbs.POSITIONDB);
Where Position is a simple model with just a few simple properties. And RedisDbs is just an enum representing an int for a specific database. With both this application and the redisjson instance running locally on a high performance server, it takes two seconds for this function to return a database with 20k json values in it. This is unacceptable for my specific usecase, I need this to be done in the maximum of 1 second, preferably sub 600ms. Are there any optimizations I could make to this?
I'm convinced the problem is with the KEYS command.
Here is what is written about Keys command in redis.io:
Warning: consider KEYS as a command that should only be used in production environments with extreme care. It may ruin performance
when it is executed against large databases. This command is intended
for debugging and special operations, such as changing your keyspace
layout. Don't use KEYS in your regular application code.
You can save the list of your json keys and then use them in your function instead of calling the keys command.
I am trying to build a dynamic Property Accessor. Want something which is like really fast as close to calling the actually Property. Dont want to go the Reflection route as its very slow. So i opted to using DynamicAssembly and inject IL using ILGenerator. Below is the ILGenerator related code which seems to work
Label nulllabel = getIL.DefineLabel();
Label returnlabel = getIL.DefineLabel();
//_type = targetGetMethod.ReturnType;
if (methods.Count > 0)
{
getIL.DeclareLocal(typeof(object));
getIL.DeclareLocal(typeof(bool));
getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
//(target object)
//Cast to the source type
getIL.Emit(OpCodes.Castclass, this.mTargetType);
//Get the property value
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
getIL.Emit(OpCodes.Stloc_0); //Store it
getIL.Emit(OpCodes.Br_S,returnlabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Stloc_0);
getIL.MarkLabel(returnlabel);
getIL.Emit(OpCodes.Ldloc_0);
}
else
{
getIL.ThrowException(typeof(MissingMethodException));
}
getIL.Emit(OpCodes.Ret);
So above get the first argument which is the object that contains the property. the methods collection contains the nested property if any. for each property i use EmitCall which puts the the value on the stack and then i try to box it. This works like a charm.
The only issue is if you have a property like Order.Instrument.Symbol.Name and assume that Instrument object is null. Then the code will throw an null object exception.
So this what i did, i introduced a null check
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
getIL.Emit(OpCodes.Stloc_0);
getIL.Emit(OpCodes.Ldloc_0);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Ceq);
getIL.Emit(OpCodes.Stloc_1);
getIL.Emit(OpCodes.Ldloc_1);
getIL.Emit(OpCodes.Brtrue_S, nulllabel);
getIL.Emit(OpCodes.Ldloc_0);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
Now this code breaks saying That the object/memory is corrupted etc. So what exactly is wrong with this code. Am i missing something here.
Thanks in Advance.
Previously, if you had consecutive properties P returning string and then Q returning int, you would get something like this:
...
call P // returns string
call Q // requires a string on the stack, returns an int
box
...
Now you have something like this:
...
call P // returns string
store // stores to object
... // load, compare to null, etc.
load // loads an *object*
call Q // requires a *string* on the stack
store // stores to object *without boxing*
...
So I see two clear problems:
You are calling methods in such a way that the target is only known to be an object, not a specific type which has that method.
You are not boxing value types before storing them to a local of type object.
These can be solved by reworking your logic slightly. There are also a few other minor details you could clean up:
Rather than ceq followed by brtrue, just use beq.
There's no point in doing Stloc_1 followed by Ldloc_1 rather than just using the value on the stack since that local isn't used anywhere else.
Incorporating these changes, here's what I'd do:
Type finalType = null;
foreach (var methodInfo in methods)
{
finalType = methodInfo.ReturnType;
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (!finalType.IsValueType)
{
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Beq_S, nulllabel);
}
}
if (finalType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
getIL.Emit(OpCodes.Br_S, returnLabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Pop);
getIL.Emit(OpCodes.Ldnull);
getIL.MarkLabel(returnlabel);
Note that we can get rid of both locals since we now just duplicate the top value on the stack before comparing against null.
I'm a little puzzled over the possible cachedependencies in asp.net, and I'm not sure how to use them.
I would like to add items to the HttpRuntime.Cache in a way, that the elements should invalidate if I change other elements in the cache. The dependencies should be defined by the key.
I want a function like this:
public MyObject LoadFromCache(string itemDescriptor, IEnumerable<string> dependencies)
{
var ret = HttpRuntime.Cache[itemDescriptor] as MyObject;
if (ret == null)
{
ret = LoadFromDataBase(itemDescriptor);
//this is the part I'm not able to figure out. Adding more than one dependency items.
var dep = new CacheDependency();
dependencies.ForEach(o => dep.SomeHowAdd(o));
HttpRuntime.Cache.Add(
itemDescriptor,
ret,
dependencies,
System.Web.Caching.Cache.NoAbsoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
Caching.CacheItemPriority.Normal,
null
);
}
return ret;
}
Help me out on this one.
I didn't know you could do this, but if you look at the CacheDependency constructor here, you can see that the second parameter is an array of cache keys, so that if any of those cached items change, the whole dependency will be changed and your dependent item will be invalidated as well.
So your code would be something like:
String[] cacheKeys = new string[]{"cacheKey1","cacheKey2"};
var dep = New CacheDependency("", cacheKeys);
HttpRuntime.Cache.Add(itemDescriptor, ret, dep ...);
I have two tables without any cascade deleting. I want to delete parent object with all child objects. I do it this way
//get parent object
return _dataContext.Menu.Include("ChildMenu").Include("ParentMenu").Include("Pictures").FirstOrDefault(m => m.MenuId == id);
//then i loop all child objects
var picList = (List<Picture>)menu.Pictures.ToList();
for (int i = 0; i < picList.Count; i++)
{
if (File.Exists(HttpContext.Current.Server.MapPath(picList[i].ImgPath)))
{
File.Delete(HttpContext.Current.Server.MapPath(picList[i].ImgPath));
}
if (File.Exists(HttpContext.Current.Server.MapPath(picList[i].ThumbPath)))
{
File.Delete(HttpContext.Current.Server.MapPath(picList[i].ThumbPath));
}
//**what must i do here?**
//menu.Pictures.Remove(picList[i]);
// DataManager dm = new DataManager();
// dm.Picture.Delete(picList[i].Id);
//menu.Pictures.de
//_dataContext.SaveChanges();
//picList[i] = null;
}
//delete parent object
_dataContext.DeleteObject(_dataContext.Menu.Include("ChildMenu").Include("ParentMenu")
.Include("Pictures").FirstOrDefault(m => m.MenuId == id););
_dataContext.SaveChanges();
It is enough to set the <OnDelete Action="Cascade" /> for the master association end in the CSDL part of the model.
In this case your code will work.
My situation was slightly different, and it took a while to get it right so I thought it worth documenting. I have two related tables, Quote and QuoteExtension:
Quote (Parent, Primary Key QuoteId)
QuoteExtension (Calculated fields for Quote, Primary and Foreign Key QuoteId)
I didn't have to set the OnDelete action to get it to work - but Craig's comment (if I could vote that up more I would!) led me to discover the issue. I was attempting to delete the Quote when QuoteExtension was not loaded. Therefore I found two ways that worked:
var quote = ent.Quote.Include("QuoteExtension").First(q => q.QuoteId == 2311);
ent.DeleteObject(quote);
ent.SaveChanges();
Or:
var quote = ent.Quote.First(q => q.QuoteId == 2311);
if (quote.QuoteExtension != null)
ent.Refresh(RefreshMode.ClientWins, quote.QuoteExtension);
ent.DeleteObject(quote);
ent.SaveChanges();
Interestingly trying to delete QuoteExtension manually didn't work (although it may have if I had included ent.SaveChanges() in the middle - this tends to happen only at the end of a unit of work in this system so I wanted something that didn't rely on this.
Is it possible to clear a Flex flash.utils.Dictionary? I have a Dictionary that I want to clear (remove all elements).
I don't believe there is an explicit clear command.
However, you could write your own that would loop through all the keys and run this
delete dict[key];
Or you can just reassign
dict = new Dictionary()
I think this will work, but I'm not 100% sure, as you're modifying the dictionary while iterating over it:
function clear(d:Dictionary):void {
for(var id:* in d) {
delete d[id];
}
}
However, I generally just create a new Dictionary whenever I need to clear one (though if it's referenced in multiple places then that might not work for you).
To remove all the elements in the Dictionary, loop through each key and use the delete keyword
function clear(dict:Dictionary):void
{
for(var key:Object in dict)
{
delete dict[key];
}
}
If you want to be 100% sure that your deleted keys are garbage collected, you must replace your Dictionary instance with a new Dictionary.
dict = new Dictionary();
I once had a Dictionary object with 3 million Strings as keys. Those Strings would only be garbage collected when the Dictionary instance itself was.
Not only do you need to make sure the key is of type object or * you need to get the keys first then delete them from the dictionary. Otherwise you will end up one key left in the dictionary(the last one).
I remember the above code working before but recently that has changed with the last iteration of flash player.
This code will ensure they are all removed including the last one.
//Clean up the dictionary
var keys:Array = [];
var key:*;
for ( var key:* in dictionary )
keys.push( key );
for each ( var key:* in keys )
delete dictionary[ key ];
Just:
dictionary = new Dictionary()
public static function clear(dict:Dictionary):void {
var key:*
for(key in dict) {
delete dict[key];
}
}
Use the above function as a utility function and you can use it throughout your code base.