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
0cc1d8f9
Commit
0cc1d8f9
authored
Oct 27, 2014
by
Marc Gravell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Explicit control of pattern mode;l fixes issue #114
parent
b6e4bd65
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
112 additions
and
21 deletions
+112
-21
PubSub.cs
StackExchange.Redis.Tests/PubSub.cs
+42
-0
PhysicalConnection.cs
...kExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
+3
-3
RawResult.cs
StackExchange.Redis/StackExchange/Redis/RawResult.cs
+3
-3
RedisChannel.cs
StackExchange.Redis/StackExchange/Redis/RedisChannel.cs
+52
-8
RedisServer.cs
StackExchange.Redis/StackExchange/Redis/RedisServer.cs
+2
-2
RedisSubscriber.cs
StackExchange.Redis/StackExchange/Redis/RedisSubscriber.cs
+3
-3
ResultProcessor.cs
StackExchange.Redis/StackExchange/Redis/ResultProcessor.cs
+7
-2
No files found.
StackExchange.Redis.Tests/PubSub.cs
View file @
0cc1d8f9
...
...
@@ -11,6 +11,48 @@ namespace StackExchange.Redis.Tests
public
class
PubSub
:
TestBase
{
[
Test
]
public
void
ExplicitPublishMode
()
{
using
(
var
mx
=
Create
(
channelPrefix
:
"foo:"
))
{
var
pub
=
mx
.
GetSubscriber
();
int
a
=
0
,
b
=
0
,
c
=
0
,
d
=
0
;
pub
.
Subscribe
(
new
RedisChannel
(
"*bcd"
,
RedisChannel
.
PatternMode
.
Literal
),
(
x
,
y
)
=>
{
Interlocked
.
Increment
(
ref
a
);
});
pub
.
Subscribe
(
new
RedisChannel
(
"a*cd"
,
RedisChannel
.
PatternMode
.
Pattern
),
(
x
,
y
)
=>
{
Interlocked
.
Increment
(
ref
b
);
});
pub
.
Subscribe
(
new
RedisChannel
(
"ab*d"
,
RedisChannel
.
PatternMode
.
Auto
),
(
x
,
y
)
=>
{
Interlocked
.
Increment
(
ref
c
);
});
pub
.
Subscribe
(
"abc*"
,
(
x
,
y
)
=>
{
Interlocked
.
Increment
(
ref
d
);
});
Thread
.
Sleep
(
1000
);
pub
.
Publish
(
"abcd"
,
"efg"
);
Thread
.
Sleep
(
500
);
Assert
.
AreEqual
(
0
,
Thread
.
VolatileRead
(
ref
a
),
"a1"
);
Assert
.
AreEqual
(
1
,
Thread
.
VolatileRead
(
ref
b
),
"b1"
);
Assert
.
AreEqual
(
1
,
Thread
.
VolatileRead
(
ref
c
),
"c1"
);
Assert
.
AreEqual
(
1
,
Thread
.
VolatileRead
(
ref
d
),
"d1"
);
pub
.
Publish
(
"*bcd"
,
"efg"
);
Thread
.
Sleep
(
500
);
Assert
.
AreEqual
(
1
,
Thread
.
VolatileRead
(
ref
a
),
"a2"
);
//Assert.AreEqual(1, Thread.VolatileRead(ref b), "b2");
//Assert.AreEqual(1, Thread.VolatileRead(ref c), "c2");
//Assert.AreEqual(1, Thread.VolatileRead(ref d), "d2");
}
}
[
Test
]
[
TestCase
(
true
,
null
,
false
)]
[
TestCase
(
false
,
null
,
false
)]
...
...
StackExchange.Redis/StackExchange/Redis/PhysicalConnection.cs
View file @
0cc1d8f9
...
...
@@ -740,7 +740,7 @@ void MatchResult(RawResult result)
}
// invoke the handlers
var
channel
=
items
[
1
].
AsRedisChannel
(
ChannelPrefix
);
var
channel
=
items
[
1
].
AsRedisChannel
(
ChannelPrefix
,
RedisChannel
.
PatternMode
.
Literal
);
multiplexer
.
Trace
(
"MESSAGE: "
+
channel
,
physicalName
);
if
(!
channel
.
IsNull
)
{
...
...
@@ -750,11 +750,11 @@ void MatchResult(RawResult result)
}
else
if
(
items
.
Length
>=
4
&&
items
[
0
].
IsEqual
(
pmessage
))
{
var
channel
=
items
[
2
].
AsRedisChannel
(
ChannelPrefix
);
var
channel
=
items
[
2
].
AsRedisChannel
(
ChannelPrefix
,
RedisChannel
.
PatternMode
.
Literal
);
multiplexer
.
Trace
(
"PMESSAGE: "
+
channel
,
physicalName
);
if
(!
channel
.
IsNull
)
{
var
sub
=
items
[
1
].
AsRedisChannel
(
ChannelPrefix
);
var
sub
=
items
[
1
].
AsRedisChannel
(
ChannelPrefix
,
RedisChannel
.
PatternMode
.
Pattern
);
multiplexer
.
OnMessage
(
sub
,
channel
,
items
[
3
].
AsRedisValue
());
}
return
;
// AND STOP PROCESSING!
...
...
StackExchange.Redis/StackExchange/Redis/RawResult.cs
View file @
0cc1d8f9
...
...
@@ -68,7 +68,7 @@ public override string ToString()
return
"(unknown)"
;
}
}
internal
RedisChannel
AsRedisChannel
(
byte
[]
channelPrefix
)
internal
RedisChannel
AsRedisChannel
(
byte
[]
channelPrefix
,
RedisChannel
.
PatternMode
mode
)
{
switch
(
resultType
)
{
...
...
@@ -76,7 +76,7 @@ internal RedisChannel AsRedisChannel(byte[] channelPrefix)
case
ResultType
.
BulkString
:
if
(
channelPrefix
==
null
)
{
return
(
RedisChannel
)
GetBlob
(
);
return
new
RedisChannel
(
GetBlob
(),
mode
);
}
if
(
AssertStarts
(
channelPrefix
))
{
...
...
@@ -84,7 +84,7 @@ internal RedisChannel AsRedisChannel(byte[] channelPrefix)
byte
[]
copy
=
new
byte
[
count
-
channelPrefix
.
Length
];
Buffer
.
BlockCopy
(
src
,
offset
+
channelPrefix
.
Length
,
copy
,
0
,
copy
.
Length
);
return
(
RedisChannel
)
copy
;
return
new
RedisChannel
(
copy
,
mode
)
;
}
return
default
(
RedisChannel
);
default
:
...
...
StackExchange.Redis/StackExchange/Redis/RedisChannel.cs
View file @
0cc1d8f9
...
...
@@ -13,9 +13,36 @@ public struct RedisChannel : IEquatable<RedisChannel>
private
readonly
byte
[]
value
;
private
RedisChannel
(
byte
[]
value
)
/// <summary>
/// Create a new redis channel from a buffer, explicitly controlling the pattern mode
/// </summary>
public
RedisChannel
(
byte
[]
value
,
PatternMode
mode
)
:
this
(
value
,
DeterminePatternBased
(
value
,
mode
))
{
}
/// <summary>
/// Create a new redis channel from a string, explicitly controlling the pattern mode
/// </summary>
public
RedisChannel
(
string
value
,
PatternMode
mode
)
:
this
(
value
==
null
?
null
:
Encoding
.
UTF8
.
GetBytes
(
value
),
mode
)
{
}
private
RedisChannel
(
byte
[]
value
,
bool
isPatternBased
)
{
this
.
value
=
value
;
this
.
IsPatternBased
=
isPatternBased
;
}
private
static
bool
DeterminePatternBased
(
byte
[]
value
,
PatternMode
mode
)
{
switch
(
mode
)
{
case
PatternMode
.
Auto
:
return
value
!=
null
&&
Array
.
IndexOf
(
value
,
(
byte
)
'*'
)
>=
0
;
case
PatternMode
.
Literal
:
return
false
;
case
PatternMode
.
Pattern
:
return
true
;
default
:
throw
new
ArgumentOutOfRangeException
(
"mode"
);
}
}
/// <summary>
...
...
@@ -81,7 +108,7 @@ internal bool IsNull
/// </summary>
public
static
bool
operator
==(
RedisChannel
x
,
RedisChannel
y
)
{
return
RedisValue
.
Equals
(
x
.
value
,
y
.
value
);
return
x
.
IsPatternBased
==
y
.
IsPatternBased
&&
RedisValue
.
Equals
(
x
.
value
,
y
.
value
);
}
/// <summary>
...
...
@@ -141,7 +168,8 @@ public override bool Equals(object obj)
/// </summary>
public
bool
Equals
(
RedisChannel
other
)
{
return
RedisValue
.
Equals
(
this
.
value
,
other
.
value
);
return
this
.
IsPatternBased
==
other
.
IsPatternBased
&&
RedisValue
.
Equals
(
this
.
value
,
other
.
value
);
}
/// <summary>
...
...
@@ -149,7 +177,7 @@ public bool Equals(RedisChannel other)
/// </summary>
public
override
int
GetHashCode
()
{
return
RedisValue
.
GetHashCode
(
this
.
value
);
return
RedisValue
.
GetHashCode
(
this
.
value
)
+
(
IsPatternBased
?
1
:
0
)
;
}
/// <summary>
...
...
@@ -180,9 +208,25 @@ internal RedisChannel Clone()
return
clone
;
}
internal
bool
Contains
(
byte
value
)
internal
readonly
bool
IsPatternBased
;
/// <summary>
/// The matching pattern for this channel
/// </summary>
public
enum
PatternMode
{
return
this
.
value
!=
null
&&
Array
.
IndexOf
(
this
.
value
,
value
)
>=
0
;
/// <summary>
/// Will be treated as a pattern if it includes *
/// </summary>
Auto
=
0
,
/// <summary>
/// Never a pattern
/// </summary>
Literal
=
1
,
/// <summary>
/// Always a pattern
/// </summary>
Pattern
=
2
}
/// <summary>
/// Create a channel name from a String
...
...
@@ -190,7 +234,7 @@ internal bool Contains(byte value)
public
static
implicit
operator
RedisChannel
(
string
key
)
{
if
(
key
==
null
)
return
default
(
RedisChannel
);
return
new
RedisChannel
(
Encoding
.
UTF8
.
GetBytes
(
key
));
return
new
RedisChannel
(
Encoding
.
UTF8
.
GetBytes
(
key
)
,
PatternMode
.
Auto
);
}
/// <summary>
/// Create a channel name from a Byte[]
...
...
@@ -198,7 +242,7 @@ internal bool Contains(byte value)
public
static
implicit
operator
RedisChannel
(
byte
[]
key
)
{
if
(
key
==
null
)
return
default
(
RedisChannel
);
return
new
RedisChannel
(
key
);
return
new
RedisChannel
(
key
,
PatternMode
.
Auto
);
}
/// <summary>
/// Obtain the channel name as a Byte[]
...
...
StackExchange.Redis/StackExchange/Redis/RedisServer.cs
View file @
0cc1d8f9
...
...
@@ -449,14 +449,14 @@ public RedisChannel[] SubscriptionChannels(RedisChannel pattern = default(RedisC
{
var
msg
=
pattern
.
IsNullOrEmpty
?
Message
.
Create
(-
1
,
flags
,
RedisCommand
.
PUBSUB
,
RedisLiterals
.
CHANNELS
)
:
Message
.
Create
(-
1
,
flags
,
RedisCommand
.
PUBSUB
,
RedisLiterals
.
CHANNELS
,
pattern
);
return
ExecuteSync
(
msg
,
ResultProcessor
.
RedisChannelArray
);
return
ExecuteSync
(
msg
,
ResultProcessor
.
RedisChannelArray
Literal
);
}
public
Task
<
RedisChannel
[
]>
SubscriptionChannelsAsync
(
RedisChannel
pattern
=
default
(
RedisChannel
),
CommandFlags
flags
=
CommandFlags
.
None
)
{
var
msg
=
pattern
.
IsNullOrEmpty
?
Message
.
Create
(-
1
,
flags
,
RedisCommand
.
PUBSUB
,
RedisLiterals
.
CHANNELS
)
:
Message
.
Create
(-
1
,
flags
,
RedisCommand
.
PUBSUB
,
RedisLiterals
.
CHANNELS
,
pattern
);
return
ExecuteAsync
(
msg
,
ResultProcessor
.
RedisChannelArray
);
return
ExecuteAsync
(
msg
,
ResultProcessor
.
RedisChannelArray
Literal
);
}
public
long
SubscriptionPatternCount
(
CommandFlags
flags
=
CommandFlags
.
None
)
...
...
StackExchange.Redis/StackExchange/Redis/RedisSubscriber.cs
View file @
0cc1d8f9
...
...
@@ -186,7 +186,7 @@ public bool Remove(Action<RedisChannel, RedisValue> value)
}
public
Task
SubscribeToServer
(
ConnectionMultiplexer
multiplexer
,
RedisChannel
channel
,
CommandFlags
flags
,
object
asyncState
,
bool
internalCall
)
{
var
cmd
=
channel
.
Contains
((
byte
)
'*'
)
?
RedisCommand
.
PSUBSCRIBE
:
RedisCommand
.
SUBSCRIBE
;
var
cmd
=
channel
.
IsPatternBased
?
RedisCommand
.
PSUBSCRIBE
:
RedisCommand
.
SUBSCRIBE
;
var
selected
=
multiplexer
.
SelectServer
(-
1
,
cmd
,
CommandFlags
.
DemandMaster
,
default
(
RedisKey
));
if
(
selected
==
null
||
Interlocked
.
CompareExchange
(
ref
owner
,
selected
,
null
)
!=
null
)
return
null
;
...
...
@@ -201,7 +201,7 @@ public Task UnsubscribeFromServer(RedisChannel channel, CommandFlags flags, obje
var
oldOwner
=
Interlocked
.
Exchange
(
ref
owner
,
null
);
if
(
oldOwner
==
null
)
return
null
;
var
cmd
=
channel
.
Contains
((
byte
)
'*'
)
?
RedisCommand
.
PUNSUBSCRIBE
:
RedisCommand
.
UNSUBSCRIBE
;
var
cmd
=
channel
.
IsPatternBased
?
RedisCommand
.
PUNSUBSCRIBE
:
RedisCommand
.
UNSUBSCRIBE
;
var
msg
=
Message
.
Create
(-
1
,
flags
,
cmd
,
channel
);
if
(
internalCall
)
msg
.
SetInternalCall
();
return
oldOwner
.
QueueDirectAsync
(
msg
,
ResultProcessor
.
TrackSubscriptions
,
asyncState
);
...
...
@@ -215,7 +215,7 @@ internal void Resubscribe(RedisChannel channel, ServerEndPoint server)
{
if
(
server
!=
null
&&
Interlocked
.
CompareExchange
(
ref
owner
,
server
,
server
)
==
server
)
{
var
cmd
=
channel
.
Contains
((
byte
)
'*'
)
?
RedisCommand
.
PSUBSCRIBE
:
RedisCommand
.
SUBSCRIBE
;
var
cmd
=
channel
.
IsPatternBased
?
RedisCommand
.
PSUBSCRIBE
:
RedisCommand
.
SUBSCRIBE
;
var
msg
=
Message
.
Create
(-
1
,
CommandFlags
.
FireAndForget
,
cmd
,
channel
);
msg
.
SetInternalCall
();
server
.
QueueDirectFireAndForget
(
msg
,
ResultProcessor
.
TrackSubscriptions
);
...
...
StackExchange.Redis/StackExchange/Redis/ResultProcessor.cs
View file @
0cc1d8f9
...
...
@@ -50,7 +50,7 @@ abstract class ResultProcessor
NullableInt64
=
new
NullableInt64Processor
();
public
static
readonly
ResultProcessor
<
RedisChannel
[
]>
RedisChannelArray
=
new
RedisChannelArrayProcessor
(
);
RedisChannelArray
Literal
=
new
RedisChannelArrayProcessor
(
RedisChannel
.
PatternMode
.
Literal
);
public
static
readonly
ResultProcessor
<
RedisKey
>
RedisKey
=
new
RedisKeyProcessor
();
...
...
@@ -971,6 +971,11 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
sealed
class
RedisChannelArrayProcessor
:
ResultProcessor
<
RedisChannel
[
]>
{
private
readonly
RedisChannel
.
PatternMode
mode
;
public
RedisChannelArrayProcessor
(
RedisChannel
.
PatternMode
mode
)
{
this
.
mode
=
mode
;
}
protected
override
bool
SetResultCore
(
PhysicalConnection
connection
,
Message
message
,
RawResult
result
)
{
switch
(
result
.
Type
)
...
...
@@ -988,7 +993,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
byte
[]
channelPrefix
=
connection
.
ChannelPrefix
;
for
(
int
i
=
0
;
i
<
final
.
Length
;
i
++)
{
final
[
i
]
=
arr
[
i
].
AsRedisChannel
(
channelPrefix
);
final
[
i
]
=
arr
[
i
].
AsRedisChannel
(
channelPrefix
,
mode
);
}
}
SetResult
(
message
,
final
);
...
...
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