views:

215

answers:

5

I'm using ASP.NET's in-process session state store. It locks access to a session exclusively, and which means concurrent requests to the same session are served sequentially.

I want to remove this implicit exclusive lock, so multiple requests per session can be handled concurrently. Of course, I'll be synchronizing access to the session state myself where it's applicable.

I'm using the MSDN documentation of Session State Providers to write my own session state provider, and this SO question pointed me to this example code of implementing this as an HTTP module, but the code looks suspiciously complex just for the purpose of removing the lock.

I should probably eventually implement the session state using ASP.NET's cache, and stop using the built-in session, like Vivek describes in this post, but for now how would I just like to remove the locking.

Any ideas or sample implementations?

+1  A: 

If you are only reading from the session on a given page you could use the Page directive:

<%@ Page EnableSessionState="ReadOnly" %>

to indicate the readonly nature and remove the exclusive write lock which will allow concurrent requests to this page from the same session.

As internally a ReaderWriter lock is used a reader lock will block a writer lock but a reader lock won't block reader lock. Writer lock will block all reader and writer lock.

If you need to both read and write from the same page to the session I think that what you've already found as information is more than sufficient. Just a remark about replacing the Session with Cache: while session is reliable, cache is not meaning that if you put something into the cache you are not guaranteed to retrieve it back. The ASP.NET could decide to evict the cache under some circumstances like low memory pressure so you always need to check if an item exists in the cache before accessing it.

Darin Dimitrov
Thanks Darin. `ReadOnly` vs. `ReadWrite` doesn't address my problem, since both lock the entire session (even if it's just a read lock), and I'd like the ability to lock base on specific session keys. On another note, `InProcSessionStateStore` saves its state in the ASP.NET cache, doesn't it suffer from the same problems as using the cache directly?
orip
@orip, according to [this article](http://msdn.microsoft.com/en-us/magazine/cc163730.aspx): `For pages that do not update session state, you can indicate that read-only access is required. This does not prevent the state data from being fetched, but it results in a read lock being taken on the database, which enables multiple read-only requests to access the session simultaneously and prevents lock contention when multiple requests are made to the server with the same session ID`. So `ReadOnly` will allow concurrent requests to this page.
Darin Dimitrov
They will allow concurrent read requests, but a single write request will block all other requests. In my case, I don't want a write request to block any request which has nothing to do with the session value being updated.
orip
+2  A: 

but the code looks suspiciously complex just for the purpose of removing the lock.

That's because you are thinking of it as a simple lock someone added by chance / or laziness, instead of a factor that was considered in the whole session provider concept. That code looks simple enough for the task at hand / replacing the whole existing provider with your own / and while doing so lock in a different way than it is intended.

I suggest you read a bit more about how the session concept works in asp.net. Consider that the way it was designed involves reading the Whole Session once in the request, and then writing the changed session once.

Also note that while its not your scenario, code might depend on reading separate session values to process something and can write separate values as well / locking individually can get you into the same considerations that can cause a dead lock in databases.

The designed way contrasts with your intent of reading/writing+locking as each separate item is loaded/stored.

Also note that you might be updating the values of an object you retrieved from the session and not setting it back to it, yet the session was updated. As far as I know, the providers write everything in the session back at a certain point in the life cycle, so its not straightforward if you want to separate read vs. write locks at an item level.

Finally, if you are finding a high level of resistance from the framework session providers model and the way you intent to modify it will prevent you from using some features of it (as switching to a diff provider, since those would have the same issue); then I think you should just stay away from it and roll your own for your very specific needs. That's without even using asp.net Cache, since you want to it to be your way, you control the lifetime & locks of what's stored in there.

It just appears to me that you need a different mechanism altogether, so I don't see the benefit of trying to bend the framework to do so. You might reuse some very specific pieces, like generating a session id / and cookie vs. cookie-less, but other than that its a different beast.

eglasius
Thanks eglasius, great points
orip
whoah dude, <b>old overflow!
RPM1984
@RPM1984 there, no more <b> in there, sometimes it takes over :~
eglasius
+1  A: 

You will have to write your own Session State Provider, it is not that hard as it seems. I wouldn't recommend you to use Cache because as Darin said Cache is not reliable enough, for example items there expire and/or removed from cache when there is not enough memory.

In your Session Store Provider you can lock items of session instead of the whole Session state (which suits us in our project) when writing, the essential code for this should be in ISessionStateItemCollection's implementation (in indexer), something like this:

public object this[string name]
{
    get
    {
        //no lock, just returning item (maybe immutable, it depends on how you use it)
    }
    set
    {
        //lock here
    }
}

For our project we have created implementation which stores items in AppFabric Cache and rely on GetAndLock, PutAndUnlock methods of the cache. If you have in-proc Session then you might just need to lock(smthg) {}

Hope this helps.

Kirill Muzykov
Thanks, so I'm not the only crazy one needing this :) Was locking the only reason you wrote your own session state provider?
orip
Yep, got tired of whole request is locked when there's only 2-3 lines where lock is really required :)
Kirill Muzykov
@insomniac - do you have any sample code I could look at?
orip
Kirill Muzykov
What I want to do in the long run is one thing, what I'll do next week is another :) I thought the sample code and documentation from MSDN was confusing, so another example would help me alot :)
orip
+1  A: 

I suggest that you look into moving your sessions into SQL Server Mode. SQL Server sessions is to allow for any number of requests from multiple web servers to share a single session. As far as I know, the SQL Server manages the locking mechanism internally which is tremendously efficient. You also have the added bonus of having a lower in-memory footprint. And you don't need to write an HttpModule to run it.

jojaba
Are you sure the session state isn't locked per-request in SQL Server mode as well?
orip
@orip: Yeah, I always thought that the locking mechanism was managed naturally by SQL Server transactions. But I checked out this page http://msdn.microsoft.com/en-us/library/ms178587.aspx and it *appears* that it's still handled at the web server level.
jojaba
+1  A: 

Not the answer you're looking for, but I think that even if it were possible, changing the way SessionState works in this way is a terrible idea.

Think of the poor guys who will have to maintain your code down the line. The fact that Session serializes requests in this way means ASP.NET developers often don't need to worry too much about thread-safety.

Also if someone adds a third-party component that happens to use Session, it will expect the usual guarantees regarding locks - and you'll suddenly start getting Heisenbugs.

Instead, measure performance and identify specific areas where you need requests to process concurrently - I bet there'll be few of them - and carefully implement your own locking mechanism only for the specific items involved - possibly the solution that you're planning eventually using the ASP.NET cache.

Joe
That's a valid answer, thanks. Any poor guy down the line (probably me :) would have to deal with any type of complexity introduced in order to add features, e.g. the ability to deal with concurrent requests. We already have some (informal) strict policies for using the session, because assuming statelessness keeps things much simpler for us. We actually assumed there wasn't a request lock on the session when we used it, and found out when requests weren't handled concurrently.
orip
Joe - loved your response. Assumptions made by 3rd-party components is a good point, and changing the session's behavior can violate that contract. Thanks.
orip