Merge pull request #217 from QuickJack/master
[mono.git] / mcs / class / System.Web / System.Web.SessionState_2.0 / RemoteStateServer.cs
1 //
2 // System.Web.SessionState.RemoteStateServer
3 //
4 // Author(s):
5 //  Jackson Harper (jackson@ximian.com)
6 //  Gonzalo Paniagua (gonzalo@ximian.com)
7 //  Marek Habersack (grendello@gmail.com)
8 //
9 // (C) 2003-2006 Novell, Inc (http://www.novell.com)
10 //
11
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32 #if NET_2_0
33 using System;
34 using System.Threading;
35 using System.Web.Caching;
36
37 namespace System.Web.SessionState {
38         class LockableStateServerItem
39         {
40                 public StateServerItem item;
41                 public ReaderWriterLock rwlock;
42
43                 public LockableStateServerItem (StateServerItem item)
44                 {
45                         this.item = item;
46                         this.rwlock = new ReaderWriterLock ();
47                 }
48         }
49         
50         internal class RemoteStateServer : MarshalByRefObject {
51                 const Int32 lockAcquireTimeout = 30000;
52                 Cache cache;
53                 
54                 internal RemoteStateServer ()
55                 {
56                         cache = new Cache ();
57                 }
58
59                 void Insert (string id, LockableStateServerItem item)
60                 {
61                         cache.Insert (id, item, null, Cache.NoAbsoluteExpiration, new TimeSpan (0, item.item.Timeout, 0));
62                 }
63
64                 LockableStateServerItem Retrieve (string id)
65                 {
66                         return cache [id] as LockableStateServerItem;
67                 }
68
69                 internal void CreateUninitializedItem (string id, int timeout)
70                 {
71                         StateServerItem item = new StateServerItem (timeout);
72                         item.Action = SessionStateActions.InitializeItem;
73                         LockableStateServerItem cacheItem = new LockableStateServerItem (item);
74                         Insert (id, cacheItem);
75                 }
76                 
77                 internal StateServerItem GetItem (string id,
78                                                   out bool locked,
79                                                   out TimeSpan lockAge,
80                                                   out object lockId,
81                                                   out SessionStateActions actions,
82                                                   bool exclusive)
83                 {
84                         locked = false;
85                         lockAge = TimeSpan.MinValue;
86                         lockId = Int32.MinValue;
87                         actions = SessionStateActions.None;
88                         
89                         LockableStateServerItem item = Retrieve (id);
90                         if (item == null || item.item.IsAbandoned ())
91                                 return null;
92                         
93                         try {
94                                 item.rwlock.AcquireReaderLock (lockAcquireTimeout);
95                                 if (item.item.Locked) {
96                                         locked = true;
97                                         lockAge = DateTime.UtcNow.Subtract (item.item.LockedTime);
98                                         lockId = item.item.LockId;
99                                         return null;
100                                 }
101
102                                 item.rwlock.ReleaseReaderLock ();
103                                 if (exclusive) {
104                                         item.rwlock.AcquireWriterLock (lockAcquireTimeout);
105                                         item.item.Locked = true;
106                                         item.item.LockedTime = DateTime.UtcNow;
107                                         item.item.LockId++;
108                                         lockId = item.item.LockId;
109                                 }
110                         } catch {
111                                 throw;
112                         } finally {
113                                 if (item.rwlock.IsReaderLockHeld)
114                                         item.rwlock.ReleaseReaderLock ();
115                                 
116                                 if (item.rwlock.IsWriterLockHeld)
117                                         item.rwlock.ReleaseWriterLock ();
118                         }
119                         
120                         actions = item.item.Action;
121                         return item.item;
122                 }
123
124                 internal void Remove (string id, object lockid)
125                 {
126                         cache.Remove (id);
127                 }
128
129                 internal void ResetItemTimeout (string id)
130                 {
131                         LockableStateServerItem item = Retrieve (id);
132                         if (item == null)
133                                 return;
134                         item.item.Touch ();
135                 }
136
137                 internal void ReleaseItemExclusive (string id, object lockId)
138                 {
139                         LockableStateServerItem item = Retrieve (id);
140                         if (item == null || item.item.LockId != (Int32)lockId)
141                                 return;
142                         
143                         try {
144                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
145                                 item.item.Locked = false;
146                         } catch {
147                                 throw;
148                         } finally {
149                                 if (item.rwlock.IsWriterLockHeld)
150                                         item.rwlock.ReleaseWriterLock ();
151                         }
152                 }
153                 
154                 internal void SetAndReleaseItemExclusive (string id, byte [] collection_data, byte [] sobjs_data,
155                                                           object lockId, int timeout, bool newItem)
156                 {
157                         LockableStateServerItem item = Retrieve (id);
158                         bool fresh = false;
159                         
160                         if (newItem || item == null) {
161                                 item = new LockableStateServerItem (new StateServerItem (collection_data, sobjs_data, timeout));
162                                 item.item.LockId = (Int32)lockId;
163                                 fresh = true;
164                         } else {
165                                 if (item.item.LockId != (Int32)lockId)
166                                         return;
167                                 Remove (id, lockId);
168                         }
169
170                         try {
171                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
172                                 item.item.Locked = false;
173                                 if (!fresh) {
174                                         item.item.CollectionData = collection_data;
175                                         item.item.StaticObjectsData = sobjs_data;
176                                 }
177                                 Insert (id, item);
178                         } catch {
179                                 throw;
180                         } finally {
181                                 if (item.rwlock.IsWriterLockHeld)
182                                         item.rwlock.ReleaseWriterLock ();
183                         }
184                 }
185                 
186                 public override object InitializeLifetimeService ()
187                 {
188                         return null; // just in case...
189                 }
190         }
191 }
192 #endif