Skip to content

Commit ebcf516

Browse files
committed
optimize channel tests
1 parent 71083d8 commit ebcf516

2 files changed

Lines changed: 114 additions & 71 deletions

File tree

src/StackExchange.Redis/KeyNotification.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22
using System.Buffers.Text;
33
using System.Diagnostics;
4-
4+
using static StackExchange.Redis.KeyNotificationChannels;
55
namespace StackExchange.Redis;
66

77
/// <summary>
@@ -16,20 +16,35 @@ public static bool TryParse(in RedisChannel channel, in RedisValue value, out Ke
1616
{
1717
// validate that it looks reasonable
1818
var span = channel.Span;
19-
if (span.StartsWith("__keyspace@"u8) || span.StartsWith("__keyevent@"u8))
19+
20+
const int PREFIX_LEN = KeySpaceStart.Length, MIN_LEN = PREFIX_LEN + MinSuffixBytes; // need "0__:x" or similar after prefix
21+
Debug.Assert(KeyEventStart.Length == PREFIX_LEN); // prove these are the same, DEBUG only
22+
23+
if (span.Length >= MIN_LEN)
2024
{
21-
// check that there is *something* non-empty after the prefix, with __: as the suffix (we don't verify *what*)
22-
if (span.Slice(11).IndexOf("__:"u8) > 0)
25+
var prefix = span.Slice(0, PREFIX_LEN);
26+
var hash = prefix.Hash64();
27+
switch (hash)
2328
{
24-
notification = new KeyNotification(in channel, in value);
25-
return true;
29+
case KeySpaceStart.Hash when KeySpaceStart.Is(hash, prefix):
30+
case KeyEventStart.Hash when KeyEventStart.Is(hash, prefix):
31+
// check that there is *something* non-empty after the prefix, with __: as the suffix (we don't verify *what*)
32+
if (span.Slice(PREFIX_LEN).IndexOf("__:"u8) > 0)
33+
{
34+
notification = new KeyNotification(in channel, in value);
35+
return true;
36+
}
37+
38+
break;
2639
}
2740
}
2841

2942
notification = default;
3043
return false;
3144
}
3245

46+
private const int MinSuffixBytes = 5; // need "0__:x" or similar after prefix
47+
3348
/// <summary>
3449
/// The channel associated with this notification.
3550
/// </summary>
@@ -194,10 +209,37 @@ public KeyNotificationType Type
194209
/// <summary>
195210
/// Indicates whether this notification originated from a keyspace notification, for example <c>__keyspace@0__:mykey</c> with payload <c>set</c>.
196211
/// </summary>
197-
public bool IsKeySpace => _channel.Span.StartsWith("__keyspace@"u8);
212+
public bool IsKeySpace
213+
{
214+
get
215+
{
216+
var span = _channel.Span;
217+
return span.Length >= KeySpaceStart.Length + MinSuffixBytes && KeySpaceStart.Is(span.Hash64(), span.Slice(0, KeySpaceStart.Length));
218+
}
219+
}
198220

199221
/// <summary>
200222
/// Indicates whether this notification originated from a keyevent notification, for example <c>__keyevent@0__:set</c> with payload <c>mykey</c>.
201223
/// </summary>
202-
public bool IsKeyEvent => _channel.Span.StartsWith("__keyevent@"u8);
224+
public bool IsKeyEvent
225+
{
226+
get
227+
{
228+
var span = _channel.Span;
229+
return span.Length >= KeyEventStart.Length + MinSuffixBytes && KeyEventStart.Is(span.Hash64(), span.Slice(0, KeyEventStart.Length));
230+
}
231+
}
232+
}
233+
234+
internal static partial class KeyNotificationChannels
235+
{
236+
[FastHash("__keyspace@")]
237+
internal static partial class KeySpaceStart
238+
{
239+
}
240+
241+
[FastHash("__keyevent@")]
242+
internal static partial class KeyEventStart
243+
{
244+
}
203245
}

src/StackExchange.Redis/KeyNotificationTypeFastHash.cs

