Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions libs/server/Metrics/Info/GarnetInfoMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ class GarnetInfoMetrics
_ => true
})];

/// <summary>
/// All info sections excluding module-generated ones.
/// </summary>
public static readonly HashSet<InfoMetricsType> AllInfoSet = [.. DefaultInfo.Where(e => e != InfoMetricsType.MODULES)];

/// <summary>
/// All info sections including module-generated ones.
/// </summary>
public static readonly HashSet<InfoMetricsType> EverythingInfoSet = [.. DefaultInfo];

MetricsItem[] serverInfo = null;
MetricsItem[] memoryInfo = null;
MetricsItem[] clusterInfo = null;
Expand Down
23 changes: 13 additions & 10 deletions libs/server/Metrics/Info/InfoCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,20 @@ private bool NetworkINFO()
reset = true;
else if (sbSection.EqualsUpperCaseSpanIgnoringCase("HELP"u8))
help = true;
else if (!sbSection.EqualsUpperCaseSpanIgnoringCase("ALL"u8))
else if (sbSection.EqualsUpperCaseSpanIgnoringCase("ALL"u8))
sections.UnionWith(GarnetInfoMetrics.AllInfoSet);
else if (sbSection.EqualsUpperCaseSpanIgnoringCase("DEFAULT"u8))
sections.UnionWith(GarnetInfoMetrics.DefaultInfo);
else if (sbSection.EqualsUpperCaseSpanIgnoringCase("EVERYTHING"u8))
sections.UnionWith(GarnetInfoMetrics.EverythingInfoSet);
else if (parseState.TryGetInfoMetricsType(i, out var sectionType))
{
if (parseState.TryGetInfoMetricsType(i, out var sectionType))
{
sections.Add(sectionType);
}
else
{
invalid = true;
invalidSection = parseState.GetString(i);
}
sections.Add(sectionType);
}
else
{
invalid = true;
invalidSection = parseState.GetString(i);
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion libs/server/Metrics/Info/InfoHelp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class InfoHelp
{
internal const string HELP = "HELP";
internal const string ALL = "ALL";
internal const string DEFAULT = "DEFAULT";
internal const string EVERYTHING = "EVERYTHING";
internal const string RESET = "RESET";

public static List<string> GetInfoTypeHelpMessage()
Expand All @@ -33,7 +35,9 @@ public static List<string> GetInfoTypeHelpMessage()
$"{nameof(InfoMetricsType.KEYSPACE)}: Database related statistics.",
$"{nameof(InfoMetricsType.MODULES)}: Information related to loaded modules.",
$"{nameof(InfoMetricsType.HLOGSCAN)}: Distribution of records in main store's hybrid log in-memory portion.",
$"{nameof(ALL)}: Return all informational sections.",
$"{nameof(ALL)}: Return all informational sections (excluding module generated ones).",
$"{nameof(DEFAULT)}: Return the default set of informational sections.",
$"{nameof(EVERYTHING)}: Return all informational sections including module generated ones.",
$"{nameof(HELP)}: Print this help message.",
$"{nameof(RESET)}: Reset stats.",
"\r\n",
Expand Down
77 changes: 77 additions & 0 deletions test/Garnet.test/RespInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,83 @@ public void ResetStatsTest()
ClassicAssert.AreEqual("total_found:1", totalFound, "Expected total_found to be one after sending one successful request");
}

[Test]
[TestCase("ALL")]
[TestCase("DEFAULT")]
[TestCase("EVERYTHING")]
public void InfoSectionOptionsTest(string option)
{
using var redis = ConnectionMultiplexer.Connect(TestUtils.GetConfig());
var db = redis.GetDatabase(0);

var infoResult = db.Execute("INFO", option).ToString();
ClassicAssert.IsNotNull(infoResult);
ClassicAssert.IsNotEmpty(infoResult);

// All options should include these core sections
ClassicAssert.IsTrue(infoResult.Contains("# Server"), $"INFO {option} should contain Server section");
ClassicAssert.IsTrue(infoResult.Contains("# Memory"), $"INFO {option} should contain Memory section");
ClassicAssert.IsTrue(infoResult.Contains("# Stats"), $"INFO {option} should contain Stats section");
ClassicAssert.IsTrue(infoResult.Contains("# Clients"), $"INFO {option} should contain Clients section");
ClassicAssert.IsTrue(infoResult.Contains("# Keyspace"), $"INFO {option} should contain Keyspace section");

// ALL excludes Modules section; DEFAULT and EVERYTHING include it
if (option == "ALL")
{
ClassicAssert.IsFalse(infoResult.Contains("# Modules"), "INFO ALL should not contain Modules section");
}
else
{
ClassicAssert.IsTrue(infoResult.Contains("# Modules"), $"INFO {option} should contain Modules section");
}

// All three options are based on DefaultInfo which excludes expensive sections
ClassicAssert.IsFalse(infoResult.Contains("MainStoreHashTableDistribution"), $"INFO {option} should not contain StoreHashTable section");
ClassicAssert.IsFalse(infoResult.Contains("MainStoreDeletedRecordRevivification"), $"INFO {option} should not contain StoreReviv section");
}

[Test]
public void InfoDefaultMatchesNoArgsTest()
{
using var redis = ConnectionMultiplexer.Connect(TestUtils.GetConfig());
var db = redis.GetDatabase(0);

var infoNoArgs = db.Execute("INFO").ToString();
var infoDefault = db.Execute("INFO", "DEFAULT").ToString();

// Both should return the same set of section headers
var noArgsSections = GetSectionHeaders(infoNoArgs);
var defaultSections = GetSectionHeaders(infoDefault);

CollectionAssert.AreEquivalent(noArgsSections, defaultSections,
"INFO (no args) and INFO DEFAULT should return the same sections");
}

[Test]
public void InfoAllWithModulesEqualsEverythingTest()
{
using var redis = ConnectionMultiplexer.Connect(TestUtils.GetConfig());
var db = redis.GetDatabase(0);

var infoEverything = db.Execute("INFO", "EVERYTHING").ToString();
var infoAllModules = db.Execute("INFO", "ALL", "MODULES").ToString();

var everythingSections = GetSectionHeaders(infoEverything);
var allModulesSections = GetSectionHeaders(infoAllModules);

CollectionAssert.AreEquivalent(everythingSections, allModulesSections,
"INFO EVERYTHING and INFO ALL MODULES should return the same sections");
}

private static List<string> GetSectionHeaders(string infoOutput)
{
return infoOutput.Split("\r\n")
.Where(line => line.StartsWith("# "))
.Select(line => line.TrimStart('#', ' '))
.OrderBy(s => s)
.ToList();
}

[Test]
public async Task InfoHlogScanTest()
{
Expand Down
Loading