Skip to content

Commit

Permalink
Merge branch 'main' into list-commands
Browse files Browse the repository at this point in the history
  • Loading branch information
badrishc authored May 20, 2024
2 parents b8630f3 + 78d6ad7 commit 79fbbd2
Show file tree
Hide file tree
Showing 20 changed files with 296 additions and 61 deletions.
10 changes: 8 additions & 2 deletions .azure/pipelines/azure-pipelines-external-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
# 1) update the name: string below (line 6) -- this is the version for the nuget package (e.g. 1.0.0)
# 2) update \libs\host\GarnetServer.cs readonly string version (~line 45) -- NOTE - these two values need to be the same
######################################
name: 1.0.8
trigger: none
name: 1.0.10
trigger:
branches:
include:
- main
paths:
include:
- .azure/pipelines/azure-pipelines-external-release.yml
resources:
repositories:
- repository: self
Expand Down
51 changes: 50 additions & 1 deletion .azure/pipelines/azure-pipelines-mirror.yml
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
# This is a placeholder for Azure Mirror Github pipeline
resources:
repositories:
- repository: GarnetGithubRepo
type: github
name: microsoft/garnet
endpoint: ADO_to_Github_ServiceConnection
trigger:
branches:
include:
- main

pool:
vmImage: 'ubuntu-latest'

jobs:
- job: MirrorGithubToADO
displayName: 'Mirror GitHub main to Azure DevOps main'
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: GarnetGithubRepo
clean: true
persistCredentials: true

- script: |
# Set up Git identity
git config user.email "$(GIT_USER_EMAIL)"
git config user.name "$(GIT_USER_NAME)"
git config --global credential.helper 'cache --timeout=3600'
# Fetch the latest changes from the GitHub main branch
git fetch origin main
# Check out main branch locally
# git checkout main
# Ensure the local main branch is checked out and reset to match origin/main
git checkout -B main origin/main
# Reset the main branch to match the origin/main branch
# git reset --hard origin/main
# Push the updated main branch to Azure DevOps
git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push https://dev.azure.com/msresearch/_git/Garnet main
displayName: 'Mirror GitHub main to Azure DevOps main'
env:
GIT_USER_EMAIL: $(GIT_USER_EMAIL)
GIT_USER_NAME: $(GIT_USER_NAME)
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
10 changes: 10 additions & 0 deletions libs/cluster/Server/ClusterConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,16 @@ public bool IsKnown(string nodeid)
return false;
}

/// <summary>
/// Check if local node is a PRIMARY node
/// </summary>
public bool IsPrimary => LocalNodeRole == NodeRole.PRIMARY;

/// <summary>
/// Check if local node is a REPLICA node
/// </summary>
public bool IsReplica => LocalNodeRole == NodeRole.REPLICA;

#region GetLocalNodeInfo
/// <summary>
/// Get local node ip
Expand Down
2 changes: 2 additions & 0 deletions libs/cluster/Session/ClusterSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ internal sealed unsafe partial class ClusterSession : IClusterSession
/// </summary>
bool readWriteSession = false;

public bool ReadWriteSession => clusterProvider.clusterManager.CurrentConfig.IsPrimary || readWriteSession;

public void SetReadOnlySession() => readWriteSession = false;
public void SetReadWriteSession() => readWriteSession = true;

Expand Down
2 changes: 0 additions & 2 deletions libs/host/Configuration/Options.cs
Original file line number Diff line number Diff line change
Expand Up @@ -629,8 +629,6 @@ private IAuthenticationSettings GetAuthenticationSettings(ILogger logger = null)
throw new Exception($"Authentication mode {AuthenticationMode} is not supported.");
}
}


}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion libs/host/GarnetServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class GarnetServer : IDisposable
protected StoreWrapper storeWrapper;

// IMPORTANT: Keep the version in sync with .azure\pipelines\azure-pipelines-external-release.yml line ~6.
readonly string version = "1.0.8";
readonly string version = "1.0.10";

/// <summary>
/// Resp protocol version
Expand Down
5 changes: 5 additions & 0 deletions libs/server/Cluster/IClusterSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ namespace Garnet.server
/// </summary>
public interface IClusterSession
{
/// <summary>
/// Type of session
/// </summary>
bool ReadWriteSession { get; }

/// <summary>
/// Make this cluster session a read-only session
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions libs/server/Custom/CustomCommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ internal int Register(string name, int numParams, CommandType type, CustomRawStr
throw new Exception("Out of registration space");

commandMap[id] = new CustomCommand(name, (byte)id, 1, numParams, type, customFunctions, expirationTicks);
customCommandsInfo.Add(name, commandInfo);
if (commandInfo != null) customCommandsInfo.Add(name, commandInfo);
return id;
}

Expand Down Expand Up @@ -99,7 +99,7 @@ internal int Register(string name, int numParams, CommandType commandType, int o
throw new Exception("Out of registration space");

wrapper.commandMap[subCommand] = new CustomObjectCommand(name, (byte)objectTypeId, (byte)subCommand, 1, numParams, commandType, wrapper.factory);
customCommandsInfo.Add(name, commandInfo);
if (commandInfo != null) customCommandsInfo.Add(name, commandInfo);

return subCommand;
}
Expand Down Expand Up @@ -127,7 +127,7 @@ internal int Register(string name, int numParams, CommandType commandType, int o
throw new Exception("Out of registration space");
wrapper.commandMap[subCommand] = new CustomObjectCommand(name, (byte)objectTypeId, (byte)subCommand, 1, numParams, commandType, wrapper.factory);

customCommandsInfo.Add(name, commandInfo);
if (commandInfo != null) customCommandsInfo.Add(name, commandInfo);

return (objectTypeId, subCommand);
}
Expand Down
31 changes: 15 additions & 16 deletions libs/server/Resp/AdminCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,30 +96,29 @@ private bool ProcessAdminCommands<TGarnetApi>(RespCommand command, ReadOnlySpan<
}
else if (command == RespCommand.CONFIG)
{
if (!CheckACLAdminPermissions(bufSpan, count, out bool success))
if (!CheckACLAdminPermissions(bufSpan, count, out var success))
{
return success;
}

var param = GetCommand(bufSpan, out bool success1);
// Terminate early if command arguments are less than expected
if (count < 1)
{
while (!RespWriteUtils.WriteBulkString("ERR wrong number of arguments for 'config' command"u8, ref dcurr, dend))
SendAndReset();
return true;
}

var param = GetCommand(bufSpan, out var success1);
if (!success1) return false;

if (param.SequenceEqual(CmdStrings.GET) || param.SequenceEqual(CmdStrings.get))
{
if (count > 2)
{
if (!DrainCommands(bufSpan, count - 1))
return false;
errorFlag = true;
errorCmd = Encoding.ASCII.GetString(param);
}
else
{
var key = GetCommand(bufSpan, out bool success2);
if (!success2) return false;
if (!NetworkConfigGet(bufSpan, count, out errorFlag))
return false;

while (!RespWriteUtils.WriteDirect(CmdStrings.GetConfig(key), ref dcurr, dend))
SendAndReset();
}
if (errorFlag)
errorCmd = Encoding.ASCII.GetString(CmdStrings.CONFIG) + "|" + Encoding.ASCII.GetString(param);
}
else if (param.SequenceEqual(CmdStrings.REWRITE) || param.SequenceEqual(CmdStrings.rewrite))
{
Expand Down
10 changes: 0 additions & 10 deletions libs/server/Resp/CmdStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,6 @@ namespace Garnet.server
/// </summary>
static partial class CmdStrings
{
public static ReadOnlySpan<byte> GetConfig(ReadOnlySpan<byte> key)
{
if (key.SequenceEqual("timeout"u8)) return "*2\r\n$7\r\ntimeout\r\n$1\r\n0\r\n"u8;
else if (key.SequenceEqual("save"u8)) return "*2\r\n$4\r\nsave\r\n$0\r\n\r\n"u8;
else if (key.SequenceEqual("appendonly"u8)) return "*2\r\n$10\r\nappendonly\r\n$2\r\nno\r\n"u8;
else if (key.SequenceEqual("slave-read-only"u8)) return "$3\r\nyes\r\n"u8;
else if (key.SequenceEqual("databases"u8)) return "$2\r\n16\r\n"u8;
else return RESP_EMPTYLIST;
}

/// <summary>
/// Request strings
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions libs/server/Resp/RespServerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -654,15 +654,15 @@ private bool ProcessOtherCommands<TGarnetApi>(RespCommand command, byte subcmd,

bool DrainCommands(ReadOnlySpan<byte> bufSpan, int count)
{
for (int i = 0; i < count; i++)
for (var i = 0; i < count; i++)
{
GetCommand(bufSpan, out bool success1);
if (!success1) return false;
}
return true;
}

ReadOnlySpan<byte> GetCommand(ReadOnlySpan<byte> bufSpan, out bool success)
Span<byte> GetCommand(ReadOnlySpan<byte> bufSpan, out bool success)
{
var ptr = recvBufferPtr + readHead;
var end = recvBufferPtr + bytesRead;
Expand All @@ -689,7 +689,7 @@ ReadOnlySpan<byte> GetCommand(ReadOnlySpan<byte> bufSpan, out bool success)
RespParsingException.ThrowUnexpectedToken(*ptr);
}

var result = bufSpan.Slice(readHead, length);
var result = new Span<byte>(recvBufferPtr + readHead, length);
readHead += length + 2;
success = true;

Expand Down
107 changes: 107 additions & 0 deletions libs/server/ServerConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Garnet.common;

namespace Garnet.server
{
static class ServerConfig
{
public static readonly HashSet<ServerConfigType> DefaultConfigType = Enum.GetValues<ServerConfigType>().
Where(e => e switch
{
ServerConfigType.NONE => false,
ServerConfigType.ALL => false,
_ => true
}).ToHashSet();

public static unsafe ServerConfigType GetConfig(Span<byte> parameter)
{
ConvertUtils.MakeUpperCase(parameter);
return parameter switch
{
_ when parameter.SequenceEqual("TIMEOUT"u8) => ServerConfigType.TIMEOUT,
_ when parameter.SequenceEqual("SAVE"u8) => ServerConfigType.SAVE,
_ when parameter.SequenceEqual("APPENDONLY"u8) => ServerConfigType.APPENDONLY,
_ when parameter.SequenceEqual("SLAVE-READ-ONLY"u8) => ServerConfigType.SLAVE_READ_ONLY,
_ when parameter.SequenceEqual("DATABASES"u8) => ServerConfigType.DATABASES,
_ when parameter.SequenceEqual("CLUSTER-NODE-TIMEOUT"u8) => ServerConfigType.CLUSTER_NODE_TIMEOUT,
_ when parameter.SequenceEqual("*"u8) => ServerConfigType.ALL,
_ => ServerConfigType.NONE,
};
}
}

internal sealed unsafe partial class RespServerSession : ServerSessionBase
{
private bool NetworkConfigGet(ReadOnlySpan<byte> bufSpan, int count, out bool errorFlag)
{
errorFlag = false;
if (count < 2)
{
if (!DrainCommands(bufSpan, count - 1))
return false;
errorFlag = true;
return true;
}

// Extract requested parameters
HashSet<ServerConfigType> parameters = [];
var returnAll = false;
for (var i = 0; i < count - 1; i++)
{
var parameter = GetCommand(bufSpan, out bool success2);
if (!success2) return false;
var serverConfigType = ServerConfig.GetConfig(parameter);

if (returnAll) continue;
if (serverConfigType == ServerConfigType.ALL)
{
parameters = ServerConfig.DefaultConfigType;
returnAll = true;
continue;
}

if (serverConfigType != ServerConfigType.NONE)
_ = parameters.Add(serverConfigType);
}

// Generate response for matching parameters
if (parameters.Count > 0)
{
while (!RespWriteUtils.WriteArrayLength(parameters.Count * 2, ref dcurr, dend))
SendAndReset();

foreach (var parameter in parameters)
{
var parameterValue = parameter switch
{
ServerConfigType.TIMEOUT => "$7\r\ntimeout\r\n$1\r\n0\r\n"u8,
ServerConfigType.SAVE => "$4\r\nsave\r\n$0\r\n\r\n"u8,
ServerConfigType.APPENDONLY => storeWrapper.serverOptions.EnableAOF ? "$10\r\nappendonly\r\n$3\r\nyes\r\n"u8 : "$10\r\nappendonly\r\n$2\r\nno\r\n"u8,
ServerConfigType.SLAVE_READ_ONLY => clusterSession == null || clusterSession.ReadWriteSession ? "$15\r\nslave-read-only\r\n$2\r\nno\r\n"u8 : "$15\r\nslave-read-only\r\n$3\r\nyes\r\n"u8,
ServerConfigType.DATABASES => storeWrapper.serverOptions.EnableCluster ? "$9\r\ndatabases\r\n$1\r\n1\r\n"u8 : "$9\r\ndatabases\r\n$2\r\n16\r\n"u8,
ServerConfigType.CLUSTER_NODE_TIMEOUT => Encoding.ASCII.GetBytes($"$20\r\ncluster-node-timeout\r\n${storeWrapper.serverOptions.ClusterTimeout.ToString().Length}\r\n{storeWrapper.serverOptions.ClusterTimeout}\r\n"),
ServerConfigType.NONE => throw new NotImplementedException(),
ServerConfigType.ALL => throw new NotImplementedException(),
_ => throw new NotImplementedException()
};

while (!RespWriteUtils.WriteDirect(parameterValue, ref dcurr, dend))
SendAndReset();
}
}
else
{
while (!RespWriteUtils.WriteDirect(CmdStrings.RESP_EMPTYLIST, ref dcurr, dend))
SendAndReset();
}

return true;
}
}
}
17 changes: 17 additions & 0 deletions libs/server/ServerConfigType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

namespace Garnet.server
{
internal enum ServerConfigType : int
{
NONE,
ALL,
TIMEOUT,
SAVE,
APPENDONLY,
SLAVE_READ_ONLY,
DATABASES,
CLUSTER_NODE_TIMEOUT
}
}
6 changes: 3 additions & 3 deletions libs/server/Servers/RegisterApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public RegisterApi(GarnetProvider provider)
/// >0 => set expiration to given value.
/// </param>
/// <returns>ID of the registered command</returns>
public int NewCommand(string name, int numParams, CommandType type, CustomRawStringFunctions customFunctions, RespCommandsInfo commandInfo, long expirationTicks = 0)
public int NewCommand(string name, int numParams, CommandType type, CustomRawStringFunctions customFunctions, RespCommandsInfo commandInfo = null, long expirationTicks = 0)
=> provider.StoreWrapper.customCommandManager.Register(name, numParams, type, customFunctions, commandInfo, expirationTicks);

/// <summary>
Expand Down Expand Up @@ -82,7 +82,7 @@ public void NewType(int type, CustomObjectFactory factory)
/// <param name="type">Type ID for factory, registered using RegisterType</param>
/// <param name="commandInfo">RESP command info</param>
/// <returns>ID of the registered command</returns>
public int NewCommand(string name, int numParams, CommandType commandType, int type, RespCommandsInfo commandInfo)
public int NewCommand(string name, int numParams, CommandType commandType, int type, RespCommandsInfo commandInfo = null)
=> provider.StoreWrapper.customCommandManager.Register(name, numParams, commandType, type, commandInfo);

/// <summary>
Expand All @@ -94,7 +94,7 @@ public int NewCommand(string name, int numParams, CommandType commandType, int t
/// <param name="factory">Custom factory for object</param>
/// <param name="commandInfo">RESP command info</param>
/// <returns>ID of the registered command</returns>
public (int, int) NewCommand(string name, int numParams, CommandType commandType, CustomObjectFactory factory, RespCommandsInfo commandInfo)
public (int, int) NewCommand(string name, int numParams, CommandType commandType, CustomObjectFactory factory, RespCommandsInfo commandInfo = null)
=> provider.StoreWrapper.customCommandManager.Register(name, numParams, commandType, factory, commandInfo);

}
Expand Down
Loading

0 comments on commit 79fbbd2

Please sign in to comment.