I have an ASP.NET application with a lot of dynamic content. The content is the same for all users belonging to a particular client. To reduce the number of database hits required per request, I decided to cache client-level data. I created a static class ("ClientCache") to hold the data.
The most-often used method of the class is by far "GetClientData", which brings back a ClientData object containing all stored data for a particular client. ClientData is loaded lazily, though: if the requested client data is already cached, the caller gets the cached data; otherwise, the data is fetched, added to the cache and then returned to the caller.
Eventually I started getting intermittent crashes in the the GetClientData method on the line where the ClientData object is added to the cache. Here's the method body:
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
ClientData client;
if (_clients.ContainsKey(fk_client))
{
client = _clients[fk_client];
}
else
{
client = new ClientData(fk_client);
_clients.Add(fk_client, client);
}
return client;
}
The exception text is always something like "An object with the same key already exists."
Of course, I tried to write the code so that it just wasn't possible to add a client to the cache if it already existed.
At this point, I'm suspecting that I've got a race condition and the method is being executed twice concurrently, which could explain how the code would crash. What I'm confused about, though, is how the method could be executed twice concurrently at all. As far as I know, any ASP.NET application only ever fields one request at a time (that's why we can use HttpContext.Current).
So, is this bug likely a race condition that will require putting locks in critical sections? Or am I missing a more obvious bug?
If an ASP.NET application only handles one request at a time all ASP.NET sites would be in serious trouble. ASP.NET can process dozens at a time (typically 25 per CPU core).
You should use ASP.NET Cache instead of using your own dictionary to store your object. Operations on the cache are thread-safe.
Note you need to be sure that read operation on the object you store in the cache are threadsafe, unfortunately most .NET class simply state the instance members aren't thread-safe without trying to point any that may be.
Edit:
A comment to this answer states:-
Only atomic operations on the cache are thread safe. If you do something like check
if a key exists and then add it, that is NOT thread safe and can cause the item to
overwritten.
Its worth pointing out that if we feel we need to make such an operation atomic then the cache is probably not the right place for the resource.
I have quite a bit of code that does exactly as the comment describes. However the resource being stored will be the same in both places. Hence if an existing item on rare occasions gets overwritten the only the cost is that one thread unnecessarily generated a resource. The cost of this rare event is much less than the cost of trying to make the operation atomic every time an attempt to access it is made.
This is very easy to fix:
private _clientsLock = new Object();
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null)
lock (_clientsLock)
// Check again because another thread could have created a new
// dictionary in-between the lock and this check
if (_clients == null)
_clients = new Dictionary<Guid, ClientData>();
if (_clients.ContainsKey(fk_client))
// Don't need a lock here UNLESS there are also deletes. If there are
// deletes, then a lock like the one below (in the else) is necessary
return _clients[fk_client];
else
{
ClientData client = new ClientData(fk_client);
lock (_clientsLock)
// Again, check again because another thread could have added this
// this ClientData between the last ContainsKey check and this add
if (!clients.ContainsKey(fk_client))
_clients.Add(fk_client, client);
return client;
}
}
Keep in mind that whenever you mess with static classes, you have the potential for thread synchronization problems. If there's a static class-level list of some kind (in this case, _clients, the Dictionary object), there's DEFINITELY going to be thread synchronization issues to deal with.
Your code really does assume only one thread is in the function at a time.
This just simply won't be true in ASP.NET
If you insist on doing it this way, use a static semaphore to lock the area around this class.
you need thread safe & minimize lock.
see Double-checked locking (http://en.wikipedia.org/wiki/Double-checked_locking)
write simply with TryGetValue.
public static object lockClientsSingleton = new object();
public static ClientData GetClientData(Guid fk_client)
{
if (_clients == null) {
lock( lockClientsSingleton ) {
if( _clients==null ) {
_clients = new Dictionary``();
}
}
}
ClientData client;
if( !_clients.TryGetValue( fk_client, out client ) )
{
lock(_clients)
{
if( !_clients.TryGetValue( fk_client, out client ) )
{
client = new ClientData(fk_client)
_clients.Add( fk_client, client );
}
}
}
return client;
}
Related
I'm just learning nHibernate and have come across what probably is a simple issue to resolve.
Right so I've figured out so far that you can't/shouldn;t nest nHibernate Transactions within each other; in my case I figured this out when scope went to another routine and I started a new Transaction.
So should I be doing the following?
using (ITransaction transaction = session.BeginTransaction())
{
NHibernateMembership mQuery =
session.QueryOver<NHibernateMembership>()
.Where(x => x.Username == username)
.And(x => x.ApplicationName == ApplicationName)
.SingleOrDefault();
if (mQuery != null)
{
mQuery.PasswordQuestion = newPwdQuestion;
mQuery.PasswordAnswer = EncodePassword(newPwdAnswer);
session.Update(mQuery);
transaction.Commit();
passwordQuestionUpdated = true;
}
}
// Assume this is in another routine elsewhere but being
// called right after the first in the same request
using (ITransaction transaction = session.BeginTransaction())
{
NHibernateMembership mQuery =
session.QueryOver<NHibernateMembership>()
.Where(x => x.Username == username)
.And(x => x.ApplicationName == ApplicationName)
.SingleOrDefault();
if (mQuery != null)
{
mQuery.PasswordQuestion = newPwdQuestion;
mQuery.PasswordAnswer = EncodePassword(newPwdAnswer);
session.Update(mQuery);
transaction.Commit();
passwordQuestionUpdated = true;
}
}
Note: I know they are simply a copy, i'm just demonstrating my question
First Question
Is this the way it is MEANT to be done? Transaction per operation?
Second Question
Do I need call transaction.Commit(); each time or only in the last set?
Third Question
Is there a better way, automated or manual, to do this?
Third Question
Can I use session.Transaction.IsActive to determine if the "Current Session" already is part of a transaction - so in this case I can make the "Transaction wrap" in the highest level, let's say the Web Form code, and let routines be called within it and then commit all work at the end. Is this a flawed method?
I really want to hammer this down so I start as I mean to go on; I don;t want to find 1000s of lines of code in that I need to change it all.
Thanks in advance.
EDIT:
Right so I wrote some code to explain my issue exactly.
private void CallingRoutine()
{
using(ISession session = Helper.GetCurrentSession)
{
using (ITransaction transaction = session.BeginTransaction())
{
// RUN nHIbernate QUERY to get an OBJECT-1
// DO WORK on OBJECT
// Need to CALL an EXTERNAL ROUTINE to finish work
ExternalRoutine();
// DO WORK on OBJECT-1 again
// *** At this point ADO exception triggers
}
}
}
private bool ExternalRoutine()
{
using(ISession session = Helper.GetCurrentSession)
{
using (ITransaction transaction = session.BeginTransaction())
{
// RUN nHIbernate QUERY to get an OBJECT-2
// DO WORK on OBJECT
// Determine result
if(Data)
{
return true;
}
return false;
}
}
}
Hopefully this demonstrates the issue. This is how I understood to write the Transactions but notice how the ADO exception occurs. I'm obviously doing something wrong. How am I meant to write these routines?
Take for example if I was to write a helper object for some provider and within each routine exposed there is a nHibernate query run - how wold I write those routines, in regards to Transactions, assuming I knew nothing about the calling function and data - my job is to work with nHibernate effectively and efficiently and return a result.
This is what I assumed by writing the transaction how I did in ExternalRoutine() - to assume that this is the only use of nHibernate and to explicitly make the Transaction.
If possible, I would suggest using System.Transactions.TransactionScope:
using(var trans = new TransactionScope())
using(var session = .. create your session...) {
... do your stuff ...
trans.Complete();
}
The trans.Complete will cause the session to flush and commit the transaction, in addition you can have nested transactionscopes. The only "downside" to this is that it will escalate to DTC if you have multiple connections (or enlisted resources such as MSMQ), but this is not necessarily a downside unless you're using something like MySQL which doesn't play nicely with DTC.
For simple cases I would probably use a transaction scope in the BeginRequest and commit it in EndRequest if there were no errors (or use a filter if u're using ASP.NET MVC), but that really depends a lot on what you're doing - as long as your operations are short (which they should be in a web app), this should be fine. The overhead of creating a session and transaction scope is not that big that it should cause problems for accessing static resources (or resources that don't need the session), unless you're looking at a really high volume / high performance website.
I'm developing an application that uses SQLite as the primary data storage method. I have two processes running for my app using an alternate entry point.
I need to access the same DB from the two different processes but as we all now SQLite is not like a server DB engine, it can only be accessed once at a time.
I wanted to know if there is a way to kind of "lock" the DB when it's being accessed by other process so that if the second process tries to acces the DB at the same time, it would wait until the first process finishes and then try to access it again.
How can this issue be treated?
If you have not already, create a class that abstracts your database access out and store it in the RuntimeStore. From wherever you are going to interface with SQLite, get a reference to that class using the GUID you stored it with (RuntimeStore.get(long)) and synchronize the class however you would normally (member object lock, synchronized methods).
Do NOT just use the Wikipedia style singleton pattern as it is not a true singleton across processes on this platform.
See:
http://www.blackberry.com/developers/docs/5.0.0api/net/rim/device/api/system/RuntimeStore.html
Sample:
class SQLManager {
private static long GUID = 0xa178d3ce564cae69L; // hash of com.stackoverflow.SQLManager
private SQLManager() {
// ctor stuff here
}
public static SQLManager getInstance() {
RuntimeStore rs = RuntimeStore.getRuntimeStore();
SQLManager instance = rs.get(GUID);
if (instance == null) {
instance = new SQLManager();
rs.put(GUID, instance);
}
return instance;
}
}
You're still using the singleton "pattern" per se, but you're storing the object instance in the RuntimeStore on first getInstance call, and subsequently pulling it form the RuntimeStore - using a GUID that you specify.
Apart from blocking other threads reading from the cache what other problems should I be thinking about when locking the cache insert method for a public facing website.
The actual data retrieval and insert into the cache should take no more than 1 second, which we can live with. More importantly i don't want multiple thread potentially all hitting the Insert method at the same time.
The sample code looks something like:
public static readonly object _syncRoot = new object();
if (HttpContext.Current.Cache["key"] == null)
{
lock (_syncRoot)
{
HttpContext.Current.Cache.Insert("key", "DATA", null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
}
}
Response.Write(HttpContext.Current.Cache["key"]);
I expect that you do this to prevent the data retrieval is done more than once, perhaps because the amount of data is high, which might have impact on your server when multiple users trigger that retrieval.
A lock like this just on the Cache.Insert itself is useless, because this method is thread-safe. A lock like this can be useful to prevent double data retrieval, but in that case you should consider using a double checked lock:
var data = HttpContext.Current.Cache["key"];
if (data == null)
{
lock (_syncRoot)
{
// Here, check again for null after the lock.
var data = HttpContext.Current.Cache["key"];
if (data == null)
{
var data = [RETRIEVE DATA]
HttpContext.Current.Cache.Insert("key", data, null, ...);
}
}
return data;
But to your main question. Apart from the risk of locking for a too long period of time, causing large delays in your web application, there is nothing to worry about :-). A lock around a Cache.Insert by itself, will do you no harm.
I think I need some help understanding how static objects persist in an ASP.Net application. I have this scenario:
someFile.cs in a class library:
public delegate void CustomFunction();
public static class A {
public static CustomFunction Func = null;
}
someOtherFile.cs in a class library:
public class Q {
public Q() {
if (A.Func != null) {
A.Func();
}
}
}
Some ASP.Net page:
Page_Init {
A.Func = MyFunc;
}
public void MyFunc() {
System.IO.File.AppendAllText(
"mydebug.txt", DateTime.Now.ToString("hh/mm/ss.fff", Session.SessionID));
}
Page_Load {
Q myQ = new Q();
System.Threading.Thread.Sleep(20000);
mQ = new Q();
}
The idea is that I have a business object which does some operation based on a callback function at the UI level. I set the callback function to a static variable on Page_Init (in the real code version, in the Master page, if that makes a difference). I thought that every execution of the page, no matter what user session it came from, would go through that function's logic but operate on its own set of data. What seems to be happening instead is a concurrency issue.
If I run one user session, then while it is sleeping between calls to that callback function, start another user session, when the first session comes back from sleeping it picks up the session ID from the second user session. How can this be possible?
Output of mydebug.txt:
01/01/01.000 abababababab (session #1, first call)
01/01/05.000 cdcdcdcdcdcd (session #2, first call - started 5 seconds after session #1)
01/01/21.000 cdcdcdcdcdcd (session #1 returns after the wait but has assumed the function context from session #2!!!!!)
01/01/25.000 cdcdcdcdcdcd (session #2 returns with its own context)
Why is the function's context (meaning, its local data, etc.) being overwritten from one user session to another?
Each request to an asp.net site comes in and is processed on it's own thread. But each of those threads belong to the same application. That means anything you mark as static is shared across all requests, and therefore also all sessions and users.
In this case, the MyFunc function that's part of your page class is copied over top of the static Func member in A with every page_init, and so every time any user does a page_init, he's replacing the A.Func used by all requests.
Static data is shared among the entire application domain of your webapp.
In short, it's shared among all the threads serving requests in your webapp, it's not bound to a session/thread/user in any way but to the webapp as a whole.(unlike e.g. php where each request lives in its own isolated environment bar a few knobs provided - such as the session variable.)
I won't try to improve on the other answers' explanations of static members, but do want to point out another way to code around your immediate problem.
As a solution, you could make an instance-oriented version of your class A, store it in a page-level variable, and pass it to Q's constructor on page load:
public class MyPage: Page {
private A2 _a2;
// I've modified A2's constructor here to accept the function
protected Page_Init() { this._a2 = new A2(MyFunc); }
protected Page_Load() {
Q myQ = new Q(this._a2);
// etc..
}
}
In fact, if there's no pressing need to declare A2 earlier, you could just instantiate it when you create your instance of Q in Page_Load.
Edit: to answer the question you raised in other comments, the reason the variables are being shared is that the requests are sharing the same delegate, which has only a single copy of its variables. See Jon Skeet's The Beauty of Closures for more details.
One solution you might consider is using [ThreadStatic].
http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(VS.71).aspx
It will make your statics per thread. There are cavaets however so you should test.
If you want the data to persist only for the current request, use HttpContext.Items:
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.items.aspx
If you want the data to persist for the current user's session (assuming you have session state enabled), use HttpContext.Session:
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.session.aspx
i try to put a lock to a static string object to access to cache,, the lock() block executes in my local,but whenever i deploy it to the server, it locks forever. i write every single step to event log to see the process and lock(object) just causes the deadlock on the server. The command right after lock() is never executed as the i dont see an entry in the event log.
below is the code:
public static string CacheSyncObject = "CacheSync";
public static DataView GetUsers()
{
DataTable dtUsers = null;
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write(String.Format("GetUsers() cache hit: {0}",dtUsers.Rows.Count));
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() cache miss");
lock (CacheSyncObject)
{
Global.eventLogger.Write("GetUsers() locked SyncObject");
if (HttpContext.Current.Cache["dtUsers"] != null)
{
Global.eventLogger.Write("GetUsers() opps, another thread filled the cache, release lock");
return (HttpContext.Current.Cache["dtUsers"] as DataTable).Copy().DefaultView;
}
Global.eventLogger.Write("GetUsers() locked SyncObject"); ==> this is never written to the log, so which means to me that, lock() never executes.
You're locking on a string, which is a generally bad idea in .NET due to interning. The .NET runtime actually stores all identical literal strings only once, so you have little control over who sees a specific string.
I'm not sure how the ASP.NET runtime handles this, but the regular .NET runtime actually uses interning for the entire process which means that interned strings are shared even between different AppDomains. Thus you could be deadlocking between different instances of you method.
What happens if you use:
public static object CacheSyncObject = new object();