Merge pull request #5714 from alexischr/update_bockbuild
[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 using System;
33 using System.Threading;
34 using System.Web.Caching;
35
36 namespace System.Web.SessionState {
37         class LockableStateServerItem
38         {
39                 public StateServerItem item;
40                 public ReaderWriterLock rwlock;
41
42                 public LockableStateServerItem (StateServerItem item)
43                 {
44                         this.item = item;
45                         this.rwlock = new ReaderWriterLock ();
46                 }
47         }
48         
49         internal class RemoteStateServer : MarshalByRefObject {
50                 const Int32 lockAcquireTimeout = 30000;
51                 Cache cache;
52                 
53                 internal RemoteStateServer ()
54                 {
55                         cache = new Cache ();
56                 }
57
58                 void Insert (string id, LockableStateServerItem item)
59                 {
60                         cache.Insert (id, item, null, Cache.NoAbsoluteExpiration, new TimeSpan (0, item.item.Timeout, 0));
61                 }
62
63                 LockableStateServerItem Retrieve (string id)
64                 {
65                         return cache [id] as LockableStateServerItem;
66                 }
67
68                 internal void CreateUninitializedItem (string id, int timeout)
69                 {
70                         StateServerItem item = new StateServerItem (timeout);
71                         item.Action = SessionStateActions.InitializeItem;
72                         LockableStateServerItem cacheItem = new LockableStateServerItem (item);
73                         Insert (id, cacheItem);
74                 }
75                 
76                 internal StateServerItem GetItem (string id,
77                                                   out bool locked,
78                                                   out TimeSpan lockAge,
79                                                   out object lockId,
80                                                   out SessionStateActions actions,
81                                                   bool exclusive)
82                 {
83                         locked = false;
84                         lockAge = TimeSpan.MinValue;
85                         lockId = Int32.MinValue;
86                         actions = SessionStateActions.None;
87                         
88                         LockableStateServerItem item = Retrieve (id);
89                         if (item == null || item.item.IsAbandoned ())
90                                 return null;
91                         
92                         try {
93                                 item.rwlock.AcquireReaderLock (lockAcquireTimeout);
94                                 if (item.item.Locked) {
95                                         locked = true;
96                                         lockAge = DateTime.UtcNow.Subtract (item.item.LockedTime);
97                                         lockId = item.item.LockId;
98                                         return null;
99                                 }
100
101                                 item.rwlock.ReleaseReaderLock ();
102                                 if (exclusive) {
103                                         item.rwlock.AcquireWriterLock (lockAcquireTimeout);
104                                         item.item.Locked = true;
105                                         item.item.LockedTime = DateTime.UtcNow;
106                                         item.item.LockId++;
107                                         lockId = item.item.LockId;
108                                 }
109                         } catch {
110                                 throw;
111                         } finally {
112                                 if (item.rwlock.IsReaderLockHeld)
113                                         item.rwlock.ReleaseReaderLock ();
114                                 
115                                 if (item.rwlock.IsWriterLockHeld)
116                                         item.rwlock.ReleaseWriterLock ();
117                         }
118                         
119                         actions = item.item.Action;
120                         return item.item;
121                 }
122
123                 internal void Remove (string id, object lockid)
124                 {
125                         cache.Remove (id);
126                 }
127
128                 internal void ResetItemTimeout (string id)
129                 {
130                         LockableStateServerItem item = Retrieve (id);
131                         if (item == null)
132                                 return;
133                         item.item.Touch ();
134                 }
135
136                 internal void ReleaseItemExclusive (string id, object lockId)
137                 {
138                         LockableStateServerItem item = Retrieve (id);
139                         if (item == null || item.item.LockId != (Int32)lockId)
140                                 return;
141                         
142                         try {
143                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
144                                 item.item.Locked = false;
145                         } catch {
146                                 throw;
147                         } finally {
148                                 if (item.rwlock.IsWriterLockHeld)
149                                         item.rwlock.ReleaseWriterLock ();
150                         }
151                 }
152                 
153                 internal void SetAndReleaseItemExclusive (string id, byte [] collection_data, byte [] sobjs_data,
154                                                           object lockId, int timeout, bool newItem)
155                 {
156                         LockableStateServerItem item = Retrieve (id);
157                         bool fresh = false;
158                         
159                         if (newItem || item == null) {
160                                 item = new LockableStateServerItem (new StateServerItem (collection_data, sobjs_data, timeout));
161                                 item.item.LockId = (Int32)lockId;
162                                 fresh = true;
163                         } else {
164                                 if (item.item.LockId != (Int32)lockId)
165                                         return;
166                                 Remove (id, lockId);
167                         }
168
169                         try {
170                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
171                                 item.item.Locked = false;
172                                 if (!fresh) {
173                                         item.item.CollectionData = collection_data;
174                                         item.item.StaticObjectsData = sobjs_data;
175                                 }
176                                 Insert (id, item);
177                         } catch {
178                                 throw;
179                         } finally {
180                                 if (item.rwlock.IsWriterLockHeld)
181                                         item.rwlock.ReleaseWriterLock ();
182                         }
183                 }
184                 
185                 public override object InitializeLifetimeService ()
186                 {
187                         return null; // just in case...
188                 }
189         }
190 }