Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
StackExchange.Redis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
tsai
StackExchange.Redis
Commits
dbe1c4d0
Commit
dbe1c4d0
authored
Jan 20, 2015
by
Marc Gravell
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #127 from PashaPash/stale-connection-fix
Azure stale connection detection
parents
57f1c3b9
d29f54fb
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
99 additions
and
36 deletions
+99
-36
ConnectingFailDetection.cs
StackExchange.Redis.Tests/ConnectingFailDetection.cs
+35
-9
DebuggingAids.cs
StackExchange.Redis/StackExchange/Redis/DebuggingAids.cs
+20
-0
PhysicalBridge.cs
StackExchange.Redis/StackExchange/Redis/PhysicalBridge.cs
+0
-17
PhysicalConnection.cs
...kExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
+31
-10
SocketManager.Poll.cs
...kExchange.Redis/StackExchange/Redis/SocketManager.Poll.cs
+10
-0
SocketManager.cs
StackExchange.Redis/StackExchange/Redis/SocketManager.cs
+3
-0
No files found.
StackExchange.Redis.Tests/ConnectingFailDetection.cs
View file @
dbe1c4d0
...
...
@@ -8,7 +8,7 @@ namespace StackExchange.Redis.Tests
public
class
ConnectingFailDetection
:
TestBase
{
#if DEBUG
[
Test
Case
]
[
Test
]
public
void
FastNoticesFailOnConnectingSync
()
{
try
...
...
@@ -34,16 +34,15 @@ public void FastNoticesFailOnConnectingSync()
Assert
.
IsTrue
(
muxer
.
IsConnected
);
}
ClearAmbientFailures
();
}
finally
{
SocketManager
.
ConnectCompletionType
=
CompletionType
.
Any
;
ClearAmbientFailures
();
}
}
[
Test
Case
]
[
Test
]
public
void
ConnectsWhenBeginConnectCompletesSynchronously
()
{
try
...
...
@@ -57,16 +56,15 @@ public void ConnectsWhenBeginConnectCompletesSynchronously()
Assert
.
IsTrue
(
muxer
.
IsConnected
);
}
ClearAmbientFailures
();
}
finally
{
SocketManager
.
ConnectCompletionType
=
CompletionType
.
Any
;
ClearAmbientFailures
();
}
}
[
Test
Case
]
[
Test
]
public
void
FastNoticesFailOnConnectingAsync
()
{
try
...
...
@@ -92,15 +90,43 @@ public void FastNoticesFailOnConnectingAsync()
Thread
.
Sleep
(
2000
);
Assert
.
IsTrue
(
muxer
.
IsConnected
);
}
}
finally
{
SocketManager
.
ConnectCompletionType
=
CompletionType
.
Any
;
ClearAmbientFailures
();
}
}
[
Test
]
public
void
ReconnectsOnStaleConnection
()
{
try
{
using
(
var
muxer
=
Create
(
keepAlive
:
1
,
connectTimeout
:
3000
))
{
var
conn
=
muxer
.
GetDatabase
();
conn
.
Ping
();
Assert
.
IsTrue
(
muxer
.
IsConnected
);
PhysicalConnection
.
EmulateStaleConnection
=
true
;
Thread
.
Sleep
(
500
);
Assert
.
IsFalse
(
muxer
.
IsConnected
);
PhysicalConnection
.
EmulateStaleConnection
=
false
;
Thread
.
Sleep
(
1000
);
Assert
.
IsTrue
(
muxer
.
IsConnected
);
}
}
finally
{
SocketManager
.
ConnectCompletionType
=
CompletionType
.
Any
;
PhysicalConnection
.
EmulateStaleConnection
=
false
;
ClearAmbientFailures
();
}
}
#endif
}
}
StackExchange.Redis/StackExchange/Redis/DebuggingAids.cs
View file @
dbe1c4d0
...
...
@@ -260,6 +260,26 @@ bool ISocketCallback.IgnoreConnect
{
get
{
return
multiplexer
.
IgnoreConnect
;
}
}
private
volatile
static
bool
emulateStaleConnection
;
public
static
bool
EmulateStaleConnection
{
get
{
return
emulateStaleConnection
;
}
set
{
emulateStaleConnection
=
value
;
}
}
partial
void
DebugEmulateStaleConnection
(
ref
int
firstUnansweredWrite
)
{
if
(
emulateStaleConnection
)
{
firstUnansweredWrite
=
Environment
.
TickCount
-
100000
;
}
}
}
#endif
...
...
StackExchange.Redis/StackExchange/Redis/PhysicalBridge.cs
View file @
dbe1c4d0
...
...
@@ -679,23 +679,6 @@ private bool ChangeState(State oldState, State newState)
return
result
;
}
private
void
Flush
()
{
var
tmp
=
physical
;
if
(
tmp
!=
null
)
{
try
{
Trace
(
connectionType
+
" flushed"
);
tmp
.
Flush
();
}
catch
(
Exception
ex
)
{
OnInternalError
(
ex
);
}
}
}
private
PhysicalConnection
GetConnection
()
{
if
(
state
==
(
int
)
State
.
Disconnected
)
...
...
StackExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
View file @
dbe1c4d0
...
...
@@ -64,6 +64,7 @@ private static readonly Message
int
ioBufferBytes
=
0
;
int
lastWriteTickCount
,
lastReadTickCount
,
lastBeatTickCount
;
int
firstUnansweredWriteTickCount
;
private
Stream
netStream
,
outStream
;
...
...
@@ -85,6 +86,7 @@ public PhysicalConnection(PhysicalBridge bridge)
public
void
BeginConnect
()
{
Thread
.
VolatileWrite
(
ref
firstUnansweredWriteTickCount
,
0
);
var
endpoint
=
this
.
bridge
.
ServerEndPoint
.
EndPoint
;
multiplexer
.
Trace
(
"Connecting..."
,
physicalName
);
...
...
@@ -164,14 +166,15 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, Exception
if
(
isCurrent
&&
Interlocked
.
CompareExchange
(
ref
failureReported
,
1
,
0
)
==
0
)
{
//try
//{
int
now
=
Environment
.
TickCount
,
lastRead
=
Thread
.
VolatileRead
(
ref
lastReadTickCount
),
lastWrite
=
Thread
.
VolatileRead
(
ref
lastWriteTickCount
),
lastBeat
=
Thread
.
VolatileRead
(
ref
lastBeatTickCount
);
int
unansweredRead
=
Thread
.
VolatileRead
(
ref
firstUnansweredWriteTickCount
);
string
message
=
failureType
+
" on "
+
Format
.
ToString
(
bridge
.
ServerEndPoint
.
EndPoint
)
+
"/"
+
connectionType
+
", input-buffer: "
+
ioBufferBytes
+
", outstanding: "
+
GetSentAwaitingResponseCount
()
+
", last-read: "
+
unchecked
(
now
-
lastRead
)
/
1000
+
"s ago, last-write: "
+
unchecked
(
now
-
lastWrite
)
/
1000
+
"s ago, keep-alive: "
+
bridge
.
ServerEndPoint
.
WriteEverySeconds
+
"s, pending: "
+
", last-read: "
+
unchecked
(
now
-
lastRead
)
/
1000
+
"s ago, last-write: "
+
unchecked
(
now
-
lastWrite
)
/
1000
+
"s ago"
+
", unanswered-write: "
+
unchecked
(
now
-
unansweredRead
)
/
1000
+
"s ago"
+
", keep-alive: "
+
bridge
.
ServerEndPoint
.
WriteEverySeconds
+
"s, pending: "
+
bridge
.
GetPendingCount
()
+
", state: "
+
oldState
+
", last-heartbeat: "
+
(
lastBeat
==
0
?
"never"
:
(
unchecked
(
now
-
lastBeat
)
/
1000
+
"s ago"
))
+
(
bridge
.
IsBeating
?
" (mid-beat)"
:
""
)
+
", last-mbeat: "
+
multiplexer
.
LastHeartbeatSecondsAgo
+
"s ago, global: "
+
ConnectionMultiplexer
.
LastGlobalHeartbeatSecondsAgo
+
"s ago"
;
...
...
@@ -181,13 +184,6 @@ public void RecordConnectionFailed(ConnectionFailureType failureType, Exception
:
new
RedisConnectionException
(
failureType
,
message
,
innerException
);
bridge
.
OnConnectionFailed
(
this
,
failureType
,
ex
);
// throw ex;
//}
//catch (Exception caught)
//{
// bridge.OnConnectionFailed(this, failureType, caught);
//}
}
// cleanup
...
...
@@ -390,6 +386,10 @@ internal void WriteHeader(RedisCommand command, int arguments)
throw
ExceptionFactory
.
CommandDisabled
(
multiplexer
.
IncludeDetailInExceptions
,
command
,
null
,
bridge
.
ServerEndPoint
);
}
outStream
.
WriteByte
((
byte
)
'*'
);
// remember the time of the first write that still not followed by read
Interlocked
.
CompareExchange
(
ref
firstUnansweredWriteTickCount
,
Environment
.
TickCount
,
0
);
WriteRaw
(
outStream
,
arguments
+
1
);
WriteUnified
(
outStream
,
commandBytes
);
}
...
...
@@ -825,6 +825,10 @@ private bool ProcessReadBytes(int bytesRead)
}
Interlocked
.
Exchange
(
ref
lastReadTickCount
,
Environment
.
TickCount
);
// reset unanswered write timestamp
Thread
.
VolatileWrite
(
ref
firstUnansweredWriteTickCount
,
0
);
ioBufferBytes
+=
bytesRead
;
multiplexer
.
Trace
(
"More bytes available: "
+
bytesRead
+
" ("
+
ioBufferBytes
+
")"
,
physicalName
);
int
offset
=
0
,
count
=
ioBufferBytes
;
...
...
@@ -962,5 +966,22 @@ RawResult TryParseResult(byte[] buffer, ref int offset, ref int count)
throw
new
InvalidOperationException
(
"Unexpected response prefix: "
+
(
char
)
resultType
);
}
}
partial
void
DebugEmulateStaleConnection
(
ref
int
firstUnansweredWrite
);
public
void
CheckForStaleConnection
()
{
int
firstUnansweredWrite
;
firstUnansweredWrite
=
Thread
.
VolatileRead
(
ref
firstUnansweredWriteTickCount
);
DebugEmulateStaleConnection
(
ref
firstUnansweredWrite
);
int
now
=
Environment
.
TickCount
;
if
(
firstUnansweredWrite
!=
0
&&
(
now
-
firstUnansweredWrite
)
>
this
.
multiplexer
.
RawConfig
.
SyncTimeout
)
{
this
.
RecordConnectionFailed
(
ConnectionFailureType
.
SocketFailure
,
origin
:
"CheckForStaleConnection"
);
}
}
}
}
StackExchange.Redis/StackExchange/Redis/SocketManager.Poll.cs
View file @
dbe1c4d0
...
...
@@ -178,6 +178,7 @@ internal ManagerState State
private
void
ReadImpl
()
{
List
<
IntPtr
>
dead
=
null
,
active
=
new
List
<
IntPtr
>();
List
<
ISocketCallback
>
activeCallbacks
=
new
List
<
ISocketCallback
>();
IntPtr
[]
readSockets
=
EmptyPointers
,
errorSockets
=
EmptyPointers
;
long
lastHeartbeat
=
Environment
.
TickCount
;
SocketPair
[]
allSocketPairs
=
null
;
...
...
@@ -185,6 +186,7 @@ private void ReadImpl()
{
managerState
=
ManagerState
.
CheckForHeartbeat
;
active
.
Clear
();
activeCallbacks
.
Clear
();
if
(
dead
!=
null
)
dead
.
Clear
();
// this check is actually a pace-maker; sometimes the Timer callback stalls for
...
...
@@ -227,6 +229,7 @@ private void ReadImpl()
if
(
pair
.
Value
.
Socket
.
Connected
)
{
active
.
Add
(
pair
.
Key
);
activeCallbacks
.
Add
(
pair
.
Value
.
Callback
);
}
else
{
...
...
@@ -267,6 +270,13 @@ private void ReadImpl()
ready
=
select
(
0
,
readSockets
,
null
,
errorSockets
,
ref
timeout
);
if
(
ready
<=
0
)
{
if
(
ready
==
0
)
{
foreach
(
var
s
in
activeCallbacks
)
{
s
.
CheckForStaleConnection
();
}
}
continue
;
// -ve typically means a socket was disposed just before; just retry
}
...
...
StackExchange.Redis/StackExchange/Redis/SocketManager.cs
View file @
dbe1c4d0
...
...
@@ -39,6 +39,9 @@ internal partial interface ISocketCallback
/// Indicates that we cannot know whether data is available, and that the consume should commence reading asynchronously
/// </summary>
void
StartReading
();
// check for write-read timeout
void
CheckForStaleConnection
();
}
internal
struct
SocketToken
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment