|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Diagnostics; |
| 4 | +using System.Linq; |
| 5 | +using System.Threading; |
| 6 | + |
| 7 | +namespace StackExchange.Redis; |
| 8 | + |
| 9 | +public partial class ConnectionMultiplexer |
| 10 | +{ |
| 11 | + private readonly HashSet<string> _libraryNameSuffixHash = new(); |
| 12 | + private string _libraryNameSuffixCombined = ""; |
| 13 | + |
| 14 | + /// <inheritdoc cref="IConnectionMultiplexer.AddLibraryNameSuffix(string)" /> |
| 15 | + public void AddLibraryNameSuffix(string suffix) |
| 16 | + { |
| 17 | + if (string.IsNullOrWhiteSpace(suffix)) return; // trivial |
| 18 | + |
| 19 | + // sanitize and re-check |
| 20 | + suffix = ServerEndPoint.ClientInfoSanitize(suffix ?? "").Trim(); |
| 21 | + if (string.IsNullOrWhiteSpace(suffix)) return; // trivial |
| 22 | + |
| 23 | + lock (_libraryNameSuffixHash) |
| 24 | + { |
| 25 | + if (!_libraryNameSuffixHash.Add(suffix)) return; // already cited; nothing to do |
| 26 | + |
| 27 | + _libraryNameSuffixCombined = "-" + string.Join("-", _libraryNameSuffixHash.OrderBy(_ => _)); |
| 28 | + } |
| 29 | + |
| 30 | + // if we get here, we *actually changed something*; we can retroactively fixup the connections |
| 31 | + var libName = GetFullLibraryName(); // note this also checks SetClientLibrary |
| 32 | + if (string.IsNullOrWhiteSpace(libName) || !CommandMap.IsAvailable(RedisCommand.CLIENT)) return; // disabled on no lib name |
| 33 | + |
| 34 | + // note that during initial handshake we use raw Message; this is low frequency - no |
| 35 | + // concern over overhead of Execute here |
| 36 | + var args = new object[] { RedisLiterals.SETINFO, RedisLiterals.lib_name, libName }; |
| 37 | + foreach (var server in GetServers()) |
| 38 | + { |
| 39 | + try |
| 40 | + { |
| 41 | + // note we can only fixup the *interactive* channel; that's tolerable here |
| 42 | + if (server.IsConnected) |
| 43 | + { |
| 44 | + // best effort only |
| 45 | + server.Execute("CLIENT", args, CommandFlags.FireAndForget); |
| 46 | + } |
| 47 | + } |
| 48 | + catch (Exception ex) |
| 49 | + { |
| 50 | + // if an individual server trips, that's fine - best effort; note we're using |
| 51 | + // F+F here anyway, so we don't *expect* any failures |
| 52 | + Debug.WriteLine(ex.Message); |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + internal string GetFullLibraryName() |
| 58 | + { |
| 59 | + var config = RawConfig; |
| 60 | + if (!config.SetClientLibrary) return ""; // disabled |
| 61 | + |
| 62 | + var libName = config.LibraryName; |
| 63 | + if (string.IsNullOrWhiteSpace(libName)) |
| 64 | + { |
| 65 | + // defer to provider if missing (note re null vs blank; if caller wants to disable |
| 66 | + // it, they should set SetClientLibrary to false, not set the name to empty string) |
| 67 | + libName = config.Defaults.LibraryName; |
| 68 | + } |
| 69 | + |
| 70 | + libName = ServerEndPoint.ClientInfoSanitize(libName); |
| 71 | + // if no primary name, return nothing, even if suffixes exist |
| 72 | + if (string.IsNullOrWhiteSpace(libName)) return ""; |
| 73 | + |
| 74 | + return libName + Volatile.Read(ref _libraryNameSuffixCombined); |
| 75 | + } |
| 76 | +} |
0 commit comments