3
3
using System . Web . SessionState ;
4
4
using System . Web ;
5
5
using Couchbase . Core ;
6
+ using Couchbase . IO ;
6
7
7
8
namespace Couchbase . AspNet . SessionState
8
9
{
10
+ /// <summary>
11
+ /// A <see cref="SessionStateStoreProviderBase"/> implementation which uses Couchbase Server as the backing store.
12
+ /// </summary>
9
13
public class CouchbaseSessionStateProvider : SessionStateStoreProviderBase
10
14
{
11
15
private ICluster _cluster ;
12
16
private IBucket _bucket ;
13
17
private static bool _exclusiveAccess ;
18
+ private int _maxRetryCount = 5 ;
19
+
20
+ /// <summary>
21
+ /// Required default ctor for ASP.NET
22
+ /// </summary>
23
+ public CouchbaseSessionStateProvider ( )
24
+ {
25
+ }
26
+
27
+ /// <summary>
28
+ /// For unit testing only.
29
+ /// </summary>
30
+ /// <param name="cluster"></param>
31
+ /// <param name="bucket"></param>
32
+ public CouchbaseSessionStateProvider (
33
+ ICluster cluster ,
34
+ IBucket bucket )
35
+ {
36
+ _cluster = cluster ;
37
+ _bucket = bucket ;
38
+ }
14
39
15
40
/// <summary>
16
41
/// Defines the prefix for header data in the Couchbase bucket. Must be unique to ensure it does not conflict with
@@ -28,7 +53,6 @@ public class CouchbaseSessionStateProvider : SessionStateStoreProviderBase
28
53
( System . Web . Hosting . HostingEnvironment . SiteName ?? string . Empty ) . Replace ( " " , "-" ) + "+" +
29
54
System . Web . Hosting . HostingEnvironment . ApplicationVirtualPath + "data-" ;
30
55
31
-
32
56
/// <summary>
33
57
/// Function to initialize the provider
34
58
/// </summary>
@@ -39,11 +63,16 @@ public override void Initialize(string name, NameValueCollection config)
39
63
// Initialize the base class
40
64
base . Initialize ( name , config ) ;
41
65
42
- // Create our Cluster based off the CouchbaseConfigSection
43
- _cluster = ProviderHelper . GetCluster ( name , config ) ;
44
-
45
- // Create the bucket based off the name provided in the
46
- _bucket = ProviderHelper . GetBucket ( name , config , _cluster ) ;
66
+ if ( _cluster == null )
67
+ {
68
+ // Create our Cluster based off the CouchbaseConfigSection
69
+ _cluster = ProviderHelper . GetCluster ( name , config ) ;
70
+ }
71
+ if ( _bucket == null )
72
+ {
73
+ // Create the bucket based off the name provided in the
74
+ _bucket = ProviderHelper . GetBucket ( name , config , _cluster ) ;
75
+ }
47
76
48
77
// By default use exclusive session access. But allow it to be overridden in the config file
49
78
var exclusive = ProviderHelper . GetAndRemove ( config , "exclusiveAccess" , false ) ?? "true" ;
@@ -60,6 +89,12 @@ public override void Initialize(string name, NameValueCollection config)
60
89
{
61
90
DataPrefix = dataPrefix ;
62
91
}
92
+ var maxRetryCount = ProviderHelper . GetAndRemove ( config , "maxRetryCount" , false ) ;
93
+ var temp = 0 ;
94
+ if ( int . TryParse ( maxRetryCount , out temp ) )
95
+ {
96
+ _maxRetryCount = temp ;
97
+ }
63
98
64
99
// Make sure no extra attributes are included
65
100
ProviderHelper . CheckForUnknownAttributes ( config ) ;
@@ -130,7 +165,8 @@ public override void CreateUninitializedItem(HttpContext context, string id, int
130
165
Timeout = timeout
131
166
} ;
132
167
133
- e . SaveAll ( _bucket , id , false ) ;
168
+ bool keyNotFound ;
169
+ e . SaveAll ( _bucket , id , false , out keyNotFound ) ;
134
170
}
135
171
136
172
/// <summary>
@@ -227,14 +263,19 @@ public static SessionStateItem GetSessionStoreItem(
227
263
e . LockTime = DateTime . UtcNow ;
228
264
e . Flag = SessionStateActions . None ;
229
265
266
+ ResponseStatus status ;
230
267
// try to update the item in the store
231
- if ( e . SaveHeader ( bucket , id , _exclusiveAccess ) )
268
+ if ( e . SaveHeader ( bucket , id , _exclusiveAccess , out status ) )
232
269
{
233
270
locked = true ;
234
271
lockId = e . LockId ;
235
272
236
273
return e ;
237
274
}
275
+ if ( status == ResponseStatus . KeyNotFound )
276
+ {
277
+ break ;
278
+ }
238
279
239
280
// it has been modified between we loaded and tried to save it
240
281
e = SessionStateItem . Load ( bucket , id , false ) ;
@@ -267,6 +308,8 @@ public override void SetAndReleaseItemExclusive(
267
308
object lockId ,
268
309
bool newItem )
269
310
{
311
+ bool keyNotFound ;
312
+ var retries = 0 ;
270
313
SessionStateItem e ;
271
314
do {
272
315
if ( ! newItem )
@@ -298,7 +341,7 @@ public override void SetAndReleaseItemExclusive(
298
341
e . LockTime = DateTime . MinValue ;
299
342
300
343
// Attempt to save with CAS and loop around if it fails
301
- } while ( ! e . SaveAll ( _bucket , id , _exclusiveAccess && ! newItem ) ) ;
344
+ } while ( ! e . SaveAll ( _bucket , id , _exclusiveAccess && ! newItem , out keyNotFound ) && retries ++ < _maxRetryCount && ! keyNotFound ) ;
302
345
}
303
346
304
347
/// <summary>
@@ -312,6 +355,8 @@ public override void ReleaseItemExclusive(
312
355
string id ,
313
356
object lockId )
314
357
{
358
+ ResponseStatus status ;
359
+ var retries = 0 ;
315
360
var tmp = ( ulong ) lockId ;
316
361
SessionStateItem e ;
317
362
do {
@@ -327,7 +372,7 @@ public override void ReleaseItemExclusive(
327
372
// Attempt to clear the lock for this item and loop around until we succeed
328
373
e . LockId = 0 ;
329
374
e . LockTime = DateTime . MinValue ;
330
- } while ( ! e . SaveHeader ( _bucket , id , _exclusiveAccess ) ) ;
375
+ } while ( ! e . SaveHeader ( _bucket , id , _exclusiveAccess , out status ) && retries < _maxRetryCount && status != ResponseStatus . KeyNotFound ) ;
331
376
}
332
377
333
378
/// <summary>
@@ -361,6 +406,8 @@ public override void ResetItemTimeout(
361
406
HttpContext context ,
362
407
string id )
363
408
{
409
+ bool keyNotFound ;
410
+ var retries = 0 ;
364
411
SessionStateItem e ;
365
412
do {
366
413
// Load the item with CAS
@@ -371,7 +418,7 @@ public override void ResetItemTimeout(
371
418
}
372
419
373
420
// Try to save with CAS, and loop around until we succeed
374
- } while ( ! e . SaveAll ( _bucket , id , _exclusiveAccess ) ) ;
421
+ } while ( ! e . SaveAll ( _bucket , id , _exclusiveAccess , out keyNotFound ) && retries < _maxRetryCount && ! keyNotFound ) ;
375
422
}
376
423
377
424
/// <summary>
0 commit comments