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
86949f20
Commit
86949f20
authored
Jun 15, 2018
by
Marc Gravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hot damn, it compiles; this could be very good or very bad
parent
996b182f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
198 additions
and
116 deletions
+198
-116
PhysicalConnection.cs
...kExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
+156
-105
RawResult.cs
StackExchange.Redis/StackExchange/Redis/RawResult.cs
+39
-8
ResultProcessor.cs
StackExchange.Redis/StackExchange/Redis/ResultProcessor.cs
+3
-3
No files found.
StackExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
View file @
86949f20
...
@@ -26,20 +26,20 @@ internal sealed partial class PhysicalConnection : IDisposable, ISocketCallback
...
@@ -26,20 +26,20 @@ internal sealed partial class PhysicalConnection : IDisposable, ISocketCallback
private
static
readonly
byte
[]
Crlf
=
Encoding
.
ASCII
.
GetBytes
(
"\r\n"
);
private
static
readonly
byte
[]
Crlf
=
Encoding
.
ASCII
.
GetBytes
(
"\r\n"
);
private
static
readonly
AsyncCallback
endRead
=
result
=>
//
private static readonly AsyncCallback endRead = result =>
{
//
{
PhysicalConnection
physical
;
//
PhysicalConnection physical;
if
(
result
.
CompletedSynchronously
||
(
physical
=
result
.
AsyncState
as
PhysicalConnection
)
==
null
)
return
;
//
if (result.CompletedSynchronously || (physical = result.AsyncState as PhysicalConnection) == null) return;
try
//
try
{
//
{
physical
.
Multiplexer
.
Trace
(
"Completed asynchronously: processing in callback"
,
physical
.
physicalName
);
//
physical.Multiplexer.Trace("Completed asynchronously: processing in callback", physical.physicalName);
if
(
physical
.
EndReading
(
result
))
physical
.
BeginReading
();
//
if (physical.EndReading(result)) physical.BeginReading();
}
//
}
catch
(
Exception
ex
)
//
catch (Exception ex)
{
//
{
physical
.
RecordConnectionFailed
(
ConnectionFailureType
.
InternalFailure
,
ex
);
//
physical.RecordConnectionFailed(ConnectionFailureType.InternalFailure, ex);
}
//
}
};
//
};
private
static
readonly
byte
[]
message
=
Encoding
.
UTF8
.
GetBytes
(
"message"
),
pmessage
=
Encoding
.
UTF8
.
GetBytes
(
"pmessage"
);
private
static
readonly
byte
[]
message
=
Encoding
.
UTF8
.
GetBytes
(
"message"
),
pmessage
=
Encoding
.
UTF8
.
GetBytes
(
"pmessage"
);
...
@@ -975,7 +975,7 @@ void ISocketCallback.OnHeartbeat()
...
@@ -975,7 +975,7 @@ void ISocketCallback.OnHeartbeat()
partial
void
OnWrapForLogging
(
ref
IDuplexPipe
pipe
,
string
name
);
partial
void
OnWrapForLogging
(
ref
IDuplexPipe
pipe
,
string
name
);
private
async
Task
ReadFromPipe
()
private
async
void
ReadFromPipe
()
// yes it is an async void; deal with it!
{
{
try
try
{
{
...
@@ -989,9 +989,9 @@ private async Task ReadFromPipe()
...
@@ -989,9 +989,9 @@ private async Task ReadFromPipe()
}
}
var
buffer
=
readResult
.
Buffer
;
var
buffer
=
readResult
.
Buffer
;
int
handled
=
ProcessBuffer
(
ref
buffer
);
int
handled
=
ProcessBuffer
(
in
buffer
,
out
var
consumed
);
Multiplexer
.
Trace
(
$"Processed
{
handled
}
messages"
,
physicalName
);
Multiplexer
.
Trace
(
$"Processed
{
handled
}
messages"
,
physicalName
);
input
.
AdvanceTo
(
buffer
.
Start
,
buffer
.
End
);
input
.
AdvanceTo
(
buffer
.
GetPosition
(
consumed
)
,
buffer
.
End
);
}
}
Multiplexer
.
Trace
(
"EOF"
,
physicalName
);
Multiplexer
.
Trace
(
"EOF"
,
physicalName
);
RecordConnectionFailed
(
ConnectionFailureType
.
SocketClosed
);
RecordConnectionFailed
(
ConnectionFailureType
.
SocketClosed
);
...
@@ -1002,27 +1002,27 @@ private async Task ReadFromPipe()
...
@@ -1002,27 +1002,27 @@ private async Task ReadFromPipe()
RecordConnectionFailed
(
ConnectionFailureType
.
InternalFailure
,
ex
);
RecordConnectionFailed
(
ConnectionFailureType
.
InternalFailure
,
ex
);
}
}
}
}
private
int
ProcessBuffer
(
ref
ReadOnlySequence
<
byte
>
buffer
)
private
int
ProcessBuffer
(
in
ReadOnlySequence
<
byte
>
entireBuffer
,
out
long
consumed
)
{
{
int
messageCount
=
0
;
int
messageCount
=
0
;
RawResult
result
;
var
remainingBuffer
=
entireBuffer
;
// create a snapshot so we can trim it after each decoded message
while
(!
buffer
.
IsEmpty
)
// (so that slicing later doesn't require us to keep skipping segments)
consumed
=
0
;
while
(!
remainingBuffer
.
IsEmpty
)
{
{
// we want TryParseResult to be able to mess with these without consequence
var
reader
=
new
BufferReader
(
remainingBuffer
);
var
snapshot
=
buffer
;
var
result
=
TryParseResult
(
in
remainingBuffer
,
ref
reader
)
;
result
=
TryParseResult
(
ref
buffer
);
if
(
result
.
HasValue
)
if
(
result
.
HasValue
)
{
{
messageCount
++;
consumed
+=
reader
.
TotalConsumed
;
remainingBuffer
=
remainingBuffer
.
Slice
(
reader
.
TotalConsumed
);
messageCount
++;
Multiplexer
.
Trace
(
result
.
ToString
(),
physicalName
);
Multiplexer
.
Trace
(
result
.
ToString
(),
physicalName
);
MatchResult
(
result
);
MatchResult
(
result
);
}
}
else
{
buffer
=
snapshot
;
// just in case TryParseResult toyed with it
break
;
}
}
}
return
messageCount
;
return
messageCount
;
}
}
...
@@ -1060,9 +1060,9 @@ bool ISocketCallback.IsDataAvailable
...
@@ -1060,9 +1060,9 @@ bool ISocketCallback.IsDataAvailable
}
}
}
}
private
RawResult
ReadArray
(
byte
[]
buffer
,
ref
int
offset
,
ref
int
count
)
private
RawResult
ReadArray
(
in
ReadOnlySequence
<
byte
>
buffer
,
ref
BufferReader
reader
)
{
{
var
itemCount
=
ReadLineTerminatedString
(
ResultType
.
Integer
,
buffer
,
ref
offset
,
ref
count
);
var
itemCount
=
ReadLineTerminatedString
(
ResultType
.
Integer
,
in
buffer
,
ref
reader
);
if
(
itemCount
.
HasValue
)
if
(
itemCount
.
HasValue
)
{
{
if
(!
itemCount
.
TryGetInt64
(
out
long
i64
))
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid array length"
,
Bridge
.
ServerEndPoint
);
if
(!
itemCount
.
TryGetInt64
(
out
long
i64
))
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid array length"
,
Bridge
.
ServerEndPoint
);
...
@@ -1071,18 +1071,18 @@ private RawResult ReadArray(byte[] buffer, ref int offset, ref int count)
...
@@ -1071,18 +1071,18 @@ private RawResult ReadArray(byte[] buffer, ref int offset, ref int count)
if
(
itemCountActual
<
0
)
if
(
itemCountActual
<
0
)
{
{
//for null response by command like EXEC, RESP array: *-1\r\n
//for null response by command like EXEC, RESP array: *-1\r\n
return
new
RawResult
(
ResultType
.
SimpleString
,
null
,
0
,
0
)
;
return
RawResult
.
NullMultiBulk
;
}
}
else
if
(
itemCountActual
==
0
)
else
if
(
itemCountActual
==
0
)
{
{
//for zero array response by command like SCAN, Resp array: *0\r\n
//for zero array response by command like SCAN, Resp array: *0\r\n
return
RawResult
.
Empty
Array
;
return
RawResult
.
Empty
MultiBulk
;
}
}
var
arr
=
new
RawResult
[
itemCountActual
];
var
arr
=
new
RawResult
[
itemCountActual
];
for
(
int
i
=
0
;
i
<
itemCountActual
;
i
++)
for
(
int
i
=
0
;
i
<
itemCountActual
;
i
++)
{
{
if
(!(
arr
[
i
]
=
TryParseResult
(
buffer
,
ref
offset
,
ref
count
)).
HasValue
)
if
(!(
arr
[
i
]
=
TryParseResult
(
in
buffer
,
ref
reader
)).
HasValue
)
return
RawResult
.
Nil
;
return
RawResult
.
Nil
;
}
}
return
new
RawResult
(
arr
);
return
new
RawResult
(
arr
);
...
@@ -1090,33 +1090,37 @@ private RawResult ReadArray(byte[] buffer, ref int offset, ref int count)
...
@@ -1090,33 +1090,37 @@ private RawResult ReadArray(byte[] buffer, ref int offset, ref int count)
return
RawResult
.
Nil
;
return
RawResult
.
Nil
;
}
}
private
RawResult
ReadBulkString
(
byte
[]
buffer
,
ref
int
offset
,
ref
int
count
)
private
RawResult
ReadBulkString
(
in
ReadOnlySequence
<
byte
>
buffer
,
ref
BufferReader
reader
)
{
{
var
prefix
=
ReadLineTerminatedString
(
ResultType
.
Integer
,
buffer
,
ref
offset
,
ref
count
);
var
prefix
=
ReadLineTerminatedString
(
ResultType
.
Integer
,
in
buffer
,
ref
reader
);
if
(
prefix
.
HasValue
)
if
(
prefix
.
HasValue
)
{
{
if
(!
prefix
.
TryGetInt64
(
out
long
i64
))
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid bulk string length"
,
Bridge
.
ServerEndPoint
);
if
(!
prefix
.
TryGetInt64
(
out
long
i64
))
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid bulk string length"
,
Bridge
.
ServerEndPoint
);
int
bodySize
=
checked
((
int
)
i64
);
int
bodySize
=
checked
((
int
)
i64
);
if
(
bodySize
<
0
)
if
(
bodySize
<
0
)
{
{
return
new
RawResult
(
ResultType
.
BulkString
,
null
,
0
,
0
);
return
new
RawResult
(
ResultType
.
BulkString
,
ReadOnlySequence
<
byte
>.
Empty
,
true
);
}
}
else
if
(
count
>=
bodySize
+
2
)
int
from
=
reader
.
TotalConsumed
;
if
(
reader
.
TryConsume
(
bodySize
))
{
{
if
(
buffer
[
offset
+
bodySize
]
!=
'\r'
||
buffer
[
offset
+
bodySize
+
1
]
!=
'\n'
)
switch
(
reader
.
TryConsumeCRLF
()
)
{
{
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid bulk string terminator"
,
Bridge
.
ServerEndPoint
);
case
ConsumeResult
.
NeedMoreData
:
}
break
;
// see NilResult below
var
result
=
new
RawResult
(
ResultType
.
BulkString
,
buffer
,
offset
,
bodySize
);
case
ConsumeResult
.
Success
:
offset
+=
bodySize
+
2
;
var
payload
=
bodySize
==
0
?
ReadOnlySequence
<
byte
>.
Empty
:
buffer
.
Slice
(
from
,
bodySize
);
count
-=
bodySize
+
2
;
return
new
RawResult
(
ResultType
.
BulkString
,
payload
,
false
);
return
result
;
default
:
throw
ExceptionFactory
.
ConnectionFailure
(
Multiplexer
.
IncludeDetailInExceptions
,
ConnectionFailureType
.
ProtocolFailure
,
"Invalid bulk string terminator"
,
Bridge
.
ServerEndPoint
);
}
}
}
}
}
return
RawResult
.
Nil
;
return
RawResult
.
Nil
;
}
}
private
RawResult
ReadLineTerminatedString
(
ResultType
type
,
ref
ReadOnlySequence
<
byte
>
buffer
,
ref
BufferReader
reader
)
private
RawResult
ReadLineTerminatedString
(
ResultType
type
,
in
ReadOnlySequence
<
byte
>
buffer
,
ref
BufferReader
reader
)
{
{
int
crlf
=
BufferReader
.
FindNextCrLf
(
reader
);
int
crlf
=
BufferReader
.
FindNextCrLf
(
reader
);
...
@@ -1126,48 +1130,38 @@ private RawResult ReadLineTerminatedString(ResultType type, ref ReadOnlySequence
...
@@ -1126,48 +1130,38 @@ private RawResult ReadLineTerminatedString(ResultType type, ref ReadOnlySequence
var
inner
=
buffer
.
Slice
(
reader
.
TotalConsumed
,
crlf
);
var
inner
=
buffer
.
Slice
(
reader
.
TotalConsumed
,
crlf
);
reader
.
Consume
(
crlf
+
2
);
reader
.
Consume
(
crlf
+
2
);
var
result
=
new
RawResult
(
type
,
inner
);
return
new
RawResult
(
type
,
inner
,
false
);
}
}
void
ISocketCallback
.
StartReading
()
void
ISocketCallback
.
StartReading
()
=>
ReadFromPipe
();
{
BeginReading
();
}
private
RawResult
TryParseResult
(
ref
ReadOnlySequence
<
byte
>
buff
er
)
private
RawResult
TryParseResult
(
in
ReadOnlySequence
<
byte
>
buffer
,
ref
BufferReader
read
er
)
{
{
if
(
buffer
.
IsEmpty
)
return
RawResult
.
Nil
;
var
prefix
=
reader
.
ConsumeByte
();
if
(
prefix
<
0
)
return
RawResult
.
Nil
;
// EOF
// so we have *at least* one byte
switch
(
prefix
)
char
resultType
=
(
char
)
buffer
.
First
.
Span
[
0
];
var
reader
=
new
BufferReader
(
buffer
);
reader
.
Consume
(
1
);
RawResult
result
;
switch
(
resultType
)
{
{
case
'+'
:
// simple string
case
'+'
:
// simple string
result
=
ReadLineTerminatedString
(
ResultType
.
SimpleString
,
ref
buffer
,
ref
reader
);
return
ReadLineTerminatedString
(
ResultType
.
SimpleString
,
in
buffer
,
ref
reader
);
break
;
case
'-'
:
// error
case
'-'
:
// error
result
=
ReadLineTerminatedString
(
ResultType
.
Error
,
ref
buffer
,
ref
reader
);
return
ReadLineTerminatedString
(
ResultType
.
Error
,
in
buffer
,
ref
reader
);
break
;
case
':'
:
// integer
case
':'
:
// integer
result
=
ReadLineTerminatedString
(
ResultType
.
Integer
,
ref
buffer
,
ref
reader
);
return
ReadLineTerminatedString
(
ResultType
.
Integer
,
in
buffer
,
ref
reader
);
break
;
case
'$'
:
// bulk string
case
'$'
:
// bulk string
result
=
ReadBulkString
(
buffer
,
ref
reader
);
return
ReadBulkString
(
in
buffer
,
ref
reader
);
break
;
case
'*'
:
// array
case
'*'
:
// array
result
=
ReadArray
(
buffer
,
ref
reader
);
return
ReadArray
(
in
buffer
,
ref
reader
);
break
;
default
:
default
:
throw
new
InvalidOperationException
(
"Unexpected response prefix: "
+
(
char
)
resultType
);
throw
new
InvalidOperationException
(
"Unexpected response prefix: "
+
(
char
)
prefix
);
}
}
buffer
=
buffer
.
Slice
(
reader
.
TotalConsumed
);
return
result
;
}
}
public
enum
ConsumeResult
{
Failure
,
Success
,
NeedMoreData
,
}
ref
struct
BufferReader
ref
struct
BufferReader
{
{
private
ReadOnlySequence
<
byte
>.
Enumerator
_iterator
;
private
ReadOnlySequence
<
byte
>.
Enumerator
_iterator
;
...
@@ -1177,20 +1171,24 @@ private RawResult TryParseResult(ref ReadOnlySequence<byte> buffer)
...
@@ -1177,20 +1171,24 @@ private RawResult TryParseResult(ref ReadOnlySequence<byte> buffer)
public
int
OffsetThisSpan
{
get
;
private
set
;
}
public
int
OffsetThisSpan
{
get
;
private
set
;
}
public
int
TotalConsumed
{
get
;
private
set
;
}
public
int
TotalConsumed
{
get
;
private
set
;
}
public
int
RemainingThisSpan
{
get
;
private
set
;
}
public
int
RemainingThisSpan
{
get
;
private
set
;
}
bool
FetchNext
()
public
bool
IsEmpty
=>
RemainingThisSpan
==
0
;
bool
FetchNextSegment
()
{
{
if
(
_iterator
.
MoveNext
())
do
{
{
if
(!
_iterator
.
MoveNext
())
{
OffsetThisSpan
=
RemainingThisSpan
=
0
;
return
false
;
}
_current
=
_iterator
.
Current
.
Span
;
_current
=
_iterator
.
Current
.
Span
;
OffsetThisSpan
=
0
;
OffsetThisSpan
=
0
;
RemainingThisSpan
=
_current
.
Length
;
RemainingThisSpan
=
_current
.
Length
;
return
true
;
}
while
(
IsEmpty
);
// skip empty segments, they don't help us!
}
else
return
true
;
{
OffsetThisSpan
=
RemainingThisSpan
=
0
;
return
false
;
}
}
}
public
BufferReader
(
ReadOnlySequence
<
byte
>
buffer
)
public
BufferReader
(
ReadOnlySequence
<
byte
>
buffer
)
{
{
...
@@ -1198,9 +1196,64 @@ public BufferReader(ReadOnlySequence<byte> buffer)
...
@@ -1198,9 +1196,64 @@ public BufferReader(ReadOnlySequence<byte> buffer)
_current
=
default
;
_current
=
default
;
OffsetThisSpan
=
RemainingThisSpan
=
TotalConsumed
=
0
;
OffsetThisSpan
=
RemainingThisSpan
=
TotalConsumed
=
0
;
FetchNext
();
FetchNext
Segment
();
}
}
static
readonly
byte
[]
CRLF
=
{
(
byte
)
'\r'
,
(
byte
)
'\n'
};
static
readonly
byte
[]
CRLF
=
{
(
byte
)
'\r'
,
(
byte
)
'\n'
};
/// <summary>
/// Note that in results other than success, no guarantees are made about final state; if you care: snapshot
/// </summary>
public
ConsumeResult
TryConsumeCRLF
()
{
switch
(
RemainingThisSpan
)
{
case
0
:
return
ConsumeResult
.
NeedMoreData
;
case
1
:
if
(
_current
[
OffsetThisSpan
]
!=
(
byte
)
'\r'
)
return
ConsumeResult
.
Failure
;
Consume
(
1
);
if
(
IsEmpty
)
return
ConsumeResult
.
NeedMoreData
;
var
next
=
_current
[
OffsetThisSpan
];
Consume
(
1
);
return
next
==
'\n'
?
ConsumeResult
.
Success
:
ConsumeResult
.
Failure
;
default
:
var
offset
=
OffsetThisSpan
;
var
result
=
_current
[
offset
++]
==
(
byte
)
'\r'
&&
_current
[
offset
]
==
(
byte
)
'\n'
?
ConsumeResult
.
Success
:
ConsumeResult
.
Failure
;
Consume
(
2
);
return
result
;
}
}
public
bool
TryConsume
(
int
count
)
{
if
(
count
<
0
)
throw
new
ArgumentOutOfRangeException
(
nameof
(
count
));
do
{
var
available
=
RemainingThisSpan
;
if
(
count
<=
available
)
{
// consume part of this span
TotalConsumed
+=
count
;
RemainingThisSpan
-=
count
;
OffsetThisSpan
+=
count
;
if
(
count
==
available
)
FetchNextSegment
();
// burned all of it; fetch next
return
true
;
}
// consume all of this span
TotalConsumed
+=
available
;
count
-=
available
;
}
while
(
FetchNextSegment
());
return
false
;
}
public
void
Consume
(
int
count
)
{
if
(!
TryConsume
(
count
))
throw
new
EndOfStreamException
();
}
internal
static
int
FindNextCrLf
(
BufferReader
reader
)
// very deliberately not ref; want snapshot
internal
static
int
FindNextCrLf
(
BufferReader
reader
)
// very deliberately not ref; want snapshot
{
{
// is it in the current span? (we need to handle the offsets differently if so)
// is it in the current span? (we need to handle the offsets differently if so)
...
@@ -1227,30 +1280,28 @@ public BufferReader(ReadOnlySequence<byte> buffer)
...
@@ -1227,30 +1280,28 @@ public BufferReader(ReadOnlySequence<byte> buffer)
totalSkipped
+=
span
.
Length
;
totalSkipped
+=
span
.
Length
;
}
}
}
}
while
(
reader
.
FetchNext
());
while
(
reader
.
FetchNext
Segment
());
return
-
1
;
return
-
1
;
}
}
public
void
Consume
(
int
count
)
//internal static bool HasBytes(BufferReader reader, int count) // very deliberately not ref; want snapshot
//{
// if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
// do
// {
// var available = reader.RemainingThisSpan;
// if (count <= available) return true;
// count -= available;
// } while (reader.FetchNextSegment());
// return false;
//}
public
int
ConsumeByte
()
{
{
if
(
count
<
0
)
throw
new
ArgumentOutOfRangeException
(
nameof
(
count
));
if
(
IsEmpty
)
return
-
1
;
while
(
count
!=
0
)
var
value
=
_current
[
OffsetThisSpan
];
{
Consume
(
1
);
if
(
count
<
RemainingThisSpan
)
return
value
;
{
// consume part of this span
TotalConsumed
+=
count
;
RemainingThisSpan
-=
count
;
OffsetThisSpan
+=
count
;
count
=
0
;
}
else
{
// consume all of this span
TotalConsumed
+=
RemainingThisSpan
;
count
-=
RemainingThisSpan
;
if
(!
FetchNext
())
throw
new
EndOfStreamException
();
}
}
}
}
}
}
...
...
StackExchange.Redis/StackExchange/Redis/RawResult.cs
View file @
86949f20
...
@@ -6,8 +6,9 @@ namespace StackExchange.Redis
...
@@ -6,8 +6,9 @@ namespace StackExchange.Redis
{
{
internal
readonly
struct
RawResult
internal
readonly
struct
RawResult
{
{
public
static
readonly
RawResult
EmptyArray
=
new
RawResult
(
new
RawResult
[
0
]);
internal
static
readonly
RawResult
NullMultiBulk
=
new
RawResult
((
RawResult
[])
null
);
public
static
readonly
RawResult
Nil
=
new
RawResult
();
internal
static
readonly
RawResult
EmptyMultiBulk
=
new
RawResult
(
new
RawResult
[
0
]);
internal
static
readonly
RawResult
Nil
=
new
RawResult
();
private
readonly
ReadOnlySequence
<
byte
>
_payload
;
private
readonly
ReadOnlySequence
<
byte
>
_payload
;
...
@@ -36,8 +37,9 @@ public RawResult(ResultType resultType, ReadOnlySequence<byte> payload, bool isN
...
@@ -36,8 +37,9 @@ public RawResult(ResultType resultType, ReadOnlySequence<byte> payload, bool isN
public
RawResult
(
RawResult
[]
arr
)
public
RawResult
(
RawResult
[]
arr
)
{
{
_type
=
ResultType
.
MultiBulk
;
_type
=
ResultType
.
MultiBulk
;
if
(
arr
==
null
)
_type
|=
NullResultTypeBit
;
_payload
=
default
;
_payload
=
default
;
_subArray
=
arr
??
throw
new
ArgumentNullException
(
nameof
(
arr
))
;
_subArray
=
arr
;
}
}
public
bool
HasValue
=>
Type
!=
ResultType
.
None
;
public
bool
HasValue
=>
Type
!=
ResultType
.
None
;
...
@@ -298,7 +300,7 @@ internal string[] GetItemsAsStrings()
...
@@ -298,7 +300,7 @@ internal string[] GetItemsAsStrings()
internal
RawResult
[]
GetItemsAsRawResults
()
=>
GetItems
();
internal
RawResult
[]
GetItemsAsRawResults
()
=>
GetItems
();
internal
string
GetString
()
internal
unsafe
string
GetString
()
{
{
if
(
IsNull
)
return
null
;
if
(
IsNull
)
return
null
;
if
(
_payload
.
IsEmpty
)
return
""
;
if
(
_payload
.
IsEmpty
)
return
""
;
...
@@ -306,15 +308,44 @@ internal string GetString()
...
@@ -306,15 +308,44 @@ internal string GetString()
if
(
_payload
.
IsSingleSegment
)
if
(
_payload
.
IsSingleSegment
)
{
{
var
span
=
_payload
.
First
.
Span
;
var
span
=
_payload
.
First
.
Span
;
unsafe
fixed
(
byte
*
ptr
=
&
span
[
0
])
{
{
fixed
(
byte
*
ptr
=
&
span
[
0
])
return
Encoding
.
UTF8
.
GetString
(
ptr
,
span
.
Length
);
}
}
var
decoder
=
Encoding
.
UTF8
.
GetDecoder
();
int
charCount
=
0
;
foreach
(
var
segment
in
_payload
)
{
var
span
=
segment
.
Span
;
if
(
span
.
IsEmpty
)
continue
;
fixed
(
byte
*
bPtr
=
&
span
[
0
])
{
charCount
+=
decoder
.
GetCharCount
(
bPtr
,
span
.
Length
,
false
);
}
}
decoder
.
Reset
();
string
s
=
new
string
((
char
)
0
,
charCount
);
fixed
(
char
*
sPtr
=
s
)
{
char
*
cPtr
=
sPtr
;
foreach
(
var
segment
in
_payload
)
{
var
span
=
segment
.
Span
;
if
(
span
.
IsEmpty
)
continue
;
fixed
(
byte
*
bPtr
=
&
span
[
0
])
{
{
return
Encoding
.
UTF8
.
GetString
(
ptr
,
span
.
Length
);
var
written
=
decoder
.
GetChars
(
bPtr
,
span
.
Length
,
cPtr
,
charCount
,
false
);
cPtr
+=
written
;
charCount
-=
written
;
}
}
}
}
}
}
return
Encoding
.
UTF8
.
GetString
(
blob
,
offset
,
count
)
;
return
s
;
}
}
internal
bool
TryGetDouble
(
out
double
val
)
internal
bool
TryGetDouble
(
out
double
val
)
...
...
StackExchange.Redis/StackExchange/Redis/ResultProcessor.cs
View file @
86949f20
...
@@ -1233,7 +1233,7 @@ private static GeoRadiusResult Parse(GeoRadiusOptions options, RawResult item)
...
@@ -1233,7 +1233,7 @@ private static GeoRadiusResult Parse(GeoRadiusOptions options, RawResult item)
return
new
GeoRadiusResult
(
item
.
AsRedisValue
(),
null
,
null
,
null
);
return
new
GeoRadiusResult
(
item
.
AsRedisValue
(),
null
,
null
,
null
);
}
}
// If WITHCOORD, WITHDIST or WITHHASH options are specified, the command returns an array of arrays, where each sub-array represents a single item.
// If WITHCOORD, WITHDIST or WITHHASH options are specified, the command returns an array of arrays, where each sub-array represents a single item.
var
arr
=
item
.
Get
ArrayOfRawResult
s
();
var
arr
=
item
.
Get
Item
s
();
int
index
=
0
;
int
index
=
0
;
// the first item in the sub-array is always the name of the returned item.
// the first item in the sub-array is always the name of the returned item.
...
@@ -1251,7 +1251,7 @@ private static GeoRadiusResult Parse(GeoRadiusOptions options, RawResult item)
...
@@ -1251,7 +1251,7 @@ private static GeoRadiusResult Parse(GeoRadiusOptions options, RawResult item)
if
((
options
&
GeoRadiusOptions
.
WithGeoHash
)
!=
0
)
{
hash
=
(
long
?)
arr
[
index
++].
AsRedisValue
();
}
if
((
options
&
GeoRadiusOptions
.
WithGeoHash
)
!=
0
)
{
hash
=
(
long
?)
arr
[
index
++].
AsRedisValue
();
}
if
((
options
&
GeoRadiusOptions
.
WithCoordinates
)
!=
0
)
if
((
options
&
GeoRadiusOptions
.
WithCoordinates
)
!=
0
)
{
{
var
coords
=
arr
[
index
++].
Get
ArrayOfRawResult
s
();
var
coords
=
arr
[
index
++].
Get
Item
s
();
double
longitude
=
(
double
)
coords
[
0
].
AsRedisValue
(),
latitude
=
(
double
)
coords
[
1
].
AsRedisValue
();
double
longitude
=
(
double
)
coords
[
0
].
AsRedisValue
(),
latitude
=
(
double
)
coords
[
1
].
AsRedisValue
();
position
=
new
GeoPosition
(
longitude
,
latitude
);
position
=
new
GeoPosition
(
longitude
,
latitude
);
}
}
...
@@ -1451,7 +1451,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
...
@@ -1451,7 +1451,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
switch
(
result
.
Type
)
switch
(
result
.
Type
)
{
{
case
ResultType
.
MultiBulk
:
case
ResultType
.
MultiBulk
:
var
arrayOfArrays
=
result
.
Get
ArrayOfRawResult
s
();
var
arrayOfArrays
=
result
.
Get
Item
s
();
var
returnArray
=
new
KeyValuePair
<
string
,
string
>[
arrayOfArrays
.
Length
][];
var
returnArray
=
new
KeyValuePair
<
string
,
string
>[
arrayOfArrays
.
Length
][];
...
...
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