Lines changed: 64 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,70 @@ type_changed.Hash when type_changed.Is(hash, value) => KeyNotificationType.TypeC
7272
_ => KeyNotificationType.Unknown,
7373
};
7474
}
75+
76+
internal static ReadOnlySpan<byte> GetRawBytes(KeyNotificationType type)
77+
{
78+
return type switch
79+
{
80+
KeyNotificationType.Append => append.U8,
81+
KeyNotificationType.Copy => copy.U8,
82+
KeyNotificationType.Del => del.U8,
83+
KeyNotificationType.Expire => expire.U8,
84+
KeyNotificationType.HDel => hdel.U8,
85+
KeyNotificationType.HExpired => hexpired.U8,
86+
KeyNotificationType.HIncrByFloat => hincrbyfloat.U8,
87+
KeyNotificationType.HIncrBy => hincrby.U8,
88+
KeyNotificationType.HPersist => hpersist.U8,
89+
KeyNotificationType.HSet => hset.U8,
90+
KeyNotificationType.IncrByFloat => incrbyfloat.U8,
91+
KeyNotificationType.IncrBy => incrby.U8,
92+
KeyNotificationType.LInsert => linsert.U8,
93+
KeyNotificationType.LPop => lpop.U8,
94+
KeyNotificationType.LPush => lpush.U8,
95+
KeyNotificationType.LRem => lrem.U8,
96+
KeyNotificationType.LSet => lset.U8,
97+
KeyNotificationType.LTrim => ltrim.U8,
98+
KeyNotificationType.MoveFrom => move_from.U8,
99+
KeyNotificationType.MoveTo => move_to.U8,
100+
KeyNotificationType.Persist => persist.U8,
101+
KeyNotificationType.RenameFrom => rename_from.U8,
102+
KeyNotificationType.RenameTo => rename_to.U8,
103+
KeyNotificationType.Restore => restore.U8,
104+
KeyNotificationType.RPop => rpop.U8,
105+
KeyNotificationType.RPush => rpush.U8,
106+
KeyNotificationType.SAdd => sadd.U8,
107+
KeyNotificationType.Set => set.U8,
108+
KeyNotificationType.SetRange => setrange.U8,
109+
KeyNotificationType.SortStore => sortstore.U8,
110+
KeyNotificationType.SRem => srem.U8,
111+
KeyNotificationType.SPop => spop.U8,
112+
KeyNotificationType.XAdd => xadd.U8,
113+
KeyNotificationType.XDel => xdel.U8,
114+
KeyNotificationType.XGroupCreateConsumer => xgroup_createconsumer.U8,
115+
KeyNotificationType.XGroupCreate => xgroup_create.U8,
116+
KeyNotificationType.XGroupDelConsumer => xgroup_delconsumer.U8,
117+
KeyNotificationType.XGroupDestroy => xgroup_destroy.U8,
118+
KeyNotificationType.XGroupSetId => xgroup_setid.U8,
119+
KeyNotificationType.XSetId => xsetid.U8,
120+
KeyNotificationType.XTrim => xtrim.U8,
121+
KeyNotificationType.ZAdd => zadd.U8,
122+
KeyNotificationType.ZDiffStore => zdiffstore.U8,
123+
KeyNotificationType.ZInterStore => zinterstore.U8,
124+
KeyNotificationType.ZUnionStore => zunionstore.U8,
125+
KeyNotificationType.ZIncr => zincr.U8,
126+
KeyNotificationType.ZRemByRank => zrembyrank.U8,
127+
KeyNotificationType.ZRemByScore => zrembyscore.U8,
128+
KeyNotificationType.ZRem => zrem.U8,
129+
KeyNotificationType.Expired => expired.U8,
130+
KeyNotificationType.Evicted => evicted.U8,
131+
KeyNotificationType.New => _new.U8,
132+
KeyNotificationType.Overwritten => overwritten.U8,
133+
KeyNotificationType.TypeChanged => type_changed.U8,
134+
_ => Throw(),
135+
};
136+
static ReadOnlySpan<byte> Throw() => throw new ArgumentOutOfRangeException(nameof(type));
137+
}
138+
75139
#pragma warning disable SA1300, CS8981
76140
// ReSharper disable InconsistentNaming
77141
[FastHash]
@@ -346,67 +410,4 @@ internal static partial class type_changed
346410

