2008-12-08 Atsushi Enomoto <atsushi@ximian.com>
[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                         Console.WriteLine ("RemoteStateServer.GetItem");
85                         Console.WriteLine ("\tid == {0}", id);
86                         locked = false;
87                         lockAge = TimeSpan.MinValue;
88                         lockId = Int32.MinValue;
89                         actions = SessionStateActions.None;
90                         
91                         LockableStateServerItem item = Retrieve (id);
92                         if (item == null || item.item.IsAbandoned ()) {
93                                 Console.WriteLine ("\tNo item for that id (abandoned == {0})", item != null ? item.item.IsAbandoned() : false);
94                                 return null;
95                         }
96                         
97                         try {
98                                 Console.WriteLine ("\tacquiring reader lock");
99                                 item.rwlock.AcquireReaderLock (lockAcquireTimeout);
100                                 if (item.item.Locked) {
101                                         Console.WriteLine ("\titem is locked");
102                                         locked = true;
103                                         lockAge = DateTime.UtcNow.Subtract (item.item.LockedTime);
104                                         lockId = item.item.LockId;
105                                         return null;
106                                 }
107                                 Console.WriteLine ("\teleasing reader lock");
108                                 item.rwlock.ReleaseReaderLock ();
109                                 if (exclusive) {
110                                         Console.WriteLine ("\tacquiring writer lock");
111                                         item.rwlock.AcquireWriterLock (lockAcquireTimeout);
112                                         Console.WriteLine ("\tlocking the item");
113                                         item.item.Locked = true;
114                                         item.item.LockedTime = DateTime.UtcNow;
115                                         item.item.LockId++;
116                                         Console.WriteLine ("\tnew lock id == {0}", item.item.LockId);
117                                         lockId = item.item.LockId;
118                                 }
119                         } catch {
120                                 throw;
121                         } finally {
122                                 if (item.rwlock.IsReaderLockHeld) {
123                                         Console.WriteLine ("\treleasing reader lock [finally]");
124                                         item.rwlock.ReleaseReaderLock ();
125                                 }
126                                 if (item.rwlock.IsWriterLockHeld) {
127                                         Console.WriteLine ("\treleasing writer lock [finally]");
128                                         item.rwlock.ReleaseWriterLock ();
129                                 }
130                         }
131                         
132                         Console.WriteLine ("\treturning an item");
133                         actions = item.item.Action;
134                         return item.item;
135                 }
136
137                 internal void Remove (string id, object lockid)
138                 {
139                         cache.Remove (id);
140                 }
141
142                 internal void ResetItemTimeout (string id)
143                 {
144                         LockableStateServerItem item = Retrieve (id);
145                         if (item == null)
146                                 return;
147                         item.item.Touch ();
148                 }
149
150                 internal void ReleaseItemExclusive (string id, object lockId)
151                 {
152                         LockableStateServerItem item = Retrieve (id);
153                         if (item == null || item.item.LockId != (Int32)lockId)
154                                 return;
155                         
156                         try {
157                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
158                                 item.item.Locked = false;
159                         } catch {
160                                 throw;
161                         } finally {
162                                 if (item.rwlock.IsWriterLockHeld)
163                                         item.rwlock.ReleaseWriterLock ();
164                         }
165                 }
166                 
167                 internal void SetAndReleaseItemExclusive (string id, byte [] collection_data, byte [] sobjs_data,
168                                                           object lockId, int timeout, bool newItem)
169                 {
170                         Console.WriteLine ("RemoteStateServer.SetAndReleaseItemExclusive");
171                         Console.WriteLine ("\tid == {0}", id);
172                         LockableStateServerItem item = Retrieve (id);
173                         bool fresh = false;
174                         
175                         if (newItem || item == null) {
176                                 Console.WriteLine ("\tnew item");
177                                 item = new LockableStateServerItem (new StateServerItem (collection_data, sobjs_data, timeout));
178                                 item.item.LockId = (Int32)lockId;
179                                 fresh = true;
180                         } else {
181                                 if (item.item.LockId != (Int32)lockId) {
182                                         Console.WriteLine ("\tLockId mismatch ({0} != {1})", item.item.LockId, lockId);
183                                         return;
184                                 }
185                                 Console.WriteLine ("\tremoving from cache");
186                                 Remove (id, lockId);
187                         }
188
189                         try {
190                                 Console.WriteLine ("\tacquiring writer lock");
191                                 item.rwlock.AcquireWriterLock (lockAcquireTimeout);
192                                 item.item.Locked = false;
193                                 if (!fresh) {
194                                         Console.WriteLine ("\tnot fresh = updating data");
195                                         item.item.CollectionData = collection_data;
196                                         item.item.StaticObjectsData = sobjs_data;
197                                 }
198                                 Console.WriteLine ("\tInserting in cache");
199                                 Insert (id, item);
200                         } catch {
201                                 throw;
202                         } finally {
203                                 if (item.rwlock.IsWriterLockHeld) {
204                                         Console.WriteLine ("\treleasing writer lock [finally]");
205                                         item.rwlock.ReleaseWriterLock ();
206                                 }
207                         }
208                 }
209                 
210                 public override object InitializeLifetimeService ()
211                 {
212                         return null; // just in case...
213                 }
214         }
215 }
216 #endif