diff --git a/Directory.Packages.props b/Directory.Packages.props
index b6059652e5d..e933fb6f406 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -13,6 +13,7 @@
+
diff --git a/Garnet.slnx b/Garnet.slnx
index 59c0a0b3cb3..84dbfcb940d 100644
--- a/Garnet.slnx
+++ b/Garnet.slnx
@@ -1,4 +1,5 @@
+
@@ -12,11 +13,15 @@
+
+
+
+
@@ -29,12 +34,8 @@
-
-
-
-
-
-
+
+
diff --git a/analyzer/Garnet.analyzers/AvoidRespWriteUtilsAnalyzer.cs b/analyzer/Garnet.analyzers/AvoidRespWriteUtilsAnalyzer.cs
new file mode 100644
index 00000000000..86cc5b993b3
--- /dev/null
+++ b/analyzer/Garnet.analyzers/AvoidRespWriteUtilsAnalyzer.cs
@@ -0,0 +1,151 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Garnet.analyzers
+{
+ ///
+ /// Analyzer which flags uses of RespWriteUtils outside of the RespServerSessionOutput helper methods.
+ ///
+ /// The intent is to force consistency in output for handling large outputs, error tracking, constant use, etc.
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public sealed class AvoidRespWriteUtilsAnalyzer : DiagnosticAnalyzer
+ {
+ private static DiagnosticDescriptor AvoidRespWriteUtils { get; } = new("GARNET0001", "Avoid direct use of RespWriteUtils", "If possible use RespServerSession.{0} instead of RespWriteUtils.{1}", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } = [AvoidRespWriteUtils];
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics | GeneratedCodeAnalysisFlags.Analyze);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(
+ static compilationStartContext =>
+ {
+ var respWriteUtilsType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.common.RespWriteUtils");
+ var respServerSessionType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.server.RespServerSession");
+
+ if (respWriteUtilsType is not null && respServerSessionType is not null)
+ {
+ var suggestionLookup = BuildLookup(respWriteUtilsType, respServerSessionType);
+
+ compilationStartContext.RegisterSyntaxNodeAction(syntaxNodeContext => AnalyzeCaller(syntaxNodeContext, respWriteUtilsType, suggestionLookup), SyntaxKind.InvocationExpression);
+ }
+ }
+ );
+
+ // Build a map of TryWriteXXX methods on RespWriteUtils -> WriteXXX methods on RespServerSession
+ static Dictionary BuildLookup(INamedTypeSymbol respWriteUtilsType, INamedTypeSymbol respServerSessionType)
+ {
+ var tryWriteMethods = new HashSet();
+
+ foreach (var member in respWriteUtilsType.GetMembers())
+ {
+ if (member is not IMethodSymbol mtdSymbol)
+ {
+ continue;
+ }
+
+ if (!member.Name.StartsWith("TryWrite"))
+ {
+ continue;
+ }
+
+ _ = tryWriteMethods.Add(member.Name);
+ }
+
+ var lookup = new Dictionary();
+ foreach (var member in respServerSessionType.GetMembers())
+ {
+ if (member is not IMethodSymbol mtdSymbol)
+ {
+ continue;
+ }
+
+ // Check that method is declared in RespServerSessionOutput.cs, otherwise we don't consider it a candidate for flagging
+ if (!member.DeclaringSyntaxReferences.Any(static decl => Path.GetFileName(decl.SyntaxTree.FilePath) == "RespServerSessionOutput.cs"))
+ {
+ continue;
+ }
+
+ if (!member.Name.StartsWith("Write"))
+ {
+ continue;
+ }
+
+ var tryEquivalent = $"Try{member.Name}";
+ if (!tryWriteMethods.Contains(tryEquivalent))
+ {
+ continue;
+ }
+
+ lookup[tryEquivalent] = member.Name;
+ }
+
+ return lookup;
+ }
+ }
+
+ ///
+ /// Flag all calls to methods looking like RespWriteUtils.TryXXX
+ ///
+ private static void AnalyzeCaller(SyntaxNodeAnalysisContext context, INamedTypeSymbol respWriteUtilsType, Dictionary candidateLookup)
+ {
+ if (context.Node is not InvocationExpressionSyntax invoke)
+ {
+ return;
+ }
+
+ if (invoke.Expression is not MemberAccessExpressionSyntax memberAccess)
+ {
+ return;
+ }
+
+ if (memberAccess.Name is not IdentifierNameSyntax methodName)
+ {
+ return;
+ }
+
+ // Quickly filter out anything that doesn't look like a TryXXX method
+ if (string.IsNullOrEmpty(methodName.Identifier.Text) || !methodName.Identifier.Text.StartsWith("Try"))
+ {
+ return;
+ }
+
+ // Filter out anything in RespServerSessionOutput.cs, as it's intended to use these methods
+ if (Path.GetFileName(context.Node.SyntaxTree.FilePath) == "RespServerSessionOutput.cs")
+ {
+ return;
+ }
+
+ // Ignore anything that isn't a call to RespWriteUtils
+ var leftHandType = context.SemanticModel.GetSymbolInfo(memberAccess.Expression);
+ if (leftHandType.Symbol is null || !SymbolEqualityComparer.Default.Equals(leftHandType.Symbol, respWriteUtilsType))
+ {
+ return;
+ }
+
+ // Lookup equivalent method, and raise diagnostic
+ if (!candidateLookup.TryGetValue(methodName.Identifier.Text, out var rewriteTo))
+ {
+ return;
+ }
+
+ // Raise the actual diagnostic
+ var diag = Diagnostic.Create(AvoidRespWriteUtils, context.Node.GetLocation(), rewriteTo, methodName.Identifier.Text);
+ context.ReportDiagnostic(diag);
+ }
+ }
+}
diff --git a/analyzer/Garnet.analyzers/CollapseRepeatedConstantWriteCallsAnalyzer.cs b/analyzer/Garnet.analyzers/CollapseRepeatedConstantWriteCallsAnalyzer.cs
new file mode 100644
index 00000000000..f66bc6007d1
--- /dev/null
+++ b/analyzer/Garnet.analyzers/CollapseRepeatedConstantWriteCallsAnalyzer.cs
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Garnet.analyzers
+{
+ ///
+ /// Flag cases where two or more sequential calls to WriteXXX helpers (defined in RespServerSession) where the arguments are constants.
+ ///
+ /// IE.
+ /// WriteArrayLength(2)
+ /// WriteBulkString(CmdStrings.Foo)
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public sealed class CollapseRepeatedConstantWriteCallsAnalyzer : DiagnosticAnalyzer
+ {
+ private static DiagnosticDescriptor CollapseRepeatedConstantWriteCalls { get; } = new("GARNET0007", "Collapse Repeated Constant Write Calls", "Define a CmdString constant for these {0} consecutive WriteXXX helper calls", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } = [CollapseRepeatedConstantWriteCalls];
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics | GeneratedCodeAnalysisFlags.Analyze);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(
+ compilationStartContext =>
+ {
+ var respServerSessionType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.server.RespServerSession");
+ var cmdStringsType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.server.CmdStrings");
+
+ if (respServerSessionType is not null && cmdStringsType is not null)
+ {
+ var lookup = BuildLookup(respServerSessionType);
+
+ compilationStartContext.RegisterSyntaxNodeAction(
+ syntaxNodeContext => AnalyzeCodeBlockForRepeatedConstantWriteCalls(syntaxNodeContext, cmdStringsType, lookup),
+ SyntaxKind.Block
+ );
+ }
+ }
+ );
+
+ // Lookup all WriteXXX methods declared in RespServerSessionOutput.cs
+ static HashSet BuildLookup(INamedTypeSymbol respServerSessionType)
+ {
+ var lookup = new HashSet(SymbolEqualityComparer.Default);
+ foreach (var member in respServerSessionType.GetMembers())
+ {
+ if (member is not IMethodSymbol mtdSymbol)
+ {
+ continue;
+ }
+
+ // Check that method is declared in RespServerSessionOutput.cs, otherwise we don't consider it a candidate for flagging
+ if (!member.DeclaringSyntaxReferences.Any(static decl => Path.GetFileName(decl.SyntaxTree.FilePath) == "RespServerSessionOutput.cs"))
+ {
+ continue;
+ }
+
+ if (!member.Name.StartsWith("Write"))
+ {
+ continue;
+ }
+
+ _ = lookup.Add(mtdSymbol);
+ }
+
+ return lookup;
+ }
+ }
+
+ ///
+ /// Raise the if 2 or more calls to methods in appear in a row with constant arguments.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("MicrosoftCodeAnalysisCorrectness", "RS1024:Symbols should be compared for equality", Justification = "writeMethods is constructed with the appropriate comparer")]
+ private static void AnalyzeCodeBlockForRepeatedConstantWriteCalls(SyntaxNodeAnalysisContext blockAnalyzeContext, INamedTypeSymbol cmdStringsType, HashSet writeMethods)
+ {
+ if (blockAnalyzeContext.Node is not BlockSyntax blockSyntax)
+ {
+ return;
+ }
+
+ if (blockSyntax.Statements.Count <= 1)
+ {
+ return;
+ }
+
+ // Walk through all statements and find runs of 2+ constant calls to methods in writeMethods
+ var constantWriteCalls = new List();
+ foreach (var statement in blockSyntax.Statements)
+ {
+ // Skip trivia
+ if (statement.IsStructuredTrivia)
+ {
+ continue;
+ }
+
+ // Only look at statements of the form:
+ // WriteXXX();
+ if (statement is ExpressionStatementSyntax expressionSyntax && expressionSyntax.Expression is InvocationExpressionSyntax invocationSyntax && invocationSyntax.Expression is IdentifierNameSyntax mtdNameSyntax && mtdNameSyntax.Identifier.Text.StartsWith("Write"))
+ {
+ var methodType = blockAnalyzeContext.SemanticModel.GetSymbolInfo(mtdNameSyntax, blockAnalyzeContext.CancellationToken);
+ if (methodType.Symbol is not null && writeMethods.Contains(methodType.Symbol) && IsConstantMethodCall(blockAnalyzeContext, invocationSyntax, cmdStringsType))
+ {
+ // This is a constant, remember it and move on
+ constantWriteCalls.Add(expressionSyntax);
+ continue;
+ }
+ }
+
+ // If we encountered something we _didn't_ remember then we need to raise diagnostics for the previously found statements
+ if (constantWriteCalls.Count > 1)
+ {
+ RaiseDiagnostic(blockAnalyzeContext, constantWriteCalls);
+ }
+
+ // A single statement cannot be collapsed
+ if (constantWriteCalls.Count != 0)
+ {
+ constantWriteCalls.Clear();
+ }
+ }
+
+ // At the end of the block, flush any previously found statements
+ if (constantWriteCalls.Count > 1)
+ {
+ RaiseDiagnostic(blockAnalyzeContext, constantWriteCalls);
+ }
+
+ // Determine if a call to the given WriteXXX method should be considered a constant call
+ static bool IsConstantMethodCall(SyntaxNodeAnalysisContext blockAnalyzeContext, InvocationExpressionSyntax invocationSyntax, INamedTypeSymbol cmdStringsType)
+ {
+ foreach (var arg in invocationSyntax.ArgumentList.Arguments)
+ {
+ if (arg.Expression is MemberAccessExpressionSyntax memberAccess)
+ {
+ var beingAccessed = blockAnalyzeContext.SemanticModel.GetSymbolInfo(memberAccess.Expression, blockAnalyzeContext.CancellationToken);
+ if (beingAccessed.Symbol is not null && SymbolEqualityComparer.Default.Equals(beingAccessed.Symbol, cmdStringsType))
+ {
+ continue;
+ }
+ }
+
+ var constantValue = blockAnalyzeContext.SemanticModel.GetConstantValue(arg.Expression);
+ if (constantValue.HasValue)
+ {
+ continue;
+ }
+
+ // Non-constant, can't collapse
+ return false;
+ }
+
+ // All constants (including no argument), we can collapse
+ return true;
+ }
+
+ // Raise a diagnostic that covers all the consecutive statements passed
+ static void RaiseDiagnostic(SyntaxNodeAnalysisContext blockAnalyzeContext, List toFlag)
+ {
+ var start = toFlag[0].GetLocation();
+ var end = toFlag[toFlag.Count - 1].GetLocation();
+
+ var wholeSpan = new TextSpan(start.SourceSpan.Start, end.SourceSpan.End - start.SourceSpan.Start);
+ var location = Location.Create(start.SourceTree, wholeSpan);
+
+ var diag = Diagnostic.Create(CollapseRepeatedConstantWriteCalls, location, toFlag.Count);
+ blockAnalyzeContext.ReportDiagnostic(diag);
+ }
+ }
+ }
+}
diff --git a/analyzer/Garnet.analyzers/Garnet.analyzers.csproj b/analyzer/Garnet.analyzers/Garnet.analyzers.csproj
new file mode 100644
index 00000000000..72905e32202
--- /dev/null
+++ b/analyzer/Garnet.analyzers/Garnet.analyzers.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netstandard2.0
+ true
+ $(NoWarn);RS2008
+
+
+
+
+
+
+
diff --git a/analyzer/Garnet.analyzers/UseLargeOrConstantsForRespWritesAnalyzer.cs b/analyzer/Garnet.analyzers/UseLargeOrConstantsForRespWritesAnalyzer.cs
new file mode 100644
index 00000000000..753c77b06a8
--- /dev/null
+++ b/analyzer/Garnet.analyzers/UseLargeOrConstantsForRespWritesAnalyzer.cs
@@ -0,0 +1,464 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Garnet.analyzers
+{
+ ///
+ /// A number of analyzers in here to keep us honest about large responses and using CmdStrings
+ /// - Flag any call to WriteXXX methods in RespServerSessionOutput.cs which are variable size UNLESS they call a method with Large in its name
+ /// - Flag constants pass to WriteXXX methods which are not placed in CmdStrings classes
+ /// - Flag constants which are larger than minimum send buffer sizes
+ ///
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public sealed class UseLargeOrConstantsForRespWritesAnalyzer : DiagnosticAnalyzer
+ {
+ private static DiagnosticDescriptor UseLargeOverridesWithVariableSizeResponses { get; } = new("GARNET0002", "Use Large Overrides With Variable Size Responses", "Use {0} instead of {1} for variable size responses", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+ private static DiagnosticDescriptor AddLargeOverridesForVariableSizeResponses { get; } = new("GARNET0003", "Add Large Override For Variable Size Responses", "Add and use {0} to RespServerSessionOutput.cs in place of using {1} for variable size responses", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+ private static DiagnosticDescriptor MoveOutputConstantsToCmdStrings { get; } = new("GARNET0004", "Move Output Constants To CmdStrings", "Add {0} to CmdStrings and use it in place of an inline literal", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+ private static DiagnosticDescriptor UseExistingConstantInCmdStrings { get; } = new("GARNET0005", "Use Existing Constants In CmdStrings", "Use CmdStrings.{0} instead of inline literal", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+ private static DiagnosticDescriptor CmdStringsConstantTooLarge { get; } = new("GARNET0006", "CmdStrings Constant Too Large", "CmdStrings.{0} estimated serialization length of {1} exceeds minimum send buffer size of {2}", "Correctness", DiagnosticSeverity.Warning, isEnabledByDefault: true);
+
+ ///
+ public override ImmutableArray SupportedDiagnostics { get; } = [UseLargeOverridesWithVariableSizeResponses, AddLargeOverridesForVariableSizeResponses, MoveOutputConstantsToCmdStrings, UseExistingConstantInCmdStrings, CmdStringsConstantTooLarge];
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.ReportDiagnostics | GeneratedCodeAnalysisFlags.Analyze);
+ context.EnableConcurrentExecution();
+
+ context.RegisterCompilationStartAction(
+ static compilationStartContext =>
+ {
+ var respServerSessionType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.server.RespServerSession");
+ var cmdStringType = compilationStartContext.Compilation.GetTypeByMetadataName("Garnet.server.CmdStrings");
+
+ var byteType = compilationStartContext.Compilation.GetSpecialType(SpecialType.System_Byte);
+ var charType = compilationStartContext.Compilation.GetSpecialType(SpecialType.System_Char);
+ var stringType = compilationStartContext.Compilation.GetSpecialType(SpecialType.System_String);
+
+ var spanType = compilationStartContext.Compilation.GetTypeByMetadataName("System.Span`1");
+ var readOnlySpanType = compilationStartContext.Compilation.GetTypeByMetadataName("System.ReadOnlySpan`1");
+
+ var spanByteType = spanType.Construct(byteType);
+ var spanCharType = spanType.Construct(charType);
+
+ var readOnlySpanByteType = readOnlySpanType.Construct(byteType);
+ var readOnlySpanCharType = readOnlySpanType.Construct(charType);
+
+ var byteArrayType = compilationStartContext.Compilation.CreateArrayTypeSymbol(byteType);
+ var charArrayType = compilationStartContext.Compilation.CreateArrayTypeSymbol(charType);
+
+ HashSet variableLengthTypes =
+ new(SymbolEqualityComparer.Default)
+ {
+ spanByteType,
+ spanCharType,
+ readOnlySpanByteType,
+ readOnlySpanCharType,
+ stringType,
+ byteArrayType,
+ charArrayType,
+ };
+
+ if (respServerSessionType is not null && cmdStringType is not null)
+ {
+ var suggestionLookup = BuildWriteLargeLookup(respServerSessionType);
+
+ compilationStartContext.RegisterSyntaxNodeAction(
+ syntaxNodeContext =>
+ {
+ AnalyzeCallerForVariableSizeViolations(syntaxNodeContext, cmdStringType, variableLengthTypes, suggestionLookup, syntaxNodeContext.CancellationToken);
+ },
+ SyntaxKind.InvocationExpression
+ );
+
+ var knownConstants = BuildKnownConstantsLookup(cmdStringType, readOnlySpanByteType, compilationStartContext.CancellationToken);
+
+ compilationStartContext.RegisterSyntaxNodeAction(
+ syntaxNodeAction =>
+ {
+ AnalyzeCallerForNonCmdStringsConstants(syntaxNodeAction, cmdStringType, respServerSessionType, knownConstants, syntaxNodeAction.CancellationToken);
+ },
+ SyntaxKind.InvocationExpression
+ );
+
+ compilationStartContext.RegisterSyntaxNodeAction(
+ syntaxNodeAction =>
+ {
+ AnalyzeDeclarationForTooLargeCmdStringConstants(syntaxNodeAction, cmdStringType, knownConstants);
+ },
+ SyntaxKind.ClassDeclaration
+ );
+ }
+ }
+ );
+
+ // Build a map of WriteXXX -> WriteLargeXXX methods on RespServerSession
+ static Dictionary BuildWriteLargeLookup(INamedTypeSymbol respServerSessionType)
+ {
+ var writeMethods = new HashSet();
+ var writeLargeMethods = new HashSet();
+ foreach (var member in respServerSessionType.GetMembers())
+ {
+ if (member is not IMethodSymbol mtdSymbol)
+ {
+ continue;
+ }
+
+ // Check that method is declared in RespServerSessionOutput.cs, otherwise we don't consider it a candidate for flagging
+ if (!member.DeclaringSyntaxReferences.Any(static decl => Path.GetFileName(decl.SyntaxTree.FilePath) == "RespServerSessionOutput.cs"))
+ {
+ continue;
+ }
+
+ if (member.Name.StartsWith("WriteLarge"))
+ {
+ _ = writeLargeMethods.Add(member.Name);
+ }
+ else if (member.Name.StartsWith("Write"))
+ {
+ _ = writeMethods.Add(member.Name);
+ }
+ }
+
+ var lookup = new Dictionary();
+
+ foreach (var largeMtd in writeLargeMethods)
+ {
+ var writeEquiv = $"Write{largeMtd.Substring("WriteLarge".Length)}";
+
+ if (writeMethods.Contains(writeEquiv))
+ {
+ lookup[writeEquiv] = largeMtd;
+ }
+ }
+
+ return lookup;
+ }
+
+ // Build a map of literals ("foo" and "bar"u8) to the corresponding properties on CmdStrings
+ static Dictionary BuildKnownConstantsLookup(INamedTypeSymbol cmdStringsType, INamedTypeSymbol readOnlySpanByteType, CancellationToken cancellation)
+ {
+ var lookup = new Dictionary();
+
+ foreach (var prop in cmdStringsType.GetMembers().OfType())
+ {
+ if (prop.GetMethod is null || prop.SetMethod is not null)
+ {
+ continue;
+ }
+
+ if (!SymbolEqualityComparer.Default.Equals(prop.Type, readOnlySpanByteType))
+ {
+ continue;
+ }
+
+ var getDecl = prop.GetMethod.DeclaringSyntaxReferences.SingleOrDefault();
+ if (getDecl == null)
+ {
+ continue;
+ }
+
+ var getDeclSyntax = getDecl.GetSyntax(cancellation);
+ if (getDeclSyntax is not ArrowExpressionClauseSyntax arrowDecl)
+ {
+ continue;
+ }
+
+ if (arrowDecl.Expression is not LiteralExpressionSyntax literal)
+ {
+ continue;
+ }
+
+ lookup[literal.Token.Text] = prop.Name;
+ }
+
+ return lookup;
+ }
+ }
+
+ ///
+ /// Raises and .
+ ///
+ /// Finds any calls to WriteXXX where the input is variable length type AND not a constant, suggests uing WriteLargeXXX instead (or implementing it if it's not avaiable).
+ ///
+ private static void AnalyzeCallerForVariableSizeViolations(SyntaxNodeAnalysisContext context, INamedTypeSymbol cmdStringsType, HashSet variableLengthTypes, Dictionary largeEquivLookup, CancellationToken cancellation)
+ {
+ if (context.Node is not InvocationExpressionSyntax invoke)
+ {
+ return;
+ }
+
+ if (invoke.Expression is not IdentifierNameSyntax methodName)
+ {
+ return;
+ }
+
+ // Quickly filter out anything that doesn't look like a plain Write method
+ if (string.IsNullOrEmpty(methodName.Identifier.Text) || !methodName.Identifier.Text.StartsWith("Write") || methodName.Identifier.Text.StartsWith("WriteLarge"))
+ {
+ return;
+ }
+
+ // Ignore anything that isn't a call to a method in RespServerSessionOutput.cs
+ var method = context.SemanticModel.GetSymbolInfo(methodName);
+ if (method.Symbol is not IMethodSymbol methodSymbol || !method.Symbol.DeclaringSyntaxReferences.Any(static decl => Path.GetFileName(decl.SyntaxTree.FilePath) == "RespServerSessionOutput.cs"))
+ {
+ return;
+ }
+
+ // Skip anything without parameters or arguments
+ if (methodSymbol.Parameters.Length == 0 || invoke.ArgumentList.Arguments.Count == 0)
+ {
+ return;
+ }
+
+ // Skip anything where the "to write" parameter isn't a variable length type
+ var param0 = methodSymbol.Parameters[0];
+ var isVariableLengthType = variableLengthTypes.Contains(param0.Type);
+ if (!isVariableLengthType)
+ {
+ return;
+ }
+
+ // If the syntax tree or semantic thinks is a constant, just roll with it - other analyzers will refine this further
+ var arg0 = invoke.ArgumentList.Arguments[0];
+ var isConstant = arg0.Expression is LiteralExpressionSyntax || context.SemanticModel.GetConstantValue(arg0, cancellation).HasValue;
+ if (isConstant)
+ {
+ return;
+ }
+
+ // Skip anything that references a CmdStrings property
+ if (arg0.Expression is MemberAccessExpressionSyntax argMemberAccess)
+ {
+ var leftType = context.SemanticModel.GetSymbolInfo(argMemberAccess.Expression);
+ var rightType = context.SemanticModel.GetSymbolInfo(argMemberAccess.Name);
+ if (leftType.Symbol is INamedTypeSymbol type && SymbolEqualityComparer.Default.Equals(type, cmdStringsType) && rightType.Symbol is IPropertySymbol)
+ {
+ return;
+ }
+ }
+
+ // Raise the diagnostic, based on whether we have an existing override to use
+ Diagnostic diag;
+ if (largeEquivLookup.TryGetValue(methodName.Identifier.Text, out var largeMtdToUse))
+ {
+ diag = Diagnostic.Create(UseLargeOverridesWithVariableSizeResponses, methodName.GetLocation(), largeMtdToUse, methodName.Identifier.Text);
+ }
+ else
+ {
+ var largeEquivMtdName = $"WriteLarge{methodName.Identifier.Text.Substring("Write".Length)}";
+
+ diag = Diagnostic.Create(AddLargeOverridesForVariableSizeResponses, methodName.GetLocation(), largeEquivMtdName, methodName.Identifier.Text);
+ }
+
+ context.ReportDiagnostic(diag);
+ }
+
+ ///
+ /// Raises and if constants are used in WriteXXX methods which aren't on CmdStrings.
+ ///
+ private static void AnalyzeCallerForNonCmdStringsConstants(SyntaxNodeAnalysisContext context, INamedTypeSymbol cmdStringsType, INamedTypeSymbol respServerSession, Dictionary knownConstants, CancellationToken cancellation)
+ {
+ if (context.Node is not InvocationExpressionSyntax invoke)
+ {
+ return;
+ }
+
+ if (invoke.Expression is not IdentifierNameSyntax methodName)
+ {
+ return;
+ }
+
+ // Quickly filter out anything that doesn't look like a plain Write method
+ if (string.IsNullOrEmpty(methodName.Identifier.Text) || !methodName.Identifier.Text.StartsWith("Write"))
+ {
+ return;
+ }
+
+ // Ignore anything that isn't a call to a method in RespServerSessionOutput.cs
+ var method = context.SemanticModel.GetSymbolInfo(methodName);
+ if (method.Symbol is not IMethodSymbol methodSymbol || !method.Symbol.DeclaringSyntaxReferences.Any(static decl => Path.GetFileName(decl.SyntaxTree.FilePath) == "RespServerSessionOutput.cs"))
+ {
+ return;
+ }
+
+ // Skip anything without parameters or arguments
+ if (methodSymbol.Parameters.Length == 0 || invoke.ArgumentList.Arguments.Count == 0)
+ {
+ return;
+ }
+
+ // If the first argument isn't a constant, ignore it
+ string literalStr;
+ var arg0 = invoke.ArgumentList.Arguments[0];
+ if (arg0.Expression is LiteralExpressionSyntax literal && literal.Kind() is SyntaxKind.StringLiteralExpression or SyntaxKind.Utf8StringLiteralExpression)
+ {
+ literalStr = literal.Token.Text;
+ }
+ else
+ {
+ var inferredConstant = context.SemanticModel.GetConstantValue(arg0.Expression, cancellation);
+ if (inferredConstant.HasValue && inferredConstant.Value is string constStr)
+ {
+ literalStr = $"\"{constStr}\"u8";
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ Diagnostic diag;
+ if (knownConstants.TryGetValue(literalStr, out var propertyName))
+ {
+ diag = Diagnostic.Create(UseExistingConstantInCmdStrings, arg0.GetLocation(), propertyName);
+ }
+ else
+ {
+ diag = Diagnostic.Create(MoveOutputConstantsToCmdStrings, arg0.GetLocation(), literalStr);
+ }
+
+ context.ReportDiagnostic(diag);
+ }
+
+ ///
+ /// Checks for constants in CmdStrings that exceed CmdStrings.MaximumConstantSize in bytes.
+ ///
+ /// Constants that start with a RESP sigil are assumed to be literal, everything else is treated like a Bulk String.
+ ///
+ private static void AnalyzeDeclarationForTooLargeCmdStringConstants(SyntaxNodeAnalysisContext context, INamedTypeSymbol cmdStringsType, Dictionary constantLookup)
+ {
+ if (context.Node is not ClassDeclarationSyntax classDecl)
+ {
+ return;
+ }
+
+ // Quick check for CmdStrings name
+ if (classDecl.Identifier.Text != "CmdStrings")
+ {
+ return;
+ }
+
+ // Check for CmdStrings type
+ var declType = context.SemanticModel.GetDeclaredSymbol(classDecl);
+ if (declType is null || !SymbolEqualityComparer.Default.Equals(cmdStringsType, declType))
+ {
+ return;
+ }
+
+ // Get the MaximumConstantSize property
+ var maximumConstantSizeDecl = classDecl.Members.OfType().SingleOrDefault(static propDecl => propDecl.Identifier.Text == "MaximumConstantSize");
+ if (maximumConstantSizeDecl is null)
+ {
+ return;
+ }
+
+ // Get MaximumConstantSize literal value
+ var getDeclSyntax = maximumConstantSizeDecl.ExpressionBody;
+ if (getDeclSyntax is not ArrowExpressionClauseSyntax arrowDecl)
+ {
+ return;
+ }
+
+ if (arrowDecl.Expression is not LiteralExpressionSyntax literal)
+ {
+ return;
+ }
+
+ var maximumSizeLit = context.SemanticModel.GetConstantValue(literal);
+ if (!maximumSizeLit.HasValue)
+ {
+ return;
+ }
+
+ var maximumSize = (int)maximumSizeLit.Value;
+
+ // Consider all found constaints and calculate their effective length
+ foreach (var kv in constantLookup)
+ {
+ var lit = kv.Key;
+ var prop = kv.Value;
+
+ if (!string.IsNullOrEmpty(lit) && lit[0] == '"')
+ {
+ lit = lit.Substring(1);
+ }
+
+ if (!string.IsNullOrEmpty(lit) && lit.EndsWith("u8"))
+ {
+ lit = lit.Substring(0, lit.Length - 2);
+ }
+
+ if (!string.IsNullOrEmpty(lit) && lit[lit.Length - 1] == '"')
+ {
+ lit = lit.Substring(0, lit.Length - 1);
+ }
+
+ // Skip empty
+ if (string.IsNullOrEmpty(lit))
+ {
+ continue;
+ }
+
+ var maybeSigil = lit[0];
+ var isRespEncoded = maybeSigil is '+' or '-' or ':' or '$' or '*' or '_' or '#' or ',' or '(' or '!' or '=' or '%' or '|' or '~' or '>';
+
+ int effectiveLength;
+ if (isRespEncoded)
+ {
+ effectiveLength = lit.Replace("\\", "").Length;
+ }
+ else
+ {
+ // Assume Bulk String: $\r\n\r\n
+ var rawLength = lit.Replace("\\", "").Length;
+ effectiveLength = 1 + CountDigits(rawLength) + 2 + rawLength + 2;
+ }
+
+ if (effectiveLength > maximumSize)
+ {
+ var decl = classDecl.Members.OfType().FirstOrDefault(p => p.Identifier.Text == prop);
+
+ if (decl is not null)
+ {
+ var diag = Diagnostic.Create(CmdStringsConstantTooLarge, decl.GetLocation(), prop, effectiveLength, maximumSize);
+ context.ReportDiagnostic(diag);
+ }
+ }
+ }
+
+ // Figure out space needed to serialize a Bulk String length
+ static int CountDigits(int value)
+ {
+ value = value < 0 ? ((~value) + 1) : value;
+
+ if (value < 10) return 1;
+ if (value < 100) return 2;
+ if (value < 1000) return 3;
+ if (value < 100000000L)
+ {
+ if (value < 1000000)
+ {
+ if (value < 10000) return 4;
+ return 5 + (value >= 100000 ? 1 : 0);
+ }
+ return 7 + (value >= 10000000L ? 1 : 0);
+ }
+ return 9 + (value >= 1000000000L ? 1 : 0);
+ }
+ }
+ }
+}
diff --git a/libs/common/RespWriteUtils.cs b/libs/common/RespWriteUtils.cs
index a953eb82637..df4f1155e7a 100644
--- a/libs/common/RespWriteUtils.cs
+++ b/libs/common/RespWriteUtils.cs
@@ -94,6 +94,9 @@ public static bool TryWriteSetLength(int len, ref byte* curr, byte* end)
return true;
}
+ ///
+ /// Writes an array length
+ ///
public static bool TryWriteArrayLength(int len, ref byte* curr, byte* end, out int numDigits, out int totalLen)
{
numDigits = NumUtils.CountDigits(len);
@@ -761,6 +764,34 @@ public static bool TryWriteVerbatimString(ReadOnlySpan str, ReadOnlySpan
+ /// Write verbtatim string header.
+ ///
+ /// That is ={len}\r\n{ext}:
+ ///
+ public static bool TryWriteVerbatimStringHeader(ReadOnlySpan str, ReadOnlySpan ext, ref byte* curr, byte* end)
+ {
+ Debug.Assert(ext.Length == 3);
+
+ // Verbatim string length includes the type metadata.
+ // So ext (3 bytes) + ':' (1 byte separator) + str
+ var actualLength = 3 + 1 + str.Length;
+ var itemDigits = NumUtils.CountDigits(actualLength);
+
+ var headerLen = 1 + itemDigits + 2 + 3 + 1;
+ if (headerLen > (int)(end - curr))
+ return false;
+
+ *curr++ = (byte)'=';
+ NumUtils.WriteInt32(actualLength, itemDigits, ref curr);
+ WriteNewline(ref curr);
+ ext.CopyTo(new Span(curr, 3));
+ curr += 3;
+ *curr++ = (byte)':';
+
+ return true;
+ }
+
///
/// Write RESP3 true
///
@@ -821,13 +852,18 @@ public static bool TryWriteOne(ref byte* curr, byte* end)
public static void WriteEtagValArray(long etag, ref ReadOnlySpan value, ref byte* curr, byte* end, bool writeDirect)
{
// Writes a Resp encoded Array of Integer for ETAG as first element, and bulk string for value as second element
- RespWriteUtils.TryWriteArrayLength(2, ref curr, end);
- RespWriteUtils.TryWriteInt64(etag, ref curr, end);
+ var res = TryWriteArrayLength(2, ref curr, end);
+ Debug.Assert(res, "Caller should have ensured buffer is sufficiently large");
+
+ res = TryWriteInt64(etag, ref curr, end);
+ Debug.Assert(res, "Caller should have ensured buffer is sufficiently large");
if (writeDirect)
- RespWriteUtils.TryWriteDirect(value, ref curr, end);
+ res = TryWriteDirect(value, ref curr, end);
else
- RespWriteUtils.TryWriteBulkString(value, ref curr, end);
+ res = TryWriteBulkString(value, ref curr, end);
+
+ Debug.Assert(res, "Caller should have ensured buffer is sufficiently large");
}
///
diff --git a/libs/server/ArgSlice/ScratchBufferBuilder.cs b/libs/server/ArgSlice/ScratchBufferBuilder.cs
index 5decbd1e221..3630f399c58 100644
--- a/libs/server/ArgSlice/ScratchBufferBuilder.cs
+++ b/libs/server/ArgSlice/ScratchBufferBuilder.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+#pragma warning disable GARNET0001 // This manually manages a buffer, so calls to RespWriteUtils are fine
+
using System;
using System.Diagnostics;
using System.Numerics;
diff --git a/libs/server/Custom/CustomProcedureBase.cs b/libs/server/Custom/CustomProcedureBase.cs
index 5e18e42971c..3ba768088e0 100644
--- a/libs/server/Custom/CustomProcedureBase.cs
+++ b/libs/server/Custom/CustomProcedureBase.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
+#pragma warning disable GARNET0001 // This manually manages a buffer, so calls to RespWriteUtils are fine
+
using System;
using System.Buffers;
using System.Collections.Generic;
diff --git a/libs/server/Custom/CustomRespCommands.cs b/libs/server/Custom/CustomRespCommands.cs
index 3b97d3c5e5a..dff0f223bf6 100644
--- a/libs/server/Custom/CustomRespCommands.cs
+++ b/libs/server/Custom/CustomRespCommands.cs
@@ -35,8 +35,7 @@ private bool TryTransactionProc(byte id, CustomTransactionProcedure proc, int st
if (output.MemoryOwner != null)
SendAndReset(output.MemoryOwner, output.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -45,8 +44,7 @@ private bool TryTransactionProc(byte id, CustomTransactionProcedure proc, int st
if (output.MemoryOwner != null)
SendAndReset(output.MemoryOwner, output.Length);
else
- while (!RespWriteUtils.TryWriteError($"ERR Transaction failed.", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_transaction_failed);
}
LatencyMetrics?.Stop(LatencyMetricsType.TX_PROC_LAT);
@@ -72,16 +70,14 @@ private void TryCustomProcedure(CustomProcedure proc, int startIdx = 0)
if (output.MemoryOwner != null)
SendAndReset(output.MemoryOwner, output.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
if (output.MemoryOwner != null)
SendAndReset(output.MemoryOwner, output.Length);
else
- while (!RespWriteUtils.TryWriteError($"ERR Command failed.", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_command_failed);
}
}
@@ -106,8 +102,7 @@ private bool TryCustomRawStringCommand(RespCommand cmd, long expirat
if (output.Memory != null)
SendAndReset(output.Memory, output.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -119,8 +114,7 @@ private bool TryCustomRawStringCommand(RespCommand cmd, long expirat
if (output.Memory != null)
SendAndReset(output.Memory, output.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -157,15 +151,13 @@ private bool TryCustomObjectCommand(GarnetObjectType objType, byte s
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
if (output.SpanByteAndMemory.Memory != null)
SendAndReset(output.SpanByteAndMemory.Memory, output.SpanByteAndMemory.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
}
}
@@ -180,16 +172,14 @@ private bool TryCustomObjectCommand(GarnetObjectType objType, byte s
if (output.SpanByteAndMemory.Memory != null)
SendAndReset(output.SpanByteAndMemory.Memory, output.SpanByteAndMemory.Length);
else
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
case GarnetStatus.NOTFOUND:
Debug.Assert(output.SpanByteAndMemory.Memory == null);
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
}
diff --git a/libs/server/Garnet.server.csproj b/libs/server/Garnet.server.csproj
index de66b80f463..820bfa87a3b 100644
--- a/libs/server/Garnet.server.csproj
+++ b/libs/server/Garnet.server.csproj
@@ -8,6 +8,7 @@
+
@@ -23,7 +24,7 @@
-
+
\ No newline at end of file
diff --git a/libs/server/Lua/LuaCommands.cs b/libs/server/Lua/LuaCommands.cs
index 07d6dcd41ab..b92dcc4b401 100644
--- a/libs/server/Lua/LuaCommands.cs
+++ b/libs/server/Lua/LuaCommands.cs
@@ -73,8 +73,7 @@ private unsafe bool TryEVALSHA()
if (runner == null)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NO_SCRIPT, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NO_SCRIPT);
}
else
{
@@ -163,8 +162,7 @@ private unsafe bool TryEVAL()
if (runner == null)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NO_SCRIPT, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NO_SCRIPT);
}
else
{
@@ -199,8 +197,7 @@ private bool NetworkScriptExists()
// Returns an array where each element is a 0 if the script does not exist, and a 1 if it does
- while (!RespWriteUtils.TryWriteArrayLength(parseState.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(parseState.Count);
for (var shaIx = 0; shaIx < parseState.Count; shaIx++)
{
@@ -217,8 +214,7 @@ private bool NetworkScriptExists()
exists = storeWrapper.storeScriptCache.ContainsKey(sha1Arg) ? 1 : 0;
}
- while (!RespWriteUtils.TryWriteInt32(exists, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(exists);
}
return true;
@@ -265,8 +261,7 @@ private bool NetworkScriptFlush()
}
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -324,8 +319,7 @@ private bool NetworkScriptLoad()
}
}
- while (!RespWriteUtils.TryWriteBulkString(digest, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(digest);
}
return true;
@@ -340,8 +334,7 @@ private bool CheckLuaEnabled()
{
if (!storeWrapper.serverOptions.EnableLua)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_LUA_DISABLED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_LUA_DISABLED);
return false;
}
@@ -364,8 +357,7 @@ private bool TryExecuteScript(int count, LuaRunner scriptRunner)
catch (Exception ex)
{
logger?.LogError(ex, "Error executing Lua script");
- while (!RespWriteUtils.TryWriteError("ERR " + ex.Message, ref dcurr, dend))
- SendAndReset();
+ WriteError(ex);
// Exceptions shouldn't happen, so if they did the runner is probably in a bad state
return false;
diff --git a/libs/server/Lua/LuaRunner.Functions.cs b/libs/server/Lua/LuaRunner.Functions.cs
index e5b36a83dd8..9320d0e5da0 100644
--- a/libs/server/Lua/LuaRunner.Functions.cs
+++ b/libs/server/Lua/LuaRunner.Functions.cs
@@ -3084,8 +3084,7 @@ private unsafe int CompileCommon(nint luaState, ref TResponse resp)
_ = state.RawGetInteger(LuaType.Function, (int)LuaRegistry.Index, loadSandboxedRegistryIndex);
if (!state.TryPushBuffer(source.Span))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.LUA_out_of_memory, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError(CmdStrings.LUA_out_of_memory);
return 0;
}
@@ -3105,8 +3104,7 @@ private unsafe int CompileCommon(nint luaState, ref TResponse resp)
if (!state.TryRef(out functionRegistryIndex))
{
// Uh-oh, couldn't save the function under the registry
- while (!RespWriteUtils.TryWriteError(CmdStrings.LUA_out_of_memory, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError(CmdStrings.LUA_out_of_memory);
return 0;
}
@@ -3125,8 +3123,7 @@ private unsafe int CompileCommon(nint luaState, ref TResponse resp)
errStr = "Compilation error, cause unknown";
}
- while (!RespWriteUtils.TryWriteError(errStr, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError(Encoding.UTF8.GetBytes(errStr));
}
return 0;
diff --git a/libs/server/Lua/LuaRunner.cs b/libs/server/Lua/LuaRunner.cs
index cd5aea8dc2c..be83ba24f0d 100644
--- a/libs/server/Lua/LuaRunner.cs
+++ b/libs/server/Lua/LuaRunner.cs
@@ -47,6 +47,16 @@ private unsafe interface IResponseAdapter
/// Equivalent to .
///
void SendAndReset();
+
+ ///
+ /// Equivalent to .
+ ///
+ void WriteError(ReadOnlySpan error);
+
+ ///
+ /// Equivalent to .
+ ///
+ void WriteDirect(ReadOnlySpan data);
}
///
@@ -77,6 +87,14 @@ public byte RespProtocolVersion
///
public void SendAndReset()
=> session.SendAndReset();
+
+ ///
+ public void WriteError(ReadOnlySpan error)
+ => session.WriteError(error);
+
+ ///
+ public void WriteDirect(ReadOnlySpan data)
+ => session.WriteDirect(data);
}
///
@@ -143,6 +161,27 @@ public void SendAndReset()
BufferEnd = origin + scratchSpace.Length;
curHead = origin + len;
}
+
+#pragma warning disable GARNET0001 // These methods manually manage a buffer, so must directly use RespWriteUtils
+
+ ///
+ public void WriteError(ReadOnlySpan error)
+ {
+ while (!RespWriteUtils.TryWriteError(error, ref BufferCur, BufferEnd))
+ {
+ SendAndReset();
+ }
+ }
+
+ ///
+ public void WriteDirect(ReadOnlySpan data)
+ {
+ while (!RespWriteUtils.TryWriteDirect(data, ref BufferCur, BufferEnd))
+ {
+ SendAndReset();
+ }
+ }
+#pragma warning restore GARNET0001
}
private static (int Start, ulong[] ByteMask) NoScriptDetails = InitializeNoScriptDetails();
@@ -468,8 +507,7 @@ public unsafe bool CompileForSession(RespServerSession session)
var res = state.PCall(0, 0);
if (res != LuaStatus.OK)
{
- while (!RespWriteUtils.TryWriteError("Internal Lua Error"u8, ref session.dcurr, session.dend))
- session.SendAndReset();
+ session.WriteError("Internal Lua Error"u8);
return false;
}
@@ -1156,8 +1194,7 @@ public unsafe void RunForSession(int count, RespServerSession outerSession)
err = "Internal Lua Error"u8;
}
- while (!RespWriteUtils.TryWriteError(err, ref outerSession.dcurr, outerSession.dend))
- outerSession.SendAndReset();
+ outerSession.WriteError(err);
return;
}
@@ -1503,8 +1540,7 @@ private unsafe void RunCommon(ref TResponse resp)
if (state.StackTop == 0)
{
- while (!RespWriteUtils.TryWriteError("ERR An error occurred while invoking a Lua script"u8, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError("ERR An error occurred while invoking a Lua script"u8);
return;
}
@@ -1516,22 +1552,18 @@ private unsafe void RunCommon(ref TResponse resp)
if (errBuf.Length >= 4 && MemoryMarshal.Read("ERR "u8) == Unsafe.As(ref MemoryMarshal.GetReference(errBuf)))
{
// Response came back with a ERR, already - just pass it along
- while (!RespWriteUtils.TryWriteError(errBuf, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError(errBuf);
}
else
{
// Otherwise, this is probably a Lua error - and those aren't very descriptive
// So slap some more information in
- while (!RespWriteUtils.TryWriteDirect("-ERR Lua encountered an error: "u8, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteDirect("-ERR Lua encountered an error: "u8);
- while (!RespWriteUtils.TryWriteDirect(errBuf, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteDirect(errBuf);
- while (!RespWriteUtils.TryWriteDirect("\r\n"u8, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteDirect("\r\n"u8);
}
state.Pop(1);
@@ -1542,8 +1574,7 @@ private unsafe void RunCommon(ref TResponse resp)
{
logger?.LogError("Got an unexpected number of values back from a pcall error {callRes}", callRes);
- while (!RespWriteUtils.TryWriteError("ERR Unexpected error response"u8, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError("ERR Unexpected error response"u8);
state.ClearStack();
@@ -1648,8 +1679,7 @@ private unsafe void WriteResponse(ref TResponse resp)
state.PushConstantString(err);
state.KnownStringToBuffer(1, out var errBuff);
- while (!RespWriteUtils.TryWriteError(errBuff, ref resp.BufferCur, resp.BufferEnd))
- resp.SendAndReset();
+ resp.WriteError(errBuff);
return;
}
@@ -1944,8 +1974,10 @@ static bool TryWriteSingleItem(LuaRunner runner, bool canSend, ref TResponse res
return true;
}
+#pragma warning disable GARNET0001 // These methods have to track extra state, and so can directly use RespWriteUtils
+
// Write out $-1\r\n (the RESP2 null) and (optionally) pop the null value off the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteResp2Null(LuaRunner runner, bool canSend, bool pop, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteResp2Null(LuaRunner runner, bool canSend, bool pop, ref TResponse resp, out int errConstStrIndex)
{
var fitInBuffer = true;
@@ -1973,7 +2005,7 @@ static unsafe bool TryWriteResp2Null(LuaRunner runner, bool canSend, bool pop, r
}
// Write out _\r\n (the RESP3 null) and (optionally) pop the null value off the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteResp3Null(LuaRunner runner, bool canSend, bool pop, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteResp3Null(LuaRunner runner, bool canSend, bool pop, ref TResponse resp, out int errConstStrIndex)
{
var fitInBuffer = true;
@@ -2001,7 +2033,7 @@ static unsafe bool TryWriteResp3Null(LuaRunner runner, bool canSend, bool pop, r
}
// Writes the number on the top of the stack, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteNumber(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteNumber(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Number, "Number was not on top of stack");
@@ -2033,7 +2065,7 @@ static unsafe bool TryWriteNumber(LuaRunner runner, bool canSend, ref TResponse
}
// Writes the string on the top of the stack, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteString(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteString(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
runner.state.KnownStringToBuffer(runner.state.StackTop, out var buf);
@@ -2107,7 +2139,7 @@ static unsafe bool TryWriteString(LuaRunner runner, bool canSend, ref TResponse
}
// Writes the boolean on the top of the stack, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteResp3Boolean(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteResp3Boolean(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Boolean, "Boolean was not on top of stack");
@@ -2154,7 +2186,7 @@ static unsafe bool TryWriteResp3Boolean(LuaRunner runner, bool canSend, ref TRes
}
// Writes the number on the top of the stack as a double, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteDouble(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteDouble(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Number, "Number was not on top of stack");
@@ -2183,7 +2215,7 @@ static unsafe bool TryWriteDouble(LuaRunner runner, bool canSend, ref TResponse
}
// Write a table on the top of the stack as a map, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteMap(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteMap(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Table, "Table was not on top of stack");
@@ -2268,7 +2300,7 @@ static unsafe bool TryWriteMap(LuaRunner runner, bool canSend, ref TResponse res
}
// Convert a table to an array, where each key-value pair is converted to 2 entries, returning true if all fit in the current send buffer
- static unsafe bool TryWriteMapToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteMapToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Table, "Table was not on top of stack");
@@ -2352,7 +2384,7 @@ static unsafe bool TryWriteMapToArray(LuaRunner runner, bool canSend, ref TRespo
}
// Write a table on the top of the stack as a set, removes it from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteSet(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteSet(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Table, "Table was not on top of stack");
@@ -2428,7 +2460,7 @@ static unsafe bool TryWriteSet(LuaRunner runner, bool canSend, ref TResponse res
// Write a table on the top of the stack as an array that contains only the keys of the
// table, then remove the table from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteSetToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteSetToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Table, "Table was not on top of stack");
@@ -2505,7 +2537,7 @@ static unsafe bool TryWriteSetToArray(LuaRunner runner, bool canSend, ref TRespo
}
// Writes the string on the top of the stack out as an error, removes the string from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteError(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteError(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
runner.state.KnownStringToBuffer(runner.state.StackTop, out var errBuff);
@@ -2532,7 +2564,7 @@ static unsafe bool TryWriteError(LuaRunner runner, bool canSend, ref TResponse r
}
// Writes the table on the top of the stack out as an array, removed table from the stack, returning true if all fit in the current send buffer
- static unsafe bool TryWriteTableToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
+ static bool TryWriteTableToArray(LuaRunner runner, bool canSend, ref TResponse resp, out int errConstStrIndex)
{
// Redis does not respect metatables, so RAW access is ok here
Debug.Assert(runner.state.Type(runner.state.StackTop) == LuaType.Table, "Table was not on top of stack");
@@ -2599,6 +2631,7 @@ static unsafe bool TryWriteTableToArray(LuaRunner runner, bool canSend, ref TRes
errConstStrIndex = -1;
return fitInBuffer;
}
+#pragma warning restore GARNET0001
}
///
diff --git a/libs/server/Metrics/Info/InfoCommand.cs b/libs/server/Metrics/Info/InfoCommand.cs
index 0722fdd3b9e..23bdadc56f8 100644
--- a/libs/server/Metrics/Info/InfoCommand.cs
+++ b/libs/server/Metrics/Info/InfoCommand.cs
@@ -48,8 +48,7 @@ private bool NetworkINFO()
if (invalid)
{
- while (!RespWriteUtils.TryWriteError($"ERR Invalid section {invalidSection}. Try INFO HELP", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Invalid section {invalidSection}. Try INFO HELP");
return true;
}
@@ -61,8 +60,7 @@ private bool NetworkINFO()
{
if (storeWrapper.monitor != null)
storeWrapper.monitor.resetEventFlags[InfoMetricsType.STATS] = true;
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -71,12 +69,11 @@ private bool NetworkINFO()
var info = garnetInfo.GetRespInfo(sectionsArr, activeDbId, storeWrapper);
if (!string.IsNullOrEmpty(info))
{
- WriteVerbatimString(Encoding.ASCII.GetBytes(info));
+ WriteLargeVerbatimString(Encoding.ASCII.GetBytes(info));
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTY, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTY);
}
}
return true;
@@ -86,12 +83,10 @@ private bool NetworkINFO()
private void GetHelpMessage()
{
List sectionsHelp = InfoHelp.GetInfoTypeHelpMessage();
- while (!RespWriteUtils.TryWriteArrayLength(sectionsHelp.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(sectionsHelp.Count);
foreach (var sectionInfo in sectionsHelp)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(sectionInfo, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(sectionInfo);
}
}
}
diff --git a/libs/server/Metrics/Latency/RespLatencyCommands.cs b/libs/server/Metrics/Latency/RespLatencyCommands.cs
index d786fd8e083..b9db7b5edd9 100644
--- a/libs/server/Metrics/Latency/RespLatencyCommands.cs
+++ b/libs/server/Metrics/Latency/RespLatencyCommands.cs
@@ -21,13 +21,11 @@ private bool NetworkLatencyHelp()
}
List latencyCommands = RespLatencyHelp.GetLatencyCommands();
- while (!RespWriteUtils.TryWriteArrayLength(latencyCommands.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(latencyCommands.Count);
foreach (string command in latencyCommands)
{
- while (!RespWriteUtils.TryWriteSimpleString(command, ref dcurr, dend))
- SendAndReset();
+ WriteLargeSimpleString(command);
}
return true;
@@ -65,15 +63,13 @@ private bool NetworkLatencyHistogram()
if (invalid)
{
- while (!RespWriteUtils.TryWriteError($"ERR Invalid event {invalidEvent}. Try LATENCY HELP", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Invalid event {invalidEvent}. Try LATENCY HELP");
}
else
{
var garnetLatencyMetrics = storeWrapper.monitor?.GlobalMetrics.globalLatencyMetrics;
string response = garnetLatencyMetrics != null ? garnetLatencyMetrics.GetRespHistograms(events) : "*0\r\n";
- while (!RespWriteUtils.TryWriteAsciiDirect(response, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiDirect(response);
}
return true;
@@ -111,8 +107,7 @@ private bool NetworkLatencyReset()
if (invalid)
{
- while (!RespWriteUtils.TryWriteError($"ERR Invalid type {invalidEvent}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Invalid type {invalidEvent}");
}
else
{
@@ -122,8 +117,7 @@ private bool NetworkLatencyReset()
storeWrapper.monitor.resetLatencyMetrics[e] = true;
}
- while (!RespWriteUtils.TryWriteInt32(events.Count, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(events.Count);
}
return true;
diff --git a/libs/server/Metrics/Slowlog/RespSlowlogCommands.cs b/libs/server/Metrics/Slowlog/RespSlowlogCommands.cs
index 8dc86db2ee7..634f0270bbc 100644
--- a/libs/server/Metrics/Slowlog/RespSlowlogCommands.cs
+++ b/libs/server/Metrics/Slowlog/RespSlowlogCommands.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-using Garnet.common;
using HdrHistogram;
namespace Garnet.server
@@ -24,13 +23,11 @@ private bool NetworkSlowLogHelp()
}
List slowLogCommands = RespSlowLogHelp.GetSlowLogCommands();
- while (!RespWriteUtils.TryWriteArrayLength(slowLogCommands.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(slowLogCommands.Count);
foreach (string command in slowLogCommands)
{
- while (!RespWriteUtils.TryWriteSimpleString(command, ref dcurr, dend))
- SendAndReset();
+ WriteLargeSimpleString(command);
}
return true;
@@ -58,31 +55,23 @@ private bool NetworkSlowLogGet()
if (storeWrapper.slowLogContainer == null)
{
- while (!RespWriteUtils.TryWriteArrayLength(0, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(0);
return true;
}
var entries = storeWrapper.slowLogContainer.GetEntries(count);
- while (!RespWriteUtils.TryWriteArrayLength(entries.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(entries.Count);
SessionParseState sps = default;
foreach (var entry in entries)
{
- while (!RespWriteUtils.TryWriteArrayLength(6, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32(entry.Id, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32(entry.Timestamp, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32(entry.Duration, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(6);
+ WriteInt32(entry.Id);
+ WriteInt32(entry.Timestamp);
+ WriteInt32(entry.Duration);
if (entry.Arguments == null)
{
- while (!RespWriteUtils.TryWriteArrayLength(1, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteAsciiBulkString(entry.Command.ToString(), ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(1);
+ WriteEnumAsBulkString(entry.Command);
}
else
{
@@ -91,20 +80,15 @@ private bool NetworkSlowLogGet()
{
sps.DeserializeFrom(ptr);
}
- while (!RespWriteUtils.TryWriteArrayLength(sps.Count + 1, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteAsciiBulkString(entry.Command.ToString(), ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(sps.Count + 1);
+ WriteEnumAsBulkString(entry.Command);
for (int i = 0; i < sps.Count; i++)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(sps.GetString(i), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(sps.GetArgSliceByRef(i).Span);
}
}
- while (!RespWriteUtils.TryWriteAsciiBulkString(entry.ClientIpPort, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteAsciiBulkString(entry.ClientName, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(entry.ClientIpPort);
+ WriteLargeAsciiBulkString(entry.ClientName);
}
return true;
}
@@ -119,8 +103,7 @@ private bool NetworkSlowLogLen()
{
return AbortWithWrongNumberOfArguments(nameof(RespCommand.SLOWLOG_LEN));
}
- while (!RespWriteUtils.TryWriteInt32(storeWrapper.slowLogContainer?.Count ?? 0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(storeWrapper.slowLogContainer?.Count ?? 0);
return true;
}
@@ -135,8 +118,7 @@ private bool NetworkSlowLogReset()
return AbortWithWrongNumberOfArguments(nameof(RespCommand.SLOWLOG_RESET));
}
storeWrapper.slowLogContainer?.Clear();
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
diff --git a/libs/server/Resp/ACLCommands.cs b/libs/server/Resp/ACLCommands.cs
index 216363d5b98..e6666843444 100644
--- a/libs/server/Resp/ACLCommands.cs
+++ b/libs/server/Resp/ACLCommands.cs
@@ -3,7 +3,6 @@
using System;
using System.Diagnostics;
-using Garnet.common;
using Garnet.server.ACL;
using Garnet.server.Auth;
using Garnet.server.Auth.Settings;
@@ -20,8 +19,7 @@ private bool ValidateACLAuthenticator()
{
if (_authenticator is null or not GarnetACLAuthenticator)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_ACL_AUTH_DISABLED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_ACL_AUTH_DISABLED);
return false;
}
return true;
@@ -31,16 +29,14 @@ private bool ValidateACLFileUse()
{
if (storeWrapper.serverOptions.AuthSettings is not AclAuthenticationSettings)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_ACL_AUTH_DISABLED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_ACL_AUTH_DISABLED);
return false;
}
var aclAuthenticationSettings = (AclAuthenticationSettings)storeWrapper.serverOptions.AuthSettings;
if (aclAuthenticationSettings.AclConfigurationFile == null)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_ACL_AUTH_FILE_DISABLED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_ACL_AUTH_FILE_DISABLED);
return false;
}
@@ -64,13 +60,11 @@ private bool NetworkAclList()
var aclAuthenticator = (GarnetACLAuthenticator)_authenticator;
var userHandles = aclAuthenticator.GetAccessControlList().GetUserHandles();
- while (!RespWriteUtils.TryWriteArrayLength(userHandles.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(userHandles.Count);
foreach (var userHandle in userHandles)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(userHandle.Value.User.DescribeUser(), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(userHandle.Value.User.DescribeUser());
}
return true;
@@ -93,13 +87,11 @@ private bool NetworkAclUsers()
var aclAuthenticator = (GarnetACLAuthenticator)_authenticator;
var users = aclAuthenticator.GetAccessControlList().GetUserHandles();
- while (!RespWriteUtils.TryWriteArrayLength(users.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(users.Count);
foreach (var user in users)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(user.Key, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(user.Key);
}
return true;
@@ -121,12 +113,11 @@ private bool NetworkAclCat()
return true;
var categories = ACLParser.ListCategories();
- RespWriteUtils.TryWriteArrayLength(categories.Count, ref dcurr, dend);
+ WriteArrayLength(categories.Count);
foreach (var category in categories)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(category, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(category);
}
return true;
@@ -198,14 +189,12 @@ private bool NetworkAclSetUser()
catch (ACLException exception)
{
// Abort command execution
- while (!RespWriteUtils.TryWriteError($"ERR {exception.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(exception);
return true;
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -246,15 +235,13 @@ private bool NetworkAclDelUser()
logger?.LogDebug("ACLException: {message}", exception.Message);
// Abort command execution
- while (!RespWriteUtils.TryWriteError($"ERR {exception.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(exception);
return true;
}
// Return the number of successful deletes
- while (!RespWriteUtils.TryWriteInt32(successfulDeletes, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(successfulDeletes);
return true;
}
@@ -279,7 +266,7 @@ private bool NetworkAclWhoAmI()
// Return the name of the currently authenticated user.
Debug.Assert(aclAuthenticator.GetUserHandle()?.User != null);
- WriteAsciiBulkString(aclAuthenticator.GetUserHandle().User.Name);
+ WriteLargeBulkString(aclAuthenticator.GetUserHandle().User.Name);
return true;
}
@@ -313,13 +300,11 @@ private bool NetworkAclLoad()
logger?.LogInformation("Reading updated ACL configuration file '{filepath}'", aclAuthenticationSettings.AclConfigurationFile);
storeWrapper.accessControlList.Load(aclAuthenticationSettings.DefaultPassword, aclAuthenticationSettings.AclConfigurationFile);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
catch (ACLException exception)
{
- while (!RespWriteUtils.TryWriteError($"ERR {exception.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(exception);
}
return true;
@@ -355,14 +340,12 @@ private bool NetworkAclSave()
catch (Exception ex)
{
logger?.LogError(ex, "ACL SAVE faulted");
- while (!RespWriteUtils.TryWriteError($"ERR {ex.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(ex);
return true;
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -396,7 +379,7 @@ private bool NetworkAclGenPass()
length = (int)(bits / 4) + (bits % 4 == 0 ? 0 : 1);
}
- WriteAsciiBulkString(System.Security.Cryptography.RandomNumberGenerator.GetHexString(length, true));
+ WriteLargeBulkString(System.Security.Cryptography.RandomNumberGenerator.GetHexString(length, true));
return true;
}
@@ -432,8 +415,7 @@ private bool NetworkAclGetUser()
catch (ACLException exception)
{
// Abort command execution
- while (!RespWriteUtils.TryWriteError($"ERR {exception.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(exception);
return true;
}
@@ -444,34 +426,37 @@ private bool NetworkAclGetUser()
}
else
{
- WriteMapLength(3);
-
- while (!RespWriteUtils.TryWriteAsciiBulkString("flags", ref dcurr, dend))
- SendAndReset();
-
- WriteSetLength(1);
+ if(respProtocolVersion == 3)
+ {
+ WriteDirect(CmdStrings.RESP_Map3_flags_Set1);
+ }
+ else
+ {
+ WriteDirect(CmdStrings.RESP_Array6_flags_Array1);
+ }
- while (!RespWriteUtils.TryWriteAsciiBulkString(user.IsEnabled ? "on" : "off", ref dcurr, dend))
- SendAndReset();
+ if (user.IsEnabled)
+ {
+ WriteBulkString(CmdStrings.on);
+ }
+ else
+ {
+ WriteBulkString(CmdStrings.off);
+ }
var passwords = user.Passwords;
- while (!RespWriteUtils.TryWriteAsciiBulkString("passwords", ref dcurr, dend))
- SendAndReset();
+ WriteBulkString(CmdStrings.passwords);
- while (!RespWriteUtils.TryWriteArrayLength(passwords.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(passwords.Count);
foreach (var password in passwords)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString($"#{password.ToString()}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString($"#{password.ToString()}");
}
- while (!RespWriteUtils.TryWriteAsciiBulkString("commands", ref dcurr, dend))
- SendAndReset();
+ WriteBulkString(CmdStrings.commands);
- while (!RespWriteUtils.TryWriteAsciiBulkString(user.GetEnabledCommandsDescription(), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(user.GetEnabledCommandsDescription());
}
return true;
diff --git a/libs/server/Resp/AdminCommands.cs b/libs/server/Resp/AdminCommands.cs
index f2e9b0f47a7..84fae95b070 100644
--- a/libs/server/Resp/AdminCommands.cs
+++ b/libs/server/Resp/AdminCommands.cs
@@ -32,8 +32,7 @@ private void ProcessAdminCommands(RespCommand command, ref TGarnetAp
if (_authenticator.CanAuthenticate && !_authenticator.IsAuthenticated)
{
// If the current session is unauthenticated, we stop parsing, because no other commands are allowed
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NOAUTH, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NOAUTH);
}
var cmdFound = true;
@@ -86,8 +85,7 @@ RespCommand.MIGRATE or
return;
}
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD);
}
///
@@ -176,8 +174,7 @@ private bool NetworkMonitor()
return AbortWithWrongNumberOfArguments(nameof(RespCommand.MONITOR));
}
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD);
return true;
}
@@ -510,13 +507,11 @@ private bool NetworkRegisterCs(CustomCommandManager customCommandManager)
if (errorMsg.IsEmpty &&
TryRegisterCustomCommands(binaryPaths, cmdInfoPath, cmdDocsPath, classNameToRegisterArgs, customCommandManager, out errorMsg))
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
- while (!RespWriteUtils.TryWriteError(errorMsg, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMsg);
}
return true;
@@ -555,7 +550,7 @@ private bool NetworkModuleLoad(CustomCommandManager customCommandManager)
{
if (!errorMsg.IsEmpty)
{
- WriteError(errorMsg);
+ WriteLargeError(errorMsg);
}
return true;
@@ -571,14 +566,13 @@ private bool NetworkModuleLoad(CustomCommandManager customCommandManager)
if (ModuleRegistrar.Instance.LoadModule(customCommandManager, assembliesList[0], moduleArgs, logger, out errorMsg))
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
}
if (!errorMsg.IsEmpty)
{
- WriteError(errorMsg);
+ WriteLargeError(errorMsg);
}
return true;
@@ -608,8 +602,7 @@ private bool NetworkCOMMITAOF()
// Have to block as we're on network thread
_ = AsyncUtils.BlockingWait(CommitAofAsync(dbId));
- while (!RespWriteUtils.TryWriteSimpleString("AOF file committed"u8, ref dcurr, dend))
- SendAndReset();
+ WriteSimpleString(CmdStrings.AOF_file_committed);
return true;
}
@@ -631,8 +624,7 @@ private bool NetworkFORCEGC()
}
GC.Collect(generation, GCCollectionMode.Forced, true);
- while (!RespWriteUtils.TryWriteSimpleString("GC completed"u8, ref dcurr, dend))
- SendAndReset();
+ WriteSimpleString(CmdStrings.GC_completed);
return true;
}
@@ -655,12 +647,10 @@ private bool NetworkHCOLLECT(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
default:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_HCOLLECT_ALREADY_IN_PROGRESS, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_HCOLLECT_ALREADY_IN_PROGRESS);
break;
}
@@ -685,12 +675,10 @@ private bool NetworkZCOLLECT(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
default:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_ZCOLLECT_ALREADY_IN_PROGRESS, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_ZCOLLECT_ALREADY_IN_PROGRESS);
break;
}
@@ -734,7 +722,7 @@ private bool NetworkDebug()
nameof(RespCommand.DEBUG));
}
- WriteError(parseState.GetString(1));
+ WriteLargeError(parseState.GetArgSliceByRef(1).Span);
return true;
}
@@ -771,12 +759,12 @@ private bool NetworkDebug()
WriteArrayLength(help.Length);
foreach (var line in help)
{
- WriteSimpleString(line);
+ WriteLargeSimpleString(line);
}
return true;
}
- WriteError(string.Format(CmdStrings.GenericErrUnknownSubCommand, parseState.GetString(0), nameof(RespCommand.DEBUG)));
+ WriteLargeError(string.Format(CmdStrings.GenericErrUnknownSubCommand, parseState.GetString(0), nameof(RespCommand.DEBUG)));
return true;
}
@@ -789,17 +777,7 @@ private bool NetworkROLE()
if (!storeWrapper.serverOptions.EnableCluster)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteAsciiBulkString("master", ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_master_0_EmptyArray);
}
else
{
@@ -807,51 +785,33 @@ private bool NetworkROLE()
{
var (replication_offset, replicaInfo) = storeWrapper.clusterProvider.GetPrimaryInfo();
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteAsciiBulkString("master", ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_master);
- while (!RespWriteUtils.TryWriteInt64(replication_offset, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(replication_offset);
- while (!RespWriteUtils.TryWriteArrayLength(replicaInfo.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(replicaInfo.Count);
foreach (var replice in replicaInfo)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteAsciiBulkString(replice.address, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32(replice.port, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt64(replice.replication_offset, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(3);
+ WriteLargeAsciiBulkString(replice.address);
+ WriteInt32(replice.port);
+ WriteInt64(replice.replication_offset);
}
}
else
{
var role = storeWrapper.clusterProvider.GetReplicaInfo();
- while (!RespWriteUtils.TryWriteArrayLength(5, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array5_slave);
- while (!RespWriteUtils.TryWriteAsciiBulkString("slave", ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(role.address);
- while (!RespWriteUtils.TryWriteAsciiBulkString(role.address, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(role.port);
- while (!RespWriteUtils.TryWriteInt32(role.port, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(role.replication_state);
- while (!RespWriteUtils.TryWriteAsciiBulkString(role.replication_state, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteInt64(role.replication_offset, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(role.replication_offset);
}
}
@@ -886,13 +846,11 @@ private bool NetworkSAVE()
if (!success)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_CHECKPOINT_ALREADY_IN_PROGRESS, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_CHECKPOINT_ALREADY_IN_PROGRESS);
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
return true;
@@ -929,14 +887,9 @@ private bool NetworkEXPDELSCAN()
// Resp Response Format => *2\r\n$NUM1\r\n$NUM2\r\n
int requiredSpace = 5 + NumUtils.CountDigits(recordsExpired) + 3 + NumUtils.CountDigits(recordsScanned) + 2;
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteArrayItem(recordsExpired, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteArrayItem(recordsScanned, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
+ WriteArrayItem(recordsExpired);
+ WriteArrayItem(recordsScanned);
return true;
}
@@ -966,8 +919,7 @@ private bool NetworkLASTSAVE()
Debug.Assert(dbFound);
var seconds = db.LastSaveTime.ToUnixTimeSeconds();
- while (!RespWriteUtils.TryWriteInt64(seconds, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(seconds);
return true;
}
@@ -1008,13 +960,11 @@ private bool NetworkBGSAVE()
if (success)
{
- while (!RespWriteUtils.TryWriteSimpleString("Background saving started"u8, ref dcurr, dend))
- SendAndReset();
+ WriteSimpleString(CmdStrings.Background_saving_started);
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_CHECKPOINT_ALREADY_IN_PROGRESS, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_CHECKPOINT_ALREADY_IN_PROGRESS);
}
return true;
@@ -1025,23 +975,20 @@ private bool TryParseDatabaseId(int tokenIdx, out int dbId)
dbId = -1;
if (!parseState.TryGetInt(tokenIdx, out dbId))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return false;
}
if (dbId > 0 && storeWrapper.serverOptions.EnableCluster)
{
// Cluster mode does not allow DBID specification
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_DB_ID_CLUSTER_MODE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_DB_ID_CLUSTER_MODE);
return false;
}
if (dbId >= storeWrapper.serverOptions.MaxDatabases || dbId < 0)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_DB_INDEX_OUT_OF_RANGE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_DB_INDEX_OUT_OF_RANGE);
return false;
}
diff --git a/libs/server/Resp/ArrayCommands.cs b/libs/server/Resp/ArrayCommands.cs
index 7ba2d976413..34ea9a63da5 100644
--- a/libs/server/Resp/ArrayCommands.cs
+++ b/libs/server/Resp/ArrayCommands.cs
@@ -21,8 +21,7 @@ private bool NetworkMGET(ref TGarnetApi storageApi)
where TGarnetApi : IGarnetApi
{
// Write array header
- while (!RespWriteUtils.TryWriteArrayLength(parseState.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(parseState.Count);
if (storeWrapper.serverOptions.EnableScatterGatherGet)
{
@@ -57,8 +56,7 @@ private bool NetworkMSET(ref TGarnetApi storageApi)
var val = parseState.GetArgSliceByRef(c + 1);
_ = storageApi.SET(key, val);
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -77,8 +75,7 @@ private bool NetworkMSETNX(ref TGarnetApi storageApi)
var status = storageApi.MSET_Conditional(ref input);
// For a "set if not exists", NOTFOUND means that the operation succeeded
- while (!RespWriteUtils.TryWriteInt32(status == GarnetStatus.NOTFOUND ? 1 : 0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(status == GarnetStatus.NOTFOUND ? 1 : 0);
return true;
}
@@ -96,8 +93,7 @@ private bool NetworkDEL(ref TGarnetApi storageApi)
keysDeleted++;
}
- while (!RespWriteUtils.TryWriteInt32(keysDeleted, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(keysDeleted);
return true;
}
@@ -131,15 +127,13 @@ private bool NetworkSELECT()
if (index == this.activeDbId || this.TrySwitchActiveDatabaseSession(index))
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
// Should never reach here
Debug.Fail("Database SELECT should have succeeded.");
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_SELECT_UNSUCCESSFUL, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_SELECT_UNSUCCESSFUL);
}
return true;
@@ -183,13 +177,11 @@ private bool NetworkSWAPDB()
if (storeWrapper.TrySwapDatabases(index1, index2))
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_SWAPDB_UNSUPPORTED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_SWAPDB_UNSUPPORTED);
}
return true;
@@ -203,8 +195,7 @@ private bool NetworkDBSIZE(ref TGarnetApi storageApi)
return AbortWithWrongNumberOfArguments(nameof(RespCommand.DBSIZE));
}
- while (!RespWriteUtils.TryWriteInt32(storageApi.GetDbSize(), ref dcurr, dend))
- SendAndReset();
+ WriteInt32(storageApi.GetDbSize());
return true;
}
@@ -225,20 +216,17 @@ private bool NetworkKEYS(ref TGarnetApi storageApi)
if (keys.Count > 0)
{
// Write size of the array
- while (!RespWriteUtils.TryWriteArrayLength(keys.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(keys.Count);
// Write the keys matching the pattern
foreach (var item in keys)
{
- while (!RespWriteUtils.TryWriteBulkString(item, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(item);
}
}
else
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
}
return true;
@@ -280,8 +268,7 @@ private bool NetworkSCAN(ref TGarnetApi storageApi)
// Validate count
if (!parseState.TryGetLong(tokenIdx++, out countValue))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
}
@@ -297,22 +284,15 @@ private bool NetworkSCAN(ref TGarnetApi storageApi)
// Prepare values for output
if (keys.Count == 0)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
-
- // Number of keys "0"
- while (!RespWriteUtils.TryWriteInt32AsBulkString(0, ref dcurr, dend))
- SendAndReset();
-
- // Empty array
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ // 2 element array
+ // - Number of keys = "0"
+ // - Empty array
+ WriteDirect(CmdStrings.RESP_Array2_0String_EmptyArray);
}
else
{
// The response is two elements: the value of the cursor and the array of keys found matching the pattern
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
if (keys.Count > 0)
WriteOutputForScan(cursor, keys);
@@ -334,13 +314,11 @@ private bool NetworkTYPE(ref TGarnetApi storageApi)
if (status == GarnetStatus.OK)
{
- while (!RespWriteUtils.TryWriteSimpleString(typeName, ref dcurr, dend))
- SendAndReset();
+ WriteLargeSimpleString(typeName);
}
else
{
- while (!RespWriteUtils.TryWriteSimpleString("none"u8, ref dcurr, dend))
- SendAndReset();
+ WriteSimpleString(CmdStrings.none);
}
return true;
@@ -355,17 +333,15 @@ private void WriteOutputForScan(long cursorValue, List keys)
{
// The output is an array of two elements: cursor value and an array of keys
// Note the cursor value should be formatted as bulk string ('$')
- while (!RespWriteUtils.TryWriteInt64AsBulkString(cursorValue, ref dcurr, dend, out _))
- SendAndReset();
+ WriteInt64AsBulkString(cursorValue);
// Write size of the array
- while (!RespWriteUtils.TryWriteArrayLength(keys.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(keys.Count);
// Write the keys matching the pattern
for (int i = 0; i < keys.Count; i++)
{
- WriteDirectLargeRespString(keys[i]);
+ WriteLargeBulkString(keys[i]);
}
}
@@ -383,7 +359,7 @@ private bool NetworkArrayPING()
}
var message = parseState.GetArgSliceByRef(0).ReadOnlySpan;
- WriteDirectLargeRespString(message);
+ WriteLargeBulkString(message);
return true;
}
diff --git a/libs/server/Resp/AsyncProcessor.cs b/libs/server/Resp/AsyncProcessor.cs
index a88fe0a534d..2166f5cb1c2 100644
--- a/libs/server/Resp/AsyncProcessor.cs
+++ b/libs/server/Resp/AsyncProcessor.cs
@@ -4,7 +4,6 @@
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
-using Garnet.common;
using Tsavorite.core;
namespace Garnet.server
@@ -50,8 +49,7 @@ void NetworkGETPending(ref TGarnetApi storageApi)
{
unsafe
{
- while (!RespWriteUtils.TryWriteError($"ASYNC {asyncStarted}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ASYNC {asyncStarted}");
}
if (++asyncStarted == 1) // first async operation on the session, create the IO continuation processor
@@ -104,12 +102,8 @@ async Task AsyncGetProcessorAsync(TGarnetApi storageApi)
var o = completedOutputs.Current.Output;
// We write async push response as an array: [ "async", "", "" ]
- while (!RespWriteUtils.TryWritePushLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(CmdStrings.async, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32AsBulkString((int)completedOutputs.Current.Context, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Push3_async);
+ WriteInt32AsBulkString((int)completedOutputs.Current.Context);
if (completedOutputs.Current.Status.Found)
{
Debug.Assert(!o.IsSpanByte);
diff --git a/libs/server/Resp/BasicCommands.cs b/libs/server/Resp/BasicCommands.cs
index 9d7778e8dcf..efe0cadfb39 100644
--- a/libs/server/Resp/BasicCommands.cs
+++ b/libs/server/Resp/BasicCommands.cs
@@ -102,8 +102,7 @@ bool NetworkGETEX(ref TGarnetApi storageApi)
break;
default:
- while (!RespWriteUtils.TryWriteError($"ERR Unsupported option {parseState.GetString(1)}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Unsupported option {parseState.GetString(1)}");
return true;
}
}
@@ -288,8 +287,7 @@ private bool NetworkSET(ref TGarnetApi storageApi)
storageApi.SET(key, value);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -333,8 +331,7 @@ private bool NetworkSetRange(ref TGarnetApi storageApi)
storageApi.SETRANGE(key, ref input, ref output);
- while (!RespWriteUtils.TryWriteIntegerFromBytes(outputBuffer.Slice(0, output.Length), ref dcurr, dend))
- SendAndReset();
+ WriteLargeIntegerFromBytes(outputBuffer.Slice(0, output.Length));
return true;
}
@@ -369,8 +366,7 @@ private bool NetworkGetRange(ref TGarnetApi storageApi)
{
sessionMetrics?.incr_total_notfound();
Debug.Assert(o.IsSpanByte);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTY, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTY);
}
return true;
@@ -405,8 +401,7 @@ private bool NetworkSETEX(bool highPrecision, ref TGarnetApi storage
var input = new RawStringInput(RespCommand.SETEX, 0, valMetadata);
_ = storageApi.SET(key, ref input, ref sbVal);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -429,8 +424,7 @@ private bool NetworkSETNX(bool highPrecision, ref TGarnetApi storage
// The status returned for SETNX as NOTFOUND is the expected status in the happy path
var retVal = status == GarnetStatus.NOTFOUND ? 1 : 0;
- while (!RespWriteUtils.TryWriteInt32(retVal, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(retVal);
return true;
}
@@ -559,8 +553,7 @@ private bool NetworkSETEXNX(ref TGarnetApi storageApi)
if (!errorMessage.IsEmpty)
{
- while (!RespWriteUtils.TryWriteError(errorMessage, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMessage);
return true;
}
@@ -606,8 +599,7 @@ private bool NetworkSETEXNX(ref TGarnetApi storageApi)
break;
}
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD);
return true;
}
@@ -627,8 +619,7 @@ private unsafe bool NetworkSET_EX(RespCommand cmd, ExpirationOption
storageApi.SET(key, ref input, ref val);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -654,8 +645,7 @@ private bool NetworkSET_Conditional(RespCommand cmd, int expiry, Arg
// KEEPTTL without flags doesn't care whether it was found or not.
if (cmd == RespCommand.SETKEEPTTL)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -667,8 +657,7 @@ private bool NetworkSET_Conditional(RespCommand cmd, int expiry, Arg
if (ok)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
@@ -743,8 +732,7 @@ private bool NetworkIncrement(RespCommand cmd, ref TGarnetApi storag
switch (errorFlag)
{
case OperationError.SUCCESS:
- while (!RespWriteUtils.TryWriteIntegerFromBytes(outputBuffer.Slice(0, output.Length), ref dcurr, dend))
- SendAndReset();
+ WriteLargeIntegerFromBytes(outputBuffer.Slice(0, output.Length));
break;
case OperationError.NAN_OR_INFINITY:
case OperationError.INVALID_TYPE:
@@ -782,8 +770,7 @@ private bool NetworkIncrementByFloat(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteBulkString(output.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(output.ReadOnlySpan);
break;
case GarnetStatus.WRONGTYPE:
default:
@@ -812,8 +799,7 @@ private bool NetworkAppend(ref TGarnetApi storageApi)
storageApi.APPEND(ref sbKey, ref input, ref output);
- while (!RespWriteUtils.TryWriteIntegerFromBytes(outputBuffer.Slice(0, output.Length), ref dcurr, dend))
- SendAndReset();
+ WriteLargeIntegerFromBytes(outputBuffer.Slice(0, output.Length));
return true;
}
@@ -825,13 +811,11 @@ private bool NetworkPING()
{
if (isSubscriptionSession && respProtocolVersion == 2)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.SUSCRIBE_PONG, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.SUSCRIBE_PONG);
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_PONG, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_PONG);
}
return true;
}
@@ -844,8 +828,7 @@ private bool NetworkASKING()
//*1\r\n$6\r\n ASKING\r\n = 16
if (storeWrapper.serverOptions.EnableCluster)
SessionAsking = 2;
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -854,8 +837,7 @@ private bool NetworkASKING()
///
private bool NetworkQUIT()
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
toDispose = true;
return true;
}
@@ -872,8 +854,7 @@ private bool NetworkFLUSHDB()
if (storeWrapper.serverOptions.EnableCluster && storeWrapper.clusterProvider.IsReplica() && !clusterSession.ReadWriteSession)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_FLUSHALL_READONLY_REPLICA, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_FLUSHALL_READONLY_REPLICA);
return true;
}
@@ -912,8 +893,7 @@ private bool NetworkREADONLY()
{
//*1\r\n$8\r\nREADONLY\r\n
clusterSession?.SetReadOnlySession();
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -925,8 +905,7 @@ private bool NetworkREADWRITE()
{
//*1\r\n$9\r\nREADWRITE\r\n
clusterSession?.SetReadWriteSession();
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -951,12 +930,10 @@ private bool NetworkSTRLEN(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(value.Length, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(value.Length);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(0);
break;
}
@@ -1017,8 +994,7 @@ private bool NetworkCOMMAND()
{
var subCommand = parseState.GetString(0);
var errorMsg = string.Format(CmdStrings.GenericErrUnknownSubCommand, subCommand, nameof(RespCommand.COMMAND));
- while (!RespWriteUtils.TryWriteError(errorMsg, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMsg);
}
else
{
@@ -1047,8 +1023,7 @@ private bool NetworkCOMMAND_COUNT()
var commandCount = customCommandManagerSession.GetCustomCommandInfoCount() + respCommandCount;
- while (!RespWriteUtils.TryWriteInt32(commandCount, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(commandCount);
return true;
}
@@ -1193,13 +1168,11 @@ private bool NetworkCOMMAND_GETKEYS()
var slicedParseState = parseState.Slice(simpleCmdInfo.IsSubCommand ? 2 : 1);
var keys = slicedParseState.ExtractCommandKeys(simpleCmdInfo);
- while (!RespWriteUtils.TryWriteArrayLength(keys.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(keys.Length);
foreach (var key in keys)
{
- while (!RespWriteUtils.TryWriteBulkString(key.Span, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(key.Span);
}
return true;
@@ -1230,24 +1203,20 @@ private bool NetworkCOMMAND_GETKEYSANDFLAGS()
var slicedParseState = parseState.Slice(simpleCmdInfo.IsSubCommand ? 2 : 1);
var keysAndFlags = slicedParseState.ExtractCommandKeysAndFlags(simpleCmdInfo);
- while (!RespWriteUtils.TryWriteArrayLength(keysAndFlags.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(keysAndFlags.Length);
for (var i = 0; i < keysAndFlags.Length; i++)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(keysAndFlags[i].Item1.Span, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(keysAndFlags[i].Item1.Span);
var flags = EnumUtils.GetEnumDescriptions(keysAndFlags[i].Item2);
WriteSetLength(flags.Length);
foreach (var flag in flags)
{
- while (!RespWriteUtils.TryWriteBulkString(Encoding.ASCII.GetBytes(flag), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(Encoding.ASCII.GetBytes(flag));
}
}
@@ -1262,7 +1231,7 @@ private bool NetworkECHO()
}
var message = parseState.GetArgSliceByRef(0).ReadOnlySpan;
- WriteDirectLargeRespString(message);
+ WriteLargeBulkString(message);
return true;
}
@@ -1337,8 +1306,7 @@ private bool NetworkHELLO()
if (errorMsg != default)
{
- while (!RespWriteUtils.TryWriteError(errorMsg, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMsg);
return true;
}
@@ -1359,8 +1327,7 @@ private bool NetworkTIME()
var uSeconds = utcTime.ToString("ffffff");
var response = $"*2\r\n${seconds.ToString().Length}\r\n{seconds}\r\n${uSeconds.Length}\r\n{uSeconds}\r\n";
- while (!RespWriteUtils.TryWriteAsciiDirect(response, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiDirect(response);
return true;
}
@@ -1390,28 +1357,24 @@ private bool NetworkAUTH()
// NOTE: Some authenticators cannot accept username/password pairs
if (!_authenticator.CanAuthenticate)
{
- while (!RespWriteUtils.TryWriteError("ERR Client sent AUTH, but configured authenticator does not accept passwords"u8, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_Client_sent_AUTH_no_pass);
return true;
}
// XXX: There should be high-level AuthenticatorException
if (this.AuthenticateUser(username, password))
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
if (username.IsEmpty)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_WRONGPASS_INVALID_PASSWORD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_WRONGPASS_INVALID_PASSWORD);
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_WRONGPASS_INVALID_USERNAME_PASSWORD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_WRONGPASS_INVALID_USERNAME_PASSWORD);
}
}
return true;
@@ -1454,8 +1417,7 @@ private bool NetworkMemoryUsage(ref TGarnetApi storageApi)
if (status == GarnetStatus.OK)
{
- while (!RespWriteUtils.TryWriteInt32((int)memoryUsage, ref dcurr, dend))
- SendAndReset();
+ WriteInt32((int)memoryUsage);
}
else
{
@@ -1511,14 +1473,12 @@ private bool NetworkASYNC()
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_SYNTAX_ERROR, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_SYNTAX_ERROR);
return true;
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -1584,23 +1544,17 @@ void ProcessHelloCommand(byte? respProtocolVersion, ReadOnlySpan username,
WriteMapLength(helloResult.Length + 1);
for (var i = 0; i < helloResult.Length; i++)
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(helloResult[i].Item1, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(helloResult[i].Item1);
if (helloResult[i].Item2 is long value)
{
- while (!RespWriteUtils.TryWriteInt64(value, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(value);
}
else
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(helloResult[i].Item2.ToString(), ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(helloResult[i].Item2.ToString());
}
}
- while (!RespWriteUtils.TryWriteAsciiBulkString("modules", ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_modules_EmptyArray);
}
///
@@ -1659,8 +1613,7 @@ void FlushDb(RespCommand cmd)
if (syntaxError)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_SYNTAX_ERROR, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_SYNTAX_ERROR);
return;
}
@@ -1670,8 +1623,7 @@ void FlushDb(RespCommand cmd)
ExecuteFlushDb(cmd, unsafeTruncateLog);
logger?.LogInformation($"Running {nameof(cmd)} {{async}} {{mode}}", async ? "async" : "sync", unsafeTruncateLog ? " with unsafetruncatelog." : string.Empty);
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
void ExecuteFlushDb(RespCommand cmd, bool unsafeTruncateLog)
diff --git a/libs/server/Resp/BasicEtagCommands.cs b/libs/server/Resp/BasicEtagCommands.cs
index 2fee440918d..9d7391e7177 100644
--- a/libs/server/Resp/BasicEtagCommands.cs
+++ b/libs/server/Resp/BasicEtagCommands.cs
@@ -103,8 +103,7 @@ private bool NetworkDELIFGREATER(ref TGarnetApi storageApi)
int keysDeleted = status == GarnetStatus.OK ? 1 : 0;
- while (!RespWriteUtils.TryWriteInt32(keysDeleted, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(keysDeleted);
return true;
}
@@ -208,8 +207,7 @@ private bool NetworkSetETagConditional(RespCommand cmd, ref TGarnetA
if (!errorMessage.IsEmpty)
{
- while (!RespWriteUtils.TryWriteError(errorMessage, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMessage);
return true;
}
diff --git a/libs/server/Resp/Bitmap/BitmapCommands.cs b/libs/server/Resp/Bitmap/BitmapCommands.cs
index 20600939332..23c7c2a659b 100644
--- a/libs/server/Resp/Bitmap/BitmapCommands.cs
+++ b/libs/server/Resp/Bitmap/BitmapCommands.cs
@@ -189,8 +189,7 @@ private bool NetworkStringGetBit(ref TGarnetApi storageApi)
var status = storageApi.StringGetBit(ref sbKey, ref input, ref o);
if (status == GarnetStatus.NOTFOUND)
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
else
dcurr += o.Length;
@@ -251,8 +250,7 @@ private bool NetworkStringBitCount(ref TGarnetApi storageApi)
}
else if (status == GarnetStatus.NOTFOUND)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
return true;
@@ -324,8 +322,7 @@ private bool NetworkStringBitPosition(ref TGarnetApi storageApi)
if (BitmapManager.TryValidateBitPosOffsets(startOffset, endOffset, offsetType, hasStartOffset, hasEndOffset))
{
- while (!RespWriteUtils.TryWriteInt64(-1, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(-1);
return true;
}
@@ -343,8 +340,7 @@ private bool NetworkStringBitPosition(ref TGarnetApi storageApi)
else if (status == GarnetStatus.NOTFOUND)
{
var resp = bSetValSlice[0] == '0' ? CmdStrings.RESP_RETURN_VAL_0 : CmdStrings.RESP_RETURN_VAL_N1;
- while (!RespWriteUtils.TryWriteDirect(resp, ref dcurr, dend))
- SendAndReset();
+ WriteLargeDirect(resp);
}
return true;
@@ -375,8 +371,7 @@ private bool NetworkStringBitOperation(BitmapOperation bitOp, ref TG
var input = new RawStringInput(RespCommand.BITOP, ref parseState);
_ = storageApi.StringBitOperation(ref input, bitOp, out var result);
- while (!RespWriteUtils.TryWriteInt64(result, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(result);
return true;
}
@@ -546,8 +541,7 @@ private bool StringBitFieldAction(ref TGarnetApi storageApi,
ArgSlice overflowTypeSlice = default)
where TGarnetApi : IGarnetApi
{
- while (!RespWriteUtils.TryWriteArrayLength(secondaryCommandArgs.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(secondaryCommandArgs.Count);
var input = new RawStringInput(cmd);
@@ -575,8 +569,7 @@ private bool StringBitFieldAction(ref TGarnetApi storageApi,
if (status == GarnetStatus.NOTFOUND && opCode == RespCommand.GET)
{
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(0);
}
else
{
diff --git a/libs/server/Resp/ClientCommands.cs b/libs/server/Resp/ClientCommands.cs
index 2264677a146..372ca0d5c59 100644
--- a/libs/server/Resp/ClientCommands.cs
+++ b/libs/server/Resp/ClientCommands.cs
@@ -160,7 +160,7 @@ private bool NetworkCLIENTLIST()
resultSb.Append("\n");
var result = resultSb.ToString();
- WriteVerbatimString(Encoding.ASCII.GetBytes(result));
+ WriteLargeVerbatimString(Encoding.ASCII.GetBytes(result));
return true;
}
@@ -194,7 +194,7 @@ private bool NetworkCLIENTINFO()
resultSb.Append("\n");
var result = resultSb.ToString();
- WriteVerbatimString(Encoding.ASCII.GetBytes(result));
+ WriteLargeVerbatimString(Encoding.ASCII.GetBytes(result));
return true;
}
@@ -226,16 +226,14 @@ private bool NetworkCLIENTKILL()
{
_ = session.TryKill();
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
}
}
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NO_SUCH_CLIENT, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NO_SUCH_CLIENT);
return true;
}
@@ -401,8 +399,7 @@ private bool NetworkCLIENTKILL()
}
// Hand back result, which is count of clients _actually_ killed
- while (!RespWriteUtils.TryWriteInt32(killed, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(killed);
return true;
}
@@ -505,8 +502,7 @@ private bool NetworkCLIENTGETNAME()
}
else
{
- while (!RespWriteUtils.TryWriteAsciiBulkString(this.clientName, ref dcurr, dend))
- SendAndReset();
+ WriteLargeAsciiBulkString(this.clientName);
}
return true;
@@ -529,8 +525,7 @@ private bool NetworkCLIENTSETNAME()
this.clientName = name;
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -560,8 +555,7 @@ private bool NetworkCLIENTSETINFO()
return AbortWithErrorMessage(CmdStrings.RESP_SYNTAX_ERROR);
}
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
@@ -605,8 +599,7 @@ private bool NetworkCLIENTUNBLOCK()
if (session is null)
{
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(0);
return true;
}
@@ -616,26 +609,22 @@ private bool NetworkCLIENTUNBLOCK()
if (!isBlocked)
{
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(0);
return true;
}
var result = observer.TryForceUnblock(toThrowError);
- while (!RespWriteUtils.TryWriteInt32(result ? 1 : 0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(result ? 1 : 0);
}
else
{
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(0);
}
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_UBLOCKING_CLINET, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_UBLOCKING_CLINET);
}
return true;
diff --git a/libs/server/Resp/CmdStrings.cs b/libs/server/Resp/CmdStrings.cs
index e8c5ba5fb9e..0bb10a4d032 100644
--- a/libs/server/Resp/CmdStrings.cs
+++ b/libs/server/Resp/CmdStrings.cs
@@ -10,6 +10,11 @@ namespace Garnet.server
///
static partial class CmdStrings
{
+ ///
+ /// Maximum size to allow - considered by the UseLargeOrConstantsForRespWritesAnalyzer.
+ ///
+ internal static int MaximumConstantSize => 512;
+
///
/// Request strings
///
@@ -531,5 +536,64 @@ static partial class CmdStrings
public static ReadOnlySpan LUA_KEYS => "KEYS"u8;
public static ReadOnlySpan LUA_ARGV => "ARGV"u8;
public static ReadOnlySpan EXPDELSCAN => "EXPDELSCAN"u8;
+ public static ReadOnlySpan master => "master"u8;
+ public static ReadOnlySpan slave => "slave"u8;
+ public static ReadOnlySpan ERR_transaction_failed => "ERR Transaction failed."u8;
+ public static ReadOnlySpan ERR_command_failed => "ERR Command failed."u8;
+ public static ReadOnlySpan flags => "flags"u8;
+ public static ReadOnlySpan passwords => "passwords"u8;
+ public static ReadOnlySpan commands => "commands"u8;
+ public static ReadOnlySpan AOF_file_committed => "AOF file committed"u8;
+ public static ReadOnlySpan GC_completed => "GC completed"u8;
+ public static ReadOnlySpan Background_saving_started => "Background saving started"u8;
+ public static ReadOnlySpan none => "none"u8;
+ public static ReadOnlySpan ERR_Client_sent_AUTH_no_pass => "ERR Client sent AUTH, but configured authenticator does not accept passwords"u8;
+ public static ReadOnlySpan modules => "modules"u8;
+ public static ReadOnlySpan ERR_RESTORE_currently_only_supports => "ERR RESTORE currently only supports string types"u8;
+ public static ReadOnlySpan ERR_DUMP_payload_version_or_checksum_wrong => "ERR DUMP payload version or checksum are wrong"u8;
+ public static ReadOnlySpan ERR_DUMP_payload_length_format_invalid => "ERR DUMP payload length format is invalid"u8;
+ public static ReadOnlySpan ERR_DUMP_payload_length_is_invalid => "ERR DUMP payload length is invalid"u8;
+ public static ReadOnlySpan ERR_NX_and_XX_GT_or_LT_not_compatible => "ERR NX and XX, GT or LT options at the same time are not compatible"u8;
+ public static ReadOnlySpan message => "message"u8;
+ public static ReadOnlySpan pmessage => "pmessage"u8;
+ public static ReadOnlySpan ERR_SUBSCRIBE_is_disabled => "ERR SUBSCRIBE is disabled, enable it with --pubsub option."u8;
+ public static ReadOnlySpan psubscribe => "psubscribe"u8;
+ public static ReadOnlySpan unsubscribe => "unsubscribe"u8;
+ public static ReadOnlySpan ERR_UNSUBSCRIBE_is_disabled => "ERR UNSUBSCRIBE is disabled, enable it with --pubsub option."u8;
+ public static ReadOnlySpan punsubscribe => "punsubscribe"u8;
+ public static ReadOnlySpan ERR_PUNSUBSCRIBE_is_disabled => "ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option."u8;
+ public static ReadOnlySpan ERR_Vector_exceeded_configured_page_size => "ERR Vector exceed configured page size"u8;
+ public static ReadOnlySpan ERR_Unsupported_quantization_type => "ERR Unsupported quantization type"u8;
+ public static ReadOnlySpan ERR_Element_not_in_Vector_Set => "ERR Element not in Vector Set"u8;
+ public static ReadOnlySpan ERR_Key_not_found => "ERR Key not found"u8;
+ public static ReadOnlySpan quant_type => "quant-type"u8;
+ public static ReadOnlySpan distance_metric => "distance-metric"u8;
+ public static ReadOnlySpan input_vector_dimensions => "input-vector-dimensions"u8;
+ public static ReadOnlySpan reduced_dimensions => "reduced-dimensions"u8;
+ public static ReadOnlySpan build_exploration_factor => "build-exploration-factor"u8;
+ public static ReadOnlySpan num_links => "num_links"u8;
+ public static ReadOnlySpan size => "size"u8;
+ public static ReadOnlySpan ERR_Vector_Set_partially_deleted => "ERR Vector Set is in a partially deleted state - re-execute DEL to complete deletion"u8;
+ public static ReadOnlySpan RESP_Map3_flags_Set1 => "%3\r\n$5\r\nflags\r\n~1\r\n"u8;
+ public static ReadOnlySpan RESP_Array6_flags_Array1 => "*6\r\n$5\r\nflags\r\n*1\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_master_0_EmptyArray => "*3\r\n$6\r\nmaster\r\n:0\r\n*0\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_master => "*3\r\n$6\r\nmaster\r\n"u8;
+ public static ReadOnlySpan RESP_Array5_slave => "*5\r\n$5\r\nslave\r\n"u8;
+ public static ReadOnlySpan RESP_Array2_0String_EmptyArray => "*2\r\n$1\r\n0\r\n*0\r\n"u8;
+ public static ReadOnlySpan RESP_Push3_async => ">3\r\n$5\r\nasync\r\n"u8;
+ public static ReadOnlySpan RESP_modules_EmptyArray => "$7\r\nmodules\r\n*0\r\n"u8;
+ public static ReadOnlySpan RESP_Push3_messages => ">3\r\n$8\r\nmessages\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_messages => "*3\r\n$8\r\nmessages\r\n"u8;
+ public static ReadOnlySpan RESP_Push4_pmessages => ">4\r\n$9\r\npmessages\r\n"u8;
+ public static ReadOnlySpan RESP_Array4_pmessages => "*4\r\n$9\r\npmessages\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_psubscribe => "*3\r\n$10\r\npsubscribe\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_unsubscribe => "*3\r\n$11\r\nunsubscribe\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_unsubscribe_null3 => "*3\r\n$11\r\nunsubscribe\r\n_\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_unsubscribe_null2 => "*3\r\n$11\r\nunsubscribe\r\n$-1\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_punsubscribe => "*3\r\n$12\r\npunsubscribe\r\n"u8;
+
+ public static ReadOnlySpan RESP_Array3_punsubscribe_null3_0 => "*3\r\n$12\r\npunsubscribe\r\n_\r\n:0\r\n"u8;
+ public static ReadOnlySpan RESP_Array3_punsubscribe_null2_0 => "*3\r\n$12\r\npunsubscribe\r\n$-1\r\n:0\r\n"u8;
+ public static ReadOnlySpan RESP_Array14_quant_type => "*14\r\n$10\r\nquant_type\r\n"u8;
}
}
\ No newline at end of file
diff --git a/libs/server/Resp/HyperLogLog/HyperLogLogCommands.cs b/libs/server/Resp/HyperLogLog/HyperLogLogCommands.cs
index 3ccff292178..d6b068bb02a 100644
--- a/libs/server/Resp/HyperLogLog/HyperLogLogCommands.cs
+++ b/libs/server/Resp/HyperLogLog/HyperLogLogCommands.cs
@@ -39,8 +39,7 @@ private bool HyperLogLogAdd(ref TGarnetApi storageApi)
// Invalid HLL Type
if (*output == 0xFF)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL);
return true;
}
@@ -49,13 +48,11 @@ private bool HyperLogLogAdd(ref TGarnetApi storageApi)
if (pfaddUpdated > 0)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_1, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_1);
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
return true;
}
@@ -81,13 +78,11 @@ private bool HyperLogLogLength(ref TGarnetApi storageApi)
storageApi.HyperLogLogLength(ref input, out var cardinality, out var error);
if (error)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL);
}
else
{
- while (!RespWriteUtils.TryWriteInt64(cardinality, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(cardinality);
}
return true;
@@ -112,15 +107,13 @@ private bool HyperLogLogMerge(ref TGarnetApi storageApi)
// Invalid Type
if (error)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE_HLL);
return true;
}
if (status == GarnetStatus.OK)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
return true;
}
diff --git a/libs/server/Resp/KeyAdminCommands.cs b/libs/server/Resp/KeyAdminCommands.cs
index dde122b592c..1c13902fa89 100644
--- a/libs/server/Resp/KeyAdminCommands.cs
+++ b/libs/server/Resp/KeyAdminCommands.cs
@@ -44,16 +44,14 @@ bool NetworkRESTORE(ref TGarnetApi storageApi)
// Restore is only implemented for string type
if (valueSpan[0] != 0x00)
{
- while (!RespWriteUtils.TryWriteError("ERR RESTORE currently only supports string types", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_RESTORE_currently_only_supports);
return true;
}
// check if length of value is at least 10
if (valueSpan.Length < 10)
{
- while (!RespWriteUtils.TryWriteError("ERR DUMP payload version or checksum are wrong", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_DUMP_payload_version_or_checksum_wrong);
return true;
}
@@ -64,8 +62,7 @@ bool NetworkRESTORE(ref TGarnetApi storageApi)
if (rdbVersion > RDB_VERSION)
{
- while (!RespWriteUtils.TryWriteError("ERR DUMP payload version or checksum are wrong", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_DUMP_payload_version_or_checksum_wrong);
return true;
}
@@ -78,16 +75,14 @@ bool NetworkRESTORE(ref TGarnetApi storageApi)
if (calculatedCrc.SequenceCompareTo(payloadCrc) != 0)
{
- while (!RespWriteUtils.TryWriteError("ERR DUMP payload version or checksum are wrong", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_DUMP_payload_version_or_checksum_wrong);
return true;
}
// decode the length of payload
if (!RespLengthEncodingUtils.TryReadLength(valueSpan.Slice(1), out var length, out var payloadStart))
{
- while (!RespWriteUtils.TryWriteError("ERR DUMP payload length format is invalid", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_DUMP_payload_length_format_invalid);
return true;
}
@@ -113,13 +108,11 @@ bool NetworkRESTORE(ref TGarnetApi storageApi)
if (status is GarnetStatus.NOTFOUND)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
return true;
}
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_BUSSYKEY, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_BUSSYKEY);
return true;
}
@@ -149,8 +142,7 @@ bool NetworkDUMP(ref TGarnetApi storageApi)
if (!RespLengthEncodingUtils.TryWriteLength(value.ReadOnlySpan.Length, encodedLength, out var bytesWritten))
{
- while (!RespWriteUtils.TryWriteError("ERR DUMP payload length is invalid", ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_DUMP_payload_length_is_invalid);
return true;
}
@@ -207,7 +199,7 @@ bool NetworkDUMP(ref TGarnetApi storageApi)
if (rentedBuffer is not null)
{
- WriteDirectLarge(buffer.Slice(0, totalLength));
+ WriteLargeDirect(buffer.Slice(0, totalLength));
ArrayPool.Shared.Return(rentedBuffer);
}
else
@@ -249,12 +241,10 @@ private bool NetworkRENAME(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY);
break;
}
return true;
@@ -292,13 +282,11 @@ private bool NetworkRENAMENX(ref TGarnetApi storageApi)
{
// Integer reply: 1 if key was renamed to newkey.
// Integer reply: 0 if newkey already exists.
- while (!RespWriteUtils.TryWriteInt32(result, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(result);
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY);
}
return true;
@@ -363,8 +351,7 @@ private bool NetworkEXISTS(ref TGarnetApi storageApi)
exists++;
}
- while (!RespWriteUtils.TryWriteInt32(exists, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(exists);
return true;
}
@@ -431,10 +418,7 @@ private bool NetworkEXPIRE(RespCommand command, ref TGarnetApi stora
}
else
{
- while (!RespWriteUtils.TryWriteError(
- "ERR NX and XX, GT or LT options at the same time are not compatible", ref dcurr,
- dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_NX_and_XX_GT_or_LT_not_compatible);
}
}
}
@@ -456,13 +440,11 @@ private bool NetworkEXPIRE(RespCommand command, ref TGarnetApi stora
if (status == GarnetStatus.OK && timeoutSet)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_1, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_1);
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
return true;
@@ -487,13 +469,11 @@ private bool NetworkPERSIST(ref TGarnetApi storageApi)
if (status == GarnetStatus.OK)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_1, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_1);
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
return true;
}
@@ -528,8 +508,7 @@ private bool NetworkTTL(RespCommand command, ref TGarnetApi storageA
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_N2, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_N2);
}
return true;
}
@@ -564,8 +543,7 @@ private bool NetworkEXPIRETIME(RespCommand command, ref TGarnetApi s
}
else
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_N2, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_N2);
}
return true;
}
diff --git a/libs/server/Resp/MGetReadArgBatch.cs b/libs/server/Resp/MGetReadArgBatch.cs
index 77bcfc36006..95837bc918f 100644
--- a/libs/server/Resp/MGetReadArgBatch.cs
+++ b/libs/server/Resp/MGetReadArgBatch.cs
@@ -6,7 +6,6 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using Garnet.common;
using Tsavorite.core;
namespace Garnet.server
@@ -105,8 +104,7 @@ public readonly unsafe void SetOutput(int i, SpanByteAndMemory output)
session.storageSession.incr_session_notfound();
// Not found, write a null out
- while (!RespWriteUtils.TryWriteNull(ref session.dcurr, session.dend))
- session.SendAndReset();
+ session.WriteNull();
}
}
}
@@ -167,8 +165,7 @@ public readonly unsafe void SetOutput(int i, SpanByteAndMemory output)
{
if (pendingNullWrite)
{
- while (!RespWriteUtils.TryWriteNull(ref session.dcurr, session.dend))
- session.SendAndReset();
+ session.WriteNull();
}
else
{
@@ -324,8 +321,7 @@ public readonly unsafe void CompletePending(ref TGarnetApi storageAp
else
{
// Did not find it, was probably synchronous but we couldn't handle it until now
- while (!RespWriteUtils.TryWriteNull(ref session.dcurr, session.dend))
- session.SendAndReset();
+ session.WriteNull();
}
}
}
diff --git a/libs/server/Resp/Objects/HashCommands.cs b/libs/server/Resp/Objects/HashCommands.cs
index bfcc4986cf5..50620c68834 100644
--- a/libs/server/Resp/Objects/HashCommands.cs
+++ b/libs/server/Resp/Objects/HashCommands.cs
@@ -53,19 +53,16 @@ private unsafe bool HashSet(RespCommand command, ref TGarnetApi stor
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
if (command == RespCommand.HMSET)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
}
else
{
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
}
break;
}
@@ -107,8 +104,7 @@ private bool HashGet(RespCommand command, ref TGarnetApi storageApi)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -147,12 +143,10 @@ private bool HashGetAll(RespCommand command, ref TGarnetApi storageA
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTYLIST);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -192,15 +186,13 @@ private bool HashGetMultiple(RespCommand command, ref TGarnetApi sto
break;
case GarnetStatus.NOTFOUND:
// Write an empty array of count - 1 elements with null values.
- while (!RespWriteUtils.TryWriteArrayLength(parseState.Count - 1, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(parseState.Count - 1);
for (var i = 0; i < parseState.Count - 1; ++i)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -280,8 +272,7 @@ private bool HashRandomField(RespCommand command, ref TGarnetApi sto
case GarnetStatus.NOTFOUND:
if (includedCount)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTYLIST);
}
else
{
@@ -289,8 +280,7 @@ private bool HashRandomField(RespCommand command, ref TGarnetApi sto
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -325,16 +315,13 @@ private unsafe bool HashLength(ref TGarnetApi storageApi)
{
case GarnetStatus.OK:
// Process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -368,16 +355,13 @@ private unsafe bool HashStrLength(ref TGarnetApi storageApi)
{
case GarnetStatus.OK:
// Process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -410,16 +394,13 @@ private unsafe bool HashDelete(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -451,16 +432,13 @@ private unsafe bool HashExists(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -511,12 +489,10 @@ private unsafe bool HashKeys(RespCommand command, ref TGarnetApi sto
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -564,8 +540,7 @@ private unsafe bool HashIncrement(RespCommand command, ref TGarnetAp
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
ProcessOutput(output.SpanByteAndMemory);
@@ -649,16 +624,13 @@ private unsafe bool HashExpire(RespCommand command, ref TGarnetApi s
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numFields, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numFields);
for (var i = 0; i < numFields; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
@@ -739,16 +711,13 @@ private unsafe bool HashTimeToLive(RespCommand command, ref TGarnetA
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numFields, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numFields);
for (var i = 0; i < numFields; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
@@ -801,16 +770,13 @@ private unsafe bool HashPersist(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numFields, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numFields);
for (var i = 0; i < numFields; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
diff --git a/libs/server/Resp/Objects/ListCommands.cs b/libs/server/Resp/Objects/ListCommands.cs
index 2fac6516ec2..1cdd14d7d2c 100644
--- a/libs/server/Resp/Objects/ListCommands.cs
+++ b/libs/server/Resp/Objects/ListCommands.cs
@@ -48,14 +48,12 @@ private unsafe bool ListPush(RespCommand command, ref TGarnetApi sto
if (status == GarnetStatus.WRONGTYPE)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
}
else
{
// Write result to output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
}
return true;
}
@@ -119,8 +117,7 @@ private unsafe bool ListPop(RespCommand command, ref TGarnetApi stor
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -173,8 +170,7 @@ private unsafe bool ListPosition(ref TGarnetApi storageApi)
if (count)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
}
else
{
@@ -182,8 +178,7 @@ private unsafe bool ListPosition(ref TGarnetApi storageApi)
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -258,19 +253,15 @@ private unsafe bool ListPopMultiple(ref TGarnetApi storageApi)
switch (statusOp)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(key.Span, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(key.Span);
- while (!RespWriteUtils.TryWriteArrayLength(elements.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(elements.Length);
foreach (var element in elements)
{
- while (!RespWriteUtils.TryWriteBulkString(element.Span, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(element.Span);
}
break;
@@ -278,8 +269,7 @@ private unsafe bool ListPopMultiple(ref TGarnetApi storageApi)
WriteNullArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -313,15 +303,13 @@ private bool ListBlockingPop(RespCommand command)
if (result.IsForceUnblocked)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK);
return true;
}
if (result.IsTypeMismatch)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
return true;
}
@@ -331,14 +319,11 @@ private bool ListBlockingPop(RespCommand command)
}
else
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(new Span(result.Key), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(new Span(result.Key));
- while (!RespWriteUtils.TryWriteBulkString(new Span(result.Item), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(new Span(result.Item));
}
return true;
@@ -422,15 +407,13 @@ private bool ListBlockingMove(ArgSlice srcKey, ArgSlice dstKey,
if (result.IsForceUnblocked)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK);
return true;
}
if (result.IsTypeMismatch)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
return true;
}
@@ -440,8 +423,7 @@ private bool ListBlockingMove(ArgSlice srcKey, ArgSlice dstKey,
}
else
{
- while (!RespWriteUtils.TryWriteBulkString(new Span(result.Item), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(result.Item);
}
return true;
@@ -474,17 +456,14 @@ private bool ListLength(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
// Process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
}
@@ -514,8 +493,7 @@ private bool ListTrim(ref TGarnetApi storageApi)
if (!parseState.TryGetInt(1, out var start) ||
!parseState.TryGetInt(2, out var stop))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
@@ -528,14 +506,12 @@ private bool ListTrim(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
//GarnetStatus.OK or NOTFOUND have same result
// no need to process output, just send OK
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_OK, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_OK);
break;
}
@@ -565,8 +541,7 @@ private bool ListRange(ref TGarnetApi storageApi)
if (!parseState.TryGetInt(1, out var start) ||
!parseState.TryGetInt(2, out var end))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
@@ -586,12 +561,10 @@ private bool ListRange(ref TGarnetApi storageApi)
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTYLIST);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -619,8 +592,7 @@ private bool ListIndex(ref TGarnetApi storageApi)
// Read index param
if (!parseState.TryGetInt(1, out var index))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
@@ -645,8 +617,7 @@ private bool ListIndex(ref TGarnetApi storageApi)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -685,16 +656,13 @@ private bool ListInsert(ref TGarnetApi storageApi)
if (output.result1 == int.MinValue)
return false;
//process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -723,8 +691,7 @@ private bool ListRemove(ref TGarnetApi storageApi)
// Get count parameter
if (!parseState.TryGetInt(1, out var nCount))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
@@ -741,16 +708,13 @@ private bool ListRemove(ref TGarnetApi storageApi)
if (output.result1 == int.MinValue)
return false;
//process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -789,8 +753,7 @@ private bool ListMove(ref TGarnetApi storageApi)
case GarnetStatus.OK:
if (node != null)
{
- while (!RespWriteUtils.TryWriteBulkString(node, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(node);
}
else
{
@@ -799,8 +762,7 @@ private bool ListMove(ref TGarnetApi storageApi)
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -832,8 +794,7 @@ private bool ListRightPopLeftPush(ref TGarnetApi storageApi)
case GarnetStatus.OK:
if (node != null)
{
- while (!RespWriteUtils.TryWriteBulkString(node, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(node);
}
else
{
@@ -842,8 +803,7 @@ private bool ListRightPopLeftPush(ref TGarnetApi storageApi)
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -910,12 +870,10 @@ public bool ListSet(ref TGarnetApi storageApi)
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_NOSUCHKEY);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -999,14 +957,12 @@ private unsafe bool ListBlockingPopMultiple()
if (result.IsForceUnblocked)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK);
}
if (result.IsTypeMismatch)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
return true;
}
@@ -1016,20 +972,16 @@ private unsafe bool ListBlockingPopMultiple()
return true;
}
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(result.Key, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(result.Key);
var elements = result.Items;
- while (!RespWriteUtils.TryWriteArrayLength(elements.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(elements.Length);
foreach (var element in elements)
{
- while (!RespWriteUtils.TryWriteBulkString(element, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(element);
}
return true;
diff --git a/libs/server/Resp/Objects/ObjectStoreUtils.cs b/libs/server/Resp/Objects/ObjectStoreUtils.cs
index 08169de31d0..6568cb04b9a 100644
--- a/libs/server/Resp/Objects/ObjectStoreUtils.cs
+++ b/libs/server/Resp/Objects/ObjectStoreUtils.cs
@@ -3,7 +3,6 @@
using System;
using System.Text;
-using Garnet.common;
namespace Garnet.server
{
@@ -46,10 +45,8 @@ private bool AbortWithWrongNumberOfArgumentsOrUnknownSubcommand(string subComman
/// true if the command was completely consumed, false if the input on the receive buffer was incomplete.
private bool AbortWithErrorMessage(ReadOnlySpan errorMessage)
{
- commandErrorWritten = true;
// Print error message to result stream
- while (!RespWriteUtils.TryWriteError(errorMessage, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(errorMessage);
return true;
}
diff --git a/libs/server/Resp/Objects/SetCommands.cs b/libs/server/Resp/Objects/SetCommands.cs
index 7d7438ec465..39a6a38b7b0 100644
--- a/libs/server/Resp/Objects/SetCommands.cs
+++ b/libs/server/Resp/Objects/SetCommands.cs
@@ -42,13 +42,11 @@ private unsafe bool SetAdd(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
// Write result to output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
}
@@ -89,20 +87,17 @@ private bool SetIntersect(ref TGarnetApi storageApi)
foreach (var item in result)
{
- while (!RespWriteUtils.TryWriteBulkString(item, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(item);
}
}
else
{
- while (!RespWriteUtils.TryWriteArrayLength(resultCount, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(resultCount);
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -137,12 +132,10 @@ private bool SetIntersectStore(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -203,12 +196,10 @@ private bool SetIntersectLength(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(result, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(result);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -247,13 +238,11 @@ private bool SetUnion(ref TGarnetApi storageApi)
foreach (var item in result)
{
- while (!RespWriteUtils.TryWriteBulkString(item, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(item);
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -288,12 +277,10 @@ private bool SetUnionStore(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -330,16 +317,13 @@ private unsafe bool SetRemove(ref TGarnetApi storageApi)
{
case GarnetStatus.OK:
// Write result to output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -374,16 +358,13 @@ private unsafe bool SetLength(ref TGarnetApi storageApi)
{
case GarnetStatus.OK:
// Process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -427,8 +408,7 @@ private unsafe bool SetMembers(ref TGarnetApi storageApi)
WriteEmptySet();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -478,26 +458,22 @@ private unsafe bool SetIsMember(RespCommand cmd, ref TGarnetApi stor
case GarnetStatus.NOTFOUND:
if (isSingle)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
else
{
var count = parseState.Count - 1; // Remove key
- while (!RespWriteUtils.TryWriteArrayLength(count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(count);
for (var i = 0; i < count; i++)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
}
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -533,8 +509,7 @@ private unsafe bool SetPop(ref TGarnetApi storageApi)
if (countParameter == 0)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
return true;
}
@@ -559,8 +534,7 @@ private unsafe bool SetPop(ref TGarnetApi storageApi)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -596,16 +570,13 @@ private unsafe bool SetMove(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -645,8 +616,7 @@ private unsafe bool SetRandomMember(ref TGarnetApi storageApi)
if (countParameter == 0)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
return true;
}
@@ -673,16 +643,14 @@ private unsafe bool SetRandomMember(ref TGarnetApi storageApi)
case GarnetStatus.NOTFOUND:
if (parseState.Count == 2)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
}
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -723,14 +691,12 @@ private bool SetDiff(ref TGarnetApi storageApi)
foreach (var item in output)
{
- while (!RespWriteUtils.TryWriteBulkString(item, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(item);
}
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -758,12 +724,10 @@ private bool SetDiffStore(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(output, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
diff --git a/libs/server/Resp/Objects/SharedObjectCommands.cs b/libs/server/Resp/Objects/SharedObjectCommands.cs
index 965f8d3645c..72e59c307f8 100644
--- a/libs/server/Resp/Objects/SharedObjectCommands.cs
+++ b/libs/server/Resp/Objects/SharedObjectCommands.cs
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
-using Garnet.common;
-
namespace Garnet.server
{
internal sealed unsafe partial class RespServerSession : ServerSessionBase
@@ -77,16 +75,12 @@ private unsafe bool ObjectScan(GarnetObjectType objectType, ref TGar
return false;
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32AsBulkString(0, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
+ WriteInt32AsBulkString(0);
+ WriteEmptyArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
diff --git a/libs/server/Resp/Objects/SortedSetCommands.cs b/libs/server/Resp/Objects/SortedSetCommands.cs
index 37cc6715a99..4ad13825504 100644
--- a/libs/server/Resp/Objects/SortedSetCommands.cs
+++ b/libs/server/Resp/Objects/SortedSetCommands.cs
@@ -41,8 +41,7 @@ private unsafe bool SortedSetAdd(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
ProcessOutput(output.SpanByteAndMemory);
@@ -79,16 +78,13 @@ private unsafe bool SortedSetRemove(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(rmwOutput.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(rmwOutput.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -121,16 +117,13 @@ private unsafe bool SortedSetLength(ref TGarnetApi storageApi)
{
case GarnetStatus.OK:
// Process output
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -197,12 +190,10 @@ private unsafe bool SortedSetRange(RespCommand command, ref TGarnetA
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -229,12 +220,10 @@ private unsafe bool SortedSetRangeStore(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.OK:
- while (!RespWriteUtils.TryWriteInt32(result, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(result);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -279,8 +268,7 @@ private unsafe bool SortedSetScore(ref TGarnetApi storageApi)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -323,15 +311,13 @@ private unsafe bool SortedSetScores(ref TGarnetApi storageApi)
break;
case GarnetStatus.NOTFOUND:
// Write an empty array of count - 1 elements with null values.
- while (!RespWriteUtils.TryWriteArrayLength(parseState.Count - 1, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(parseState.Count - 1);
for (var i = 0; i < parseState.Count - 1; ++i)
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -392,12 +378,10 @@ private unsafe bool SortedSetPop(RespCommand command, ref TGarnetApi
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -487,23 +471,18 @@ private unsafe bool SortedSetMPop(ref TGarnetApi storageApi)
else
{
// Write array with 2 elements: key and array of elements
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
// Write key
- while (!RespWriteUtils.TryWriteBulkString(poppedKey.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(poppedKey.ReadOnlySpan);
// Write array of member-score pairs
- while (!RespWriteUtils.TryWriteArrayLength(pairs.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(pairs.Length);
foreach (var (member, score) in pairs)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(member.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
+ WriteLargeBulkString(member.ReadOnlySpan);
if (respProtocolVersion >= 3)
{
@@ -511,16 +490,14 @@ private unsafe bool SortedSetMPop(ref TGarnetApi storageApi)
}
else
{
- while (!RespWriteUtils.TryWriteBulkString(score.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(score.ReadOnlySpan);
}
}
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -560,12 +537,10 @@ private unsafe bool SortedSetCount(ref TGarnetApi storageApi)
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -618,22 +593,18 @@ private unsafe bool SortedSetLengthByValue(RespCommand command, ref
if (output.result1 == int.MaxValue)
{
// Error in arguments
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_MIN_MAX_NOT_VALID_STRING, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_MIN_MAX_NOT_VALID_STRING);
}
else if (output.result1 == int.MinValue) // command partially executed
return false;
else
- while (!RespWriteUtils.TryWriteInt32(output.result1, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(output.result1);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -676,8 +647,7 @@ private unsafe bool SortedSetIncrement(ref TGarnetApi storageApi)
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -744,8 +714,7 @@ private unsafe bool SortedSetRank(RespCommand command, ref TGarnetAp
WriteNull();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -796,12 +765,10 @@ private unsafe bool SortedSetRemoveRange(RespCommand command, ref TG
ProcessOutput(output.SpanByteAndMemory);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_RETURN_VAL_0, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_RETURN_VAL_0);
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -833,8 +800,7 @@ private unsafe bool SortedSetRandomMember(ref TGarnetApi storageApi)
// Read count
if (!parseState.TryGetInt(1, out paramCount))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_VALUE_IS_NOT_INTEGER);
return true;
}
@@ -882,8 +848,7 @@ private unsafe bool SortedSetRandomMember(ref TGarnetApi storageApi)
case GarnetStatus.NOTFOUND:
if (includedCount)
{
- while (!RespWriteUtils.TryWriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_EMPTYLIST);
}
else
{
@@ -891,8 +856,7 @@ private unsafe bool SortedSetRandomMember(ref TGarnetApi storageApi)
}
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
return true;
@@ -939,8 +903,7 @@ private unsafe bool SortedSetDifference(ref TGarnetApi storageApi)
if (!withScores.EqualsUpperCaseSpanIgnoringCase(CmdStrings.WITHSCORES))
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_SYNTAX_ERROR, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_SYNTAX_ERROR);
return true;
}
@@ -953,32 +916,26 @@ private unsafe bool SortedSetDifference(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
if (result == null)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
}
else
{
// write the size of the array reply
- while (!RespWriteUtils.TryWriteArrayLength(
- includeWithScores && (respProtocolVersion == 2) ? result.Count * 2 : result.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(includeWithScores && (respProtocolVersion == 2) ? result.Count * 2 : result.Count);
if (result != null)
{
foreach (var (score, element) in result)
{
if (respProtocolVersion >= 3 && includeWithScores)
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(element, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(element);
if (includeWithScores)
{
@@ -1028,12 +985,10 @@ private unsafe bool SortedSetDifferenceStore(ref TGarnetApi storageA
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
- while (!RespWriteUtils.TryWriteInt32(count, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(count);
break;
}
@@ -1124,14 +1079,12 @@ private unsafe bool SortedSetIntersect(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
if (result == null || result.Count == 0)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
}
@@ -1139,19 +1092,16 @@ private unsafe bool SortedSetIntersect(ref TGarnetApi storageApi)
var arrayLength = result.Count;
if (includeWithScores && respProtocolVersion == 2)
arrayLength *= 2;
- while (!RespWriteUtils.TryWriteArrayLength(arrayLength, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(arrayLength);
foreach (var (score, element) in result)
{
if (includeWithScores && respProtocolVersion >= 3)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
}
- while (!RespWriteUtils.TryWriteBulkString(element, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(element);
if (includeWithScores)
{
@@ -1223,12 +1173,10 @@ private unsafe bool SortedSetIntersectLength(ref TGarnetApi storageA
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
- while (!RespWriteUtils.TryWriteInt32(count, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(count);
break;
}
@@ -1311,12 +1259,10 @@ private unsafe bool SortedSetIntersectStore(ref TGarnetApi storageAp
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
- while (!RespWriteUtils.TryWriteInt32(count, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(count);
break;
}
@@ -1413,14 +1359,12 @@ private unsafe bool SortedSetUnion(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
if (result == null || result.Count == 0)
{
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
}
@@ -1428,19 +1372,16 @@ private unsafe bool SortedSetUnion(ref TGarnetApi storageApi)
var arrayLength = result.Count;
if (includeWithScores && respProtocolVersion == 2)
arrayLength *= 2;
- while (!RespWriteUtils.TryWriteArrayLength(arrayLength, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(arrayLength);
foreach (var (score, element) in result)
{
if (includeWithScores && respProtocolVersion >= 3)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
}
- while (!RespWriteUtils.TryWriteBulkString(element, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(element);
if (includeWithScores)
{
@@ -1537,12 +1478,10 @@ private unsafe bool SortedSetUnionStore(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
- while (!RespWriteUtils.TryWriteInt32(count, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(count);
break;
}
@@ -1579,15 +1518,13 @@ private unsafe bool SortedSetBlockingPop(RespCommand command)
if (result.IsForceUnblocked)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK);
return true;
}
if (result.IsTypeMismatch)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
return true;
}
@@ -1597,14 +1534,11 @@ private unsafe bool SortedSetBlockingPop(RespCommand command)
}
else
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(3);
- while (!RespWriteUtils.TryWriteBulkString(result.Key, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(result.Key);
- while (!RespWriteUtils.TryWriteBulkString(result.Item, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(result.Item);
WriteDoubleNumeric(result.Score);
}
@@ -1692,15 +1626,13 @@ private unsafe bool SortedSetBlockingMPop()
if (result.IsForceUnblocked)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_UNBLOCKED_CLIENT_VIA_CLIENT_UNBLOCK);
return true;
}
if (result.IsTypeMismatch)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
return true;
}
@@ -1711,21 +1643,16 @@ private unsafe bool SortedSetBlockingMPop()
}
// Write array with 2 elements: key and array of member-score pairs
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
- while (!RespWriteUtils.TryWriteBulkString(result.Key, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(result.Key);
- while (!RespWriteUtils.TryWriteArrayLength(result.Items.Length, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(result.Items.Length);
for (var i = 0; i < result.Items.Length; ++i)
{
- while (!RespWriteUtils.TryWriteArrayLength(2, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(result.Items[i], ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(2);
+ WriteLargeBulkString(result.Items[i]);
WriteDoubleNumeric(result.Scores[i]);
}
@@ -1810,16 +1737,13 @@ private unsafe bool SortedSetExpire(RespCommand command, ref TGarnet
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numMembers, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numMembers);
for (var i = 0; i < numMembers; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
@@ -1903,16 +1827,13 @@ private unsafe bool SortedSetTimeToLive(RespCommand command, ref TGa
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numMembers, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numMembers);
for (var i = 0; i < numMembers; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
@@ -1972,16 +1893,13 @@ private unsafe bool SortedSetPersist(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteArrayLength(numMembers, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numMembers);
for (var i = 0; i < numMembers; i++)
{
- while (!RespWriteUtils.TryWriteInt32(-2, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(-2);
}
break;
default:
diff --git a/libs/server/Resp/Objects/SortedSetGeoCommands.cs b/libs/server/Resp/Objects/SortedSetGeoCommands.cs
index 3c641ff9ac5..d13d5e0b232 100644
--- a/libs/server/Resp/Objects/SortedSetGeoCommands.cs
+++ b/libs/server/Resp/Objects/SortedSetGeoCommands.cs
@@ -92,8 +92,7 @@ private unsafe bool GeoAdd(ref TGarnetApi storageApi)
switch (status)
{
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
default:
ProcessOutput(output.SpanByteAndMemory);
@@ -183,8 +182,7 @@ private unsafe bool GeoCommands(RespCommand command, ref TGarnetApi
break;
default:
var inputCount = parseState.Count - 1;
- while (!RespWriteUtils.TryWriteArrayLength(inputCount, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(inputCount);
for (var i = 0; i < inputCount; i++)
{
WriteNullArray();
@@ -194,8 +192,7 @@ private unsafe bool GeoCommands(RespCommand command, ref TGarnetApi
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
@@ -296,13 +293,11 @@ private unsafe bool GeoSearchCommands(RespCommand command, ref TGarn
switch (status)
{
case GarnetStatus.NOTFOUND:
- while (!RespWriteUtils.TryWriteEmptyArray(ref dcurr, dend))
- SendAndReset();
+ WriteEmptyArray();
break;
case GarnetStatus.WRONGTYPE:
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_WRONG_TYPE, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_WRONG_TYPE);
break;
}
diff --git a/libs/server/Resp/Parser/RespCommand.cs b/libs/server/Resp/Parser/RespCommand.cs
index 3ed6ce1554a..411fd1c9bdf 100644
--- a/libs/server/Resp/Parser/RespCommand.cs
+++ b/libs/server/Resp/Parser/RespCommand.cs
@@ -2909,14 +2909,12 @@ private RespCommand ArrayParseCommand(bool writeErrorOnFailure, ref int count, r
{
if (!specificErrorMessage.IsEmpty)
{
- while (!RespWriteUtils.TryWriteError(specificErrorMessage, ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(specificErrorMessage);
}
else
{
// Return "Unknown RESP Command" message
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_UNK_CMD);
}
}
return cmd;
diff --git a/libs/server/Resp/PubSubCommands.cs b/libs/server/Resp/PubSubCommands.cs
index d353b7b5a7a..87ba20a95d0 100644
--- a/libs/server/Resp/PubSubCommands.cs
+++ b/libs/server/Resp/PubSubCommands.cs
@@ -24,14 +24,18 @@ public override unsafe void Publish(ArgSlice key, ArgSlice value)
{
networkSender.EnterAndGetResponseObject(out dcurr, out dend);
- WritePushLength(3);
-
- while (!RespWriteUtils.TryWriteBulkString("message"u8, ref dcurr, dend))
- SendAndReset();
+ if (respProtocolVersion == 3)
+ {
+ WriteDirect(CmdStrings.RESP_Push3_messages);
+ }
+ else
+ {
+ WriteDirect(CmdStrings.RESP_Array3_messages);
+ }
// Write key and value to the network
- WriteDirectLargeRespString(key.ReadOnlySpan);
- WriteDirectLargeRespString(value.ReadOnlySpan);
+ WriteLargeBulkString(key.ReadOnlySpan);
+ WriteLargeBulkString(value.ReadOnlySpan);
// Flush the publish message for this subscriber
if (dcurr > networkSender.GetResponseObjectHead())
@@ -54,15 +58,19 @@ public override unsafe void PatternPublish(ArgSlice pattern, ArgSlice key, ArgSl
{
networkSender.EnterAndGetResponseObject(out dcurr, out dend);
- WritePushLength(4);
-
- while (!RespWriteUtils.TryWriteBulkString("pmessage"u8, ref dcurr, dend))
- SendAndReset();
+ if(respProtocolVersion == 3)
+ {
+ WriteDirect(CmdStrings.RESP_Push4_pmessages);
+ }
+ else
+ {
+ WriteDirect(CmdStrings.RESP_Array4_pmessages);
+ }
// Write pattern, key, and value to the network
- WriteDirectLargeRespString(pattern.ReadOnlySpan);
- WriteDirectLargeRespString(key.ReadOnlySpan);
- WriteDirectLargeRespString(value.ReadOnlySpan);
+ WriteLargeBulkString(pattern.ReadOnlySpan);
+ WriteLargeBulkString(key.ReadOnlySpan);
+ WriteLargeBulkString(value.ReadOnlySpan);
if (dcurr > networkSender.GetResponseObjectHead())
Send(networkSender.GetResponseObjectHead());
@@ -120,8 +128,7 @@ private bool NetworkPUBLISH(RespCommand cmd)
AsyncUtils.BlockingWait(storeWrapper.clusterProvider.ClusterPublishAsync(cmd, _key, _val));
}
- while (!RespWriteUtils.TryWriteInt32(numClients, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numClients);
return true;
}
@@ -161,26 +168,21 @@ private bool NetworkSUBSCRIBE(RespCommand cmd)
if (disabledBroker)
continue;
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(3);
- while (!RespWriteUtils.TryWriteBulkString(header, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(header);
- while (!RespWriteUtils.TryWriteBulkString(key.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(key.ReadOnlySpan);
if (subscribeBroker.Subscribe(key, this))
numActiveChannels++;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
if (disabledBroker)
{
- while (!RespWriteUtils.TryWriteError("ERR SUBSCRIBE is disabled, enable it with --pubsub option."u8, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_SUBSCRIBE_is_disabled);
return true;
}
@@ -204,25 +206,18 @@ private bool NetworkPSUBSCRIBE()
if (disabledBroker)
continue;
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteBulkString("psubscribe"u8, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(key.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_psubscribe);
+ WriteLargeBulkString(key.ReadOnlySpan);
if (subscribeBroker.PatternSubscribe(key, this))
numActiveChannels++;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
if (disabledBroker)
{
- while (!RespWriteUtils.TryWriteError("ERR SUBSCRIBE is disabled, enable it with --pubsub option."u8, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_SUBSCRIBE_is_disabled);
return true;
}
@@ -244,31 +239,26 @@ private bool NetworkUNSUBSCRIBE()
var channels = subscribeBroker.ListAllSubscriptions(this);
foreach (var channel in channels)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString("unsubscribe"u8, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteBulkString(channel.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_unsubscribe);
+ WriteLargeBulkString(channel.ReadOnlySpan);
if (subscribeBroker.Unsubscribe(channel, this))
numActiveChannels--;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
if (channels.Count == 0)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString("unsubscribe"u8, ref dcurr, dend))
- SendAndReset();
-
- WriteNull();
-
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ if(respProtocolVersion == 3)
+ {
+ WriteDirect(CmdStrings.RESP_Array3_unsubscribe_null3);
+ }
+ else
+ {
+ WriteDirect(CmdStrings.RESP_Array3_unsubscribe_null2);
+ }
+
+ WriteInt32(numActiveChannels);
}
if (numActiveChannels == 0)
@@ -283,25 +273,19 @@ private bool NetworkUNSUBSCRIBE()
if (subscribeBroker != null)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString("unsubscribe"u8, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(key.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_unsubscribe);
+ WriteLargeBulkString(key.ReadOnlySpan);
if (subscribeBroker.Unsubscribe(new ByteArrayWrapper(key), this))
numActiveChannels--;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
}
if (subscribeBroker == null)
{
- while (!RespWriteUtils.TryWriteError("ERR UNSUBSCRIBE is disabled, enable it with --pubsub option."u8, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_UNSUBSCRIBE_is_disabled);
}
if (numActiveChannels == 0)
@@ -324,33 +308,26 @@ private bool NetworkPUNSUBSCRIBE()
List channels = subscribeBroker.ListAllPatternSubscriptions(this);
foreach (var channel in channels)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString("punsubscribe"u8, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_punsubscribe);
- while (!RespWriteUtils.TryWriteBulkString(channel.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(channel.ReadOnlySpan);
if (subscribeBroker.PatternUnsubscribe(channel, this))
numActiveChannels--;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
if (channels.Count == 0)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
-
- while (!RespWriteUtils.TryWriteBulkString("punsubscribe"u8, ref dcurr, dend))
- SendAndReset();
-
- WriteNull();
-
- while (!RespWriteUtils.TryWriteInt32(0, ref dcurr, dend))
- SendAndReset();
+ if(respProtocolVersion == 3)
+ {
+ WriteDirect(CmdStrings.RESP_Array3_punsubscribe_null3_0);
+ }
+ else
+ {
+ WriteDirect(CmdStrings.RESP_Array3_punsubscribe_null2_0);
+ }
}
if (numActiveChannels == 0)
@@ -365,25 +342,19 @@ private bool NetworkPUNSUBSCRIBE()
if (subscribeBroker != null)
{
- while (!RespWriteUtils.TryWriteArrayLength(3, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString("punsubscribe"u8, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteBulkString(key.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteDirect(CmdStrings.RESP_Array3_punsubscribe);
+ WriteLargeBulkString(key.ReadOnlySpan);
if (subscribeBroker.PatternUnsubscribe(new ByteArrayWrapper(key), this))
numActiveChannels--;
- while (!RespWriteUtils.TryWriteInt32(numActiveChannels, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numActiveChannels);
}
}
if (subscribeBroker == null)
{
- while (!RespWriteUtils.TryWriteError("ERR PUNSUBSCRIBE is disabled, enable it with --pubsub option."u8, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.ERR_PUNSUBSCRIBE_is_disabled);
}
if (numActiveChannels == 0)
@@ -410,13 +381,11 @@ private bool NetworkPUBSUB_CHANNELS()
else
channels = subscribeBroker.GetChannels(parseState.GetArgSliceByRef(0));
- while (!RespWriteUtils.TryWriteArrayLength(channels.Count, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(channels.Count);
foreach (var channel in channels)
{
- while (!RespWriteUtils.TryWriteBulkString(channel.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(channel.ReadOnlySpan);
}
return true;
}
@@ -435,8 +404,7 @@ private bool NetworkPUBSUB_NUMPAT()
var numPatSubs = subscribeBroker.NumPatternSubscriptions();
- while (!RespWriteUtils.TryWriteInt32(numPatSubs, ref dcurr, dend))
- SendAndReset();
+ WriteInt32(numPatSubs);
return true;
}
@@ -449,17 +417,14 @@ private bool NetworkPUBSUB_NUMSUB()
}
var numChannels = parseState.Count;
- while (!RespWriteUtils.TryWriteArrayLength(numChannels * 2, ref dcurr, dend))
- SendAndReset();
+ WriteArrayLength(numChannels * 2);
for (int c = 0; c < numChannels; c++)
{
var channel = parseState.GetArgSliceByRef(c);
- while (!RespWriteUtils.TryWriteBulkString(channel.ReadOnlySpan, ref dcurr, dend))
- SendAndReset();
- while (!RespWriteUtils.TryWriteInt32(subscribeBroker.NumSubscriptions(channel), ref dcurr, dend))
- SendAndReset();
+ WriteLargeBulkString(channel.ReadOnlySpan);
+ WriteInt32(subscribeBroker.NumSubscriptions(channel));
}
return true;
}
diff --git a/libs/server/Resp/PurgeBPCommand.cs b/libs/server/Resp/PurgeBPCommand.cs
index d0cde4b03f4..1ba1c6ebfb8 100644
--- a/libs/server/Resp/PurgeBPCommand.cs
+++ b/libs/server/Resp/PurgeBPCommand.cs
@@ -72,23 +72,20 @@ private bool NetworkPurgeBP()
break;
default:
success = false;
- while (!RespWriteUtils.TryWriteError($"ERR Could not purge {managerType}.", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Could not purge {managerType}.");
break;
}
if (success)
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
- while (!RespWriteUtils.TryWriteSimpleString(managerType.ToReadOnlySpan(), ref dcurr, dend))
- SendAndReset();
+ WriteEnumAsBulkString(managerType);
}
}
catch (Exception ex)
{
logger?.LogError(ex, "PURGEBP {type}:{managerType}", managerType, managerType.ToString());
- while (!RespWriteUtils.TryWriteError($"ERR {ex.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteError(ex);
return true;
}
@@ -96,8 +93,7 @@ bool ClusterPurgeBufferPool(ManagerType managerType)
{
if (clusterSession == null)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_GENERIC_CLUSTER_DISABLED, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_GENERIC_CLUSTER_DISABLED);
return false;
}
storeWrapper.clusterProvider.PurgeBufferPool(managerType);
diff --git a/libs/server/Resp/RespServerSession.cs b/libs/server/Resp/RespServerSession.cs
index f91c2bfcd45..f9cb5d9382a 100644
--- a/libs/server/Resp/RespServerSession.cs
+++ b/libs/server/Resp/RespServerSession.cs
@@ -490,8 +490,7 @@ public override int TryConsumeMessages(byte* reqBuffer, int bytesReceived)
logger?.Log(ex.LogLevel, ex, "Aborting open session due to RESP parsing error");
// Forward parsing error as RESP error
- while (!RespWriteUtils.TryWriteError($"ERR Protocol Error: {ex.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Protocol Error: {ex.Message}");
// Send message and dispose the network sender to end the session
if (dcurr > networkSender.GetResponseObjectHead())
@@ -508,8 +507,7 @@ public override int TryConsumeMessages(byte* reqBuffer, int bytesReceived)
// Forward Garnet error as RESP error
if (ex.ClientResponse)
{
- while (!RespWriteUtils.TryWriteError($"ERR Garnet Exception: {ex.Message}", ref dcurr, dend))
- SendAndReset();
+ WriteLargeError($"ERR Garnet Exception: {ex.Message}");
}
// Send message and dispose the network sender to end the session
@@ -650,13 +648,11 @@ private void ProcessMessages()
{
if (noScriptPassed)
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NOAUTH, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NOAUTH);
}
else
{
- while (!RespWriteUtils.TryWriteError(CmdStrings.RESP_ERR_NOSCRIPT, ref dcurr, dend))
- SendAndReset();
+ WriteError(CmdStrings.RESP_ERR_NOSCRIPT);
}
// Track rejected command (ACL or script permission failure)
@@ -1075,8 +1071,7 @@ bool NetworkCLIENTID()
return AbortWithWrongNumberOfArguments("client|id");
}
- while (!RespWriteUtils.TryWriteInt64(Id, ref dcurr, dend))
- SendAndReset();
+ WriteInt64(Id);
return true;
}
@@ -1163,8 +1158,7 @@ private bool IsCommandArityValid(string cmdName, int arity, int count)
if ((arity > 0 && count != arity - 1) ||
(arity < 0 && count < -arity - 1))
{
- while (!RespWriteUtils.TryWriteError(string.Format(CmdStrings.GenericErrWrongNumArgs, cmdName), ref dcurr, dend))
- SendAndReset();
+ WriteLargeError(string.Format(CmdStrings.GenericErrWrongNumArgs, cmdName));
return false;
}
@@ -1343,7 +1337,7 @@ internal void SendAndReset(IMemoryOwner memory, int length)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteDirectLarge(ReadOnlySpan src)
+ private void WriteLargeDirect(ReadOnlySpan src)
{
// Repeat while we have bytes left to write
while (src.Length > 0)
diff --git a/libs/server/Resp/RespServerSessionOutput.cs b/libs/server/Resp/RespServerSessionOutput.cs
index 969c5059e89..5440b5a8163 100644
--- a/libs/server/Resp/RespServerSessionOutput.cs
+++ b/libs/server/Resp/RespServerSessionOutput.cs
@@ -2,7 +2,10 @@
// Licensed under the MIT license.
using System;
+using System.Buffers;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Text;
using Garnet.common;
using Tsavorite.core;
@@ -19,7 +22,7 @@ internal sealed unsafe partial class RespServerSession : ServerSessionBase
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void ProcessOutput(SpanByteAndMemory output)
+ internal void ProcessOutput(SpanByteAndMemory output)
{
if (!output.IsSpanByte)
SendAndReset(output.Memory, output.Length);
@@ -28,54 +31,137 @@ private unsafe void ProcessOutput(SpanByteAndMemory output)
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteAsciiBulkString(ReadOnlySpan message)
+ internal void WriteAsciiBulkString(ReadOnlySpan message)
{
+ Debug.Assert(!message.ContainsAnyExceptInRange((char)0, (char)127), "Can only write all ASCII values using this method");
+
while (!RespWriteUtils.TryWriteAsciiBulkString(message, ref dcurr, dend))
SendAndReset();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteAsciiDirect(ReadOnlySpan message)
+ internal void WriteLargeAsciiBulkString(ReadOnlySpan message)
+ {
+ Debug.Assert(!message.ContainsAnyExceptInRange((char)0, (char)127), "Can only write all ASCII values using this method");
+
+ var buff = ArrayPool.Shared.Rent(message.Length);
+ try
+ {
+ var written = Encoding.ASCII.GetBytes(message, buff);
+ var asSpan = buff.AsSpan()[..written];
+
+ WriteLargeBulkString(asSpan);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(buff);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void WriteEnumAsBulkString(TEnum value)
+ where TEnum : struct, Enum
{
+ var asStr = value.ToString();
+ while (!RespWriteUtils.TryWriteAsciiBulkString(asStr, ref dcurr, dend))
+ SendAndReset();
+ }
+
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void WriteAsciiDirect(ReadOnlySpan message)
+ {
+ Debug.Assert(!message.ContainsAnyExceptInRange((char)0, (char)128), "Only ASCII data allowed");
+
while (!RespWriteUtils.TryWriteAsciiDirect(message, ref dcurr, dend))
SendAndReset();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteArrayLength(int len)
+ internal void WriteLargeAsciiDirect(ReadOnlySpan message)
+ {
+ Debug.Assert(!message.ContainsAnyExceptInRange((char)0, (char)128), "Only ASCII data allowed");
+
+ var buff = ArrayPool.Shared.Rent(message.Length);
+ try
+ {
+ var written = Encoding.ASCII.GetBytes(message, buff);
+
+ var asSpan = buff.AsSpan()[..written];
+
+ WriteLargeDirect(asSpan);
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(buff);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void WriteArrayLength(int len)
{
while (!RespWriteUtils.TryWriteArrayLength(len, ref dcurr, dend))
SendAndReset();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteBulkString(scoped ReadOnlySpan message)
+ internal void WriteArrayItem(long recordsExpired)
+ {
+ while (!RespWriteUtils.TryWriteArrayItem(recordsExpired, ref dcurr, dend))
+ SendAndReset();
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal void WriteBulkString(scoped ReadOnlySpan message)
{
while (!RespWriteUtils.TryWriteBulkString(message, ref dcurr, dend))
SendAndReset();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteDirectLargeRespString(ReadOnlySpan message)
+ internal void WriteLargeBulkString(ReadOnlySpan message)
{
while (!RespWriteUtils.TryWriteBulkStringLength(message, ref dcurr, dend))
SendAndReset();
- WriteDirectLarge(message);
+ WriteLargeDirect(message);
while (!RespWriteUtils.TryWriteNewLine(ref dcurr, dend))
SendAndReset();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WriteDirect(scoped ReadOnlySpan span)
+ internal void WriteLargeBulkString(ReadOnlySpan