347411
// ReSharper restore InconsistentNaming
348412
#pragma warning restore SA1300, CS8981
349-
350-
internal static ReadOnlySpan<byte> GetRawBytes(KeyNotificationType type)
351-
{
352-
return type switch
353-
{
354-
KeyNotificationType.Append => append.U8,
355-
KeyNotificationType.Copy => copy.U8,
356-
KeyNotificationType.Del => del.U8,
357-
KeyNotificationType.Expire => expire.U8,
358-
KeyNotificationType.HDel => hdel.U8,
359-
KeyNotificationType.HExpired => hexpired.U8,
360-
KeyNotificationType.HIncrByFloat => hincrbyfloat.U8,
361-
KeyNotificationType.HIncrBy => hincrby.U8,
362-
KeyNotificationType.HPersist => hpersist.U8,
363-
KeyNotificationType.HSet => hset.U8,
364-
KeyNotificationType.IncrByFloat => incrbyfloat.U8,
365-
KeyNotificationType.IncrBy => incrby.U8,
366-
KeyNotificationType.LInsert => linsert.U8,
367-
KeyNotificationType.LPop => lpop.U8,
368-
KeyNotificationType.LPush => lpush.U8,
369-
KeyNotificationType.LRem => lrem.U8,
370-
KeyNotificationType.LSet => lset.U8,
371-
KeyNotificationType.LTrim => ltrim.U8,
372-
KeyNotificationType.MoveFrom => move_from.U8,
373-
KeyNotificationType.MoveTo => move_to.U8,
374-
KeyNotificationType.Persist => persist.U8,
375-
KeyNotificationType.RenameFrom => rename_from.U8,
376-
KeyNotificationType.RenameTo => rename_to.U8,
377-
KeyNotificationType.Restore => restore.U8,
378-
KeyNotificationType.RPop => rpop.U8,
379-
KeyNotificationType.RPush => rpush.U8,
380-
KeyNotificationType.SAdd => sadd.U8,
381-
KeyNotificationType.Set => set.U8,
382-
KeyNotificationType.SetRange => setrange.U8,
383-
KeyNotificationType.SortStore => sortstore.U8,
384-
KeyNotificationType.SRem => srem.U8,
385-
KeyNotificationType.SPop => spop.U8,
386-
KeyNotificationType.XAdd => xadd.U8,
387-
KeyNotificationType.XDel => xdel.U8,
388-
KeyNotificationType.XGroupCreateConsumer => xgroup_createconsumer.U8,
389-
KeyNotificationType.XGroupCreate => xgroup_create.U8,
390-
KeyNotificationType.XGroupDelConsumer => xgroup_delconsumer.U8,
391-
KeyNotificationType.XGroupDestroy => xgroup_destroy.U8,
392-
KeyNotificationType.XGroupSetId => xgroup_setid.U8,
393-
KeyNotificationType.XSetId => xsetid.U8,
394-
KeyNotificationType.XTrim => xtrim.U8,
395-
KeyNotificationType.ZAdd => zadd.U8,
396-
KeyNotificationType.ZDiffStore => zdiffstore.U8,
397-
KeyNotificationType.ZInterStore => zinterstore.U8,
398-
KeyNotificationType.ZUnionStore => zunionstore.U8,
399-
KeyNotificationType.ZIncr => zincr.U8,
400-
KeyNotificationType.ZRemByRank => zrembyrank.U8,
401-
KeyNotificationType.ZRemByScore => zrembyscore.U8,
402-
KeyNotificationType.ZRem => zrem.U8,
403-
KeyNotificationType.Expired => expired.U8,
404-
KeyNotificationType.Evicted => evicted.U8,
405-
KeyNotificationType.New => _new.U8,
406-
KeyNotificationType.Overwritten => overwritten.U8,
407-
KeyNotificationType.TypeChanged => type_changed.U8,
408-
_ => Throw(),
409-
};
410-
static ReadOnlySpan<byte> Throw() => throw new ArgumentOutOfRangeException(nameof(type));
411-
}
412413
}

0 commit comments

Comments
 (0)