[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Data Caching, SyncLock Applications, Expiry and HELP!

Posted on 2006-05-27
4
Medium Priority
?
354 Views
Last Modified: 2008-02-07
Hi,

In way over my head.... I have a asp.net 2 web application that has some problems - most using cached datasets/tables. I have implemented data caching that loads some very frequently-used tables into cache. Essentially, the web app serves a number of domains and needs different settings/content for each - and much of that content is contained in the cached datatables/datasets but the datasets are not big but can be accessed 20-30 times in the life of a page request for a complex page.

The data caching was simply set up to hold the datasets/tables in cache and then expire them after 30 minutes - so I could reload any new settings/content. When in production under load the app had serious problems - I think related to race conditions when items in the cache expired - so I added created a LoadCache class and added a SyncLock on an object around the cache insert procedures to stop instances/threads trying to add stuff at the same time. But the problems remain it seems because multiple threads are trying to READ the cache object, then find the data doesn't exist (because it expired), then requests a load of the cache (and finds the lock on it) while another thread has already issued the request to load it. I am not sure this is what is actually happening as it really hard to trace/debug. In any event I suddenly get errors galore as threads somehow can't see the cached data.

Here is summary of what I've done:

class cacheloader
  private shared cachelock as new object

  public sub loadcache(tblname as string)
      synclock(cachelock)
      '...get the table from db
        httpcontext.current.cache.insert(tbl) 'the table is actually in its own dataset
       end synclock
  end sub
end class

then elsewhere I have:


dim ds as new dataset
ds=ctype(httpcontext.current.cache("mytable"), dataset)
if isnothing(ds) then
      dim c as new cacheloader
      c.loadcache("mytable")
      ds=ctype(httpcontext.current.cache("mytable"), dataset)
end if

I suspect that there is an issue with the scope of the cacheloader cachelock object (surely this is private to each instance of cahceloader?) and thus not a functioning lock? Should cacheloader be declared globally somewhere?

All that aside, I have come to the conclusion that the really-frequently accessed data needs to not expire in cache cuz I just can't seem to get it to work properly under load and keep everything synched. There is a good possibility that I haven't created and used the LoadCache class properly

Now to the question: if I load the datatable/sets into Application (i.e. as an Application("mydataset")) then when does this get refreshed? I have multiple worker processes configured - do each of these use the same Application object? If I load the dataset in Application during Application_Start, will each worker process run the Application_Start and have it's own copy of Application, or is it global/shared to all the worker processes. I ask this as I have the worker processes set in IIS to restart every 1/2 hour - and that would be an OK interval to reload this data.

Is there any worker process/instance specific way of loading this data so as each worker process stops/restarts, it gets its own (current) copy of data and loads it?

Sorry for the rambling...  What I thought was a good idea (using expiring cache for extremely frequently accessed data - sometimes 10+ times per page request) is not as easy as it would appear from MS docs. In fact, in no example of data caching I have seen from MS does they even mention the need to SyncLock to avoid multiple threads modifying the cache.

And... before anyone suggest sql data dependencies: I don't want the complexity of this. If I can't get simple expiring caches to work, I can't imagine having to try to debug sql data dependencies....

Thanks for any help.

0
Comment
Question by:ctudorprice
  • 2
  • 2
4 Comments
 
LVL 26

Accepted Solution

by:
Rejojohny earned 2000 total points
ID: 16775336
application object does not have refresh or expires as cache objects ..

I also see that u have this code to add data into cache
httpcontext.current.cache.insert(tbl)

i hope u know that cache has other parameters like priority, expiry, callback functions etc which can used for solving all ur problems .. pls read MSDN for all the features .. there is no need for locks etc .. if u feel that ur object in cache has to last for 30 minutes, u can set the priority to max and so it will never get removed till 30 minutes .. sliding expiration also helps for similar situation .. callback function can also be used so that when the item gets removed from cache, u can check the reason y it was removed and take approriate action ...

Rejo
0
 

Author Comment

by:ctudorprice
ID: 16775676
thanks - I ended up (glutton for punishment) totally rewriting the caching and am currently volume testing it. (I did have the other params for cache.insert).

I rewrote to use datatables in the cache instead of datatables in datasets because I thought that maybe datasets were adding a lot of overhead and were unnecessary. Also took your advice and moved the important tables to max priority. Put an Application.Lock AND a SyncLock around the cache insert - just to be double sure, and changed the scope of the object I was sync locking on to global - and generally simplified everything.

I'm still not clear on what the best approach to managing synchronization on the cache object is though - Application.Lock or SyncLock?

0
 

Author Comment

by:ctudorprice
ID: 16784301
Just so I don't confuse anyone as much as I was confused....

There was/is no need for synclock or application.lock as the tables I was storing in cache are/were read-only - doh. SyncLock is only required to ensure that the same threads don't update read/write items in cache. I had a procedure that I called to load the table into cache and that did that but when the cache ran out of memory and cache memory was full, they were immediately removed. So, I changed that to a function that inserted the table into cache and returned the table it retrieved - rather than subsequently trying to read the inserted table from cache. This enables my app to always get the table from the caching insert function, even if it is immediately removed from the cache... I'm sure there are more elegant ways to do this but my app now works under heavy load.

Here's a stripped-down outline of what I ended up doing:

dbcache.getcachedtable("mytable", CacheItemPriority.Normal)
'or
dbcache.getcachedtable("mytable", CacheItemPriority.NotRemovable)

class dbachce
public shared function getcachedtable(tablename as string, cachepriority As Caching.CacheItemPriority = CacheItemPriority.Normal) as datatable
Dim dt As DataTable = Nothing
If HttpContext.Current.Cache(tablename) Is Nothing Then
      Dim ld As New dbcacheloader
            dt = ld.loadcachetable(tablename,cachepriority)
Else
            dt = CType(HttpContext.Current.Cache(tablename), DataTable)
End If
end function
end class

class dbcacheloader
public function loadcachetable(tbl_command as string="", cachepriority As Caching.CacheItemPriority = CacheItemPriority.Normal)

Dim cacheexpires As DateTime
If HttpContext.Current.Application("cacheexpires") = Nothing Or HttpContext.Current.Application("cacheexpires") <= DateTime.Now Then
      cacheexpires = DateTime.Now.AddMinutes(30)
      HttpContext.Current.Application("cacheexpires") = cacheexpires
Else
      cacheexpires = HttpContext.Current.Application("cacheexpires")
End If

gettable = DB.GetTable("select * from " & tbl_command) 'class to open connection, retrieve datatable

'inserts the table into cache
HttpContext.Current.Cache.Insert(tbl_command, gettable, Nothing, cacheexpires, TimeSpan.Zero, cachepriority, Nothing)
'returns the table that was retrieved to the caller, just in case item was cleared immediately from cache due to low memory
Return gettable
end function
end class

Thanks Rejojohny for clearing my head. I was looking for a complicated solution to a simple problem.
0
 
LVL 26

Expert Comment

by:Rejojohny
ID: 16787281
you are welcome, glad to be of help .. :-)

Rejo
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Lots of people ask this question on how to extend the “MembershipProvider” to make use of custom authentication like using existing database or make use of some other way of authentication. Many blogs show you how to extend the membership provider c…
One of the pain points with developing AJAX, JavaScript, JQuery, and other client-side behaviors is that JavaScript doesn’t allow for cross domain request for pulling content. For example, JavaScript code on www.johnchapman.name could not pull conte…
this video summaries big data hadoop online training demo (http://onlineitguru.com/big-data-hadoop-online-training-placement.html) , and covers basics in big data hadoop .
Screencast - Getting to Know the Pipeline
Suggested Courses

873 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question