Garnet API
The IGarnetApi interface contains the operators exposed to the public API, which ultimately perform operations over the keys stored in Garnet. It inherits from IGarnetReadApi (read-only commands interface) and IGarnetAdvancedApi (advanced API calls).
For adding an new operator or command to the API, add a new method signature to the IGarnetReadApi interface in case the command performs read-only operations, or IGarnetApi otherwise.
Adding a new command to Garnet
If you are trying to add a command for your specific Garnet server instance, see Custom Commands
To add a new command to Garnet, follow these steps:
- If your command operates on an object (i.e. List, SortedSet etc.), add a new enum value to the
[ObjectName]Operation
enum inGarnet.server/Objects/[ObjectName]/[ObjectName]Object.cs
Otherwise, add a new enum value to theRespCommand
enum inGarnet.server/Resp/RespCommand.cs
. - Add the parsing logic of the new command name to
Garnet.server/Resp/RespCommand.cs
. If the command has a fixed number of arguments, add parsing logic to the FastParseCommand method. Otherwise, add parsing logic to the FastParseArrayCommand method. - Add a new method signature to IGarnetReadApi, in case the command performs read-only operations, or to IGarnetApi otherwise (
Garnet.server/API/IGarnetAPI.cs
). - Add a new method to the RespServerSession class. This method will parse the command from the network buffer, call the storage layer API (method declared in step #3) and write the RESP formatted response back to the network buffer (note that the RespServerSession class is divided across several .cs files, object-specific commands will reside under
Garnet.server/Resp/Objects/[ObjectName]Commands.cs
, while others will reside underGarnet.server/Resp/[Admin|Array|Basic|etc...]Commands.cs
, depending on the command type). - Back in
Garnet.server/Resp/RespCommand.cs
, add the new command case to the ProcessBasicCommands or ProcessArrayCommands method respectively, calling the method that was added in step #4. - Add a new method to the StorageSession class. This method is part of the storage layer. This storage API ONLY performs the RMW or Read operation calls, and it wraps the Tsavorite API. (note that the StorageSession class is divided across several .cs files, object store operations will reside under
Garnet.server/Storage/Session/ObjectStore/[ObjectName]Ops.cs
, while main store operations will mainly reside underGarnet.server/Storage/Session/MainStore/MainStoreOps.cs
, with some exceptions).
To implement the storage-level logic of the new command, follow these guidelines according to the new command type:- Single-key object store command: If you are adding a command that operates on a single object, the implementation of this method will simply be a call
[Read|RMW]ObjectStoreOperation[WithOutput]
, which in turn will call theOperate
method inGarnet.server/Objects/[ObjectName]/[ObjectName]Object.cs
, where you will have to add a new case for the command and and the object-specific command implementation inGarnet.server/Objects/[ObjectName]/[ObjectName]ObjectImpl.cs
- Multi-key object store command: If you are adding a command that operates on multiple objects, you may need to create a transaction in which you will appropriately lock the keys (using the
TransactionManager
instance). You can then operate on multiple objects (for instance using theGET
&SET
operations). - Main-store command: If you are adding a command that operates on the main store, you'll need to call Tsavorite's
Read
orRMW
methods. If you are callingRMW
, you will need to implement the initialization and in-place / copy update functionality of the new command inGarnet.server/Storage/Functions/MainStore/RMWMethods.cs
.
- Single-key object store command: If you are adding a command that operates on a single object, the implementation of this method will simply be a call
- If the command supports being called in a transaction context, add a new case for the command in the
TransactionManager.GetKeys
method and return the appropriate key locks required by the command (Garnet.server/Transaction/TxnKeyManager.cs
). - Add tests that run the command and check its output under valid and invalid conditions, test using both
SE.Redis
andLightClient
, if applicable. For object commands, add tests toGarnet.test/Resp[ObjectName]Tests.cs
. For other commands, add toGarnet.test/RespTests.cs
orGarnet.test/Resp[AdminCommands|etc...]Tests.cs
, depending on the command type. - Add newly supported command documentation to the appropriate markdown file under
website/docs/commands/
, and specify the command as supported inwebsite/docs/commands/api-compatibility.md
. - Add command info by following the next section
Before you start implementing your command logic, add a basic test that calls the new command, it will be easier to debug and implement missing logic as you go along.
Adding command info
Each supported RESP command in Garnet should have an entry in Garnet.server/Resp/RespCommandsInfo.json
, specifying the command's info.
A command's info can be added manually, but we recommend using the CommandInfoUpdater
tool to update the JSON file (can be found under playground/
).
The CommandInfoUpdater
tool calculates the difference between existing commands in Garnet.server/Resp/RespCommandsInfo.json
and commands specified in CommandInfoUpdater/SupportedCommands.cs
. It then attempts to add / remove commands' info as necessary.
Info for Garnet-only commands is retrieved from CommandInfoUpdater/GarnetCommandsInfo.json
, and info for other RESP commands is retrieved from an external RESP server (which you will need to run locally / have access to in order to run this tool).
To add command info to Garnet, follow these steps:
- Add the supported command and its supported sub-commands (if applicable) to
CommandInfoUpdater/SupportedCommands.cs
. - If you are adding a Garnet-specific command, add its info to
CommandInfoUpdater/GarnetCommandsInfo.json
. - Build & run the tool (for syntax help run the tool with
-h
or--help
).