forked from microsoft/garnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bring custom object store commands in parity with custom raw string c…
…ommands. (microsoft#499) This change brings in support for CustomObjectFunctions which provides high level of control when authoring custom object commands similar to that of custom raw string commands that already exists. Benchmark (.net 8) main branch |Method |Mean |Error |StdDev | Allocated | |----------------|----------|-----------|----------|------------| |ZAddRem |190.6 us | 1.58 us | 1.48 us | 23 KB | |MyDictSetGet |270.6 us | 1.04 us | 0.81 us | 30 KB | This PR |Method |Mean |Error |StdDev |Allocated| |----------------|----------|-----------|----------|------------| |ZAddRem | 192.7 us | 0.86 us | 0.76 us | 23 KB | |MyDictSetGet | 275.3 us | 1.63 us | 1.53 us | 30 KB |
- Loading branch information
Showing
31 changed files
with
681 additions
and
212 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
using System; | ||
using System.Buffers; | ||
using System.Diagnostics; | ||
using Garnet.common; | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT license. | ||
|
||
namespace Garnet.server | ||
{ | ||
public static class CustomCommandUtils | ||
{ | ||
/// <summary> | ||
/// Shared memory pool used by functions | ||
/// </summary> | ||
private static MemoryPool<byte> MemoryPool => MemoryPool<byte>.Shared; | ||
|
||
/// <summary> | ||
/// Get first arg from input | ||
/// </summary> | ||
/// <param name="input"></param> | ||
/// <returns></returns> | ||
public static ReadOnlySpan<byte> GetFirstArg(ReadOnlySpan<byte> input) | ||
{ | ||
int offset = 0; | ||
return GetNextArg(input, ref offset); | ||
} | ||
|
||
/// <summary> | ||
/// Get argument from input, at specified offset (starting from 0) | ||
/// </summary> | ||
/// <param name="input">Input as ReadOnlySpan of byte</param> | ||
/// <param name="offset">Current offset into input</param> | ||
/// <returns>Argument as a span</returns> | ||
public static unsafe ReadOnlySpan<byte> GetNextArg(ReadOnlySpan<byte> input, scoped ref int offset) | ||
{ | ||
byte* result = null; | ||
var len = 0; | ||
|
||
fixed (byte* inputPtr = input) | ||
{ | ||
var ptr = inputPtr + offset; | ||
var end = inputPtr + input.Length; | ||
if (ptr < end && RespReadUtils.ReadPtrWithLengthHeader(ref result, ref len, ref ptr, end)) | ||
{ | ||
offset = (int)(ptr - inputPtr); | ||
return new ReadOnlySpan<byte>(result, len); | ||
} | ||
} | ||
return default; | ||
} | ||
|
||
/// <summary> | ||
/// Create output as bulk string, from given Span | ||
/// </summary> | ||
public static unsafe void WriteBulkString(ref (IMemoryOwner<byte>, int) output, Span<byte> bulkString) | ||
{ | ||
// Get space for bulk string | ||
var len = RespWriteUtils.GetBulkStringLength(bulkString.Length); | ||
output.Item1 = MemoryPool.Rent(len); | ||
output.Item2 = len; | ||
fixed (byte* ptr = output.Item1.Memory.Span) | ||
{ | ||
var curr = ptr; | ||
// NOTE: Expected to always have enough space to write into pre-allocated buffer | ||
var success = RespWriteUtils.WriteBulkString(bulkString, ref curr, ptr + len); | ||
Debug.Assert(success, "Insufficient space in pre-allocated buffer"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Create output as error message, from given string | ||
/// </summary> | ||
public static unsafe void WriteError(ref (IMemoryOwner<byte>, int) output, string errorMessage) | ||
{ | ||
var bytes = System.Text.Encoding.ASCII.GetBytes(errorMessage); | ||
// Get space for error | ||
var len = 1 + bytes.Length + 2; | ||
output.Item1 = MemoryPool.Rent(len); | ||
fixed (byte* ptr = output.Item1.Memory.Span) | ||
{ | ||
var curr = ptr; | ||
// NOTE: Expected to always have enough space to write into pre-allocated buffer | ||
var success = RespWriteUtils.WriteError(bytes, ref curr, ptr + len); | ||
Debug.Assert(success, "Insufficient space in pre-allocated buffer"); | ||
} | ||
output.Item2 = len; | ||
} | ||
|
||
/// <summary> | ||
/// Create null output as bulk string | ||
/// </summary> | ||
public static unsafe void WriteNullBulkString(ref (IMemoryOwner<byte>, int) output) | ||
{ | ||
// Get space for null bulk string "$-1\r\n" | ||
var len = 5; | ||
output.Item1 = MemoryPool.Rent(len); | ||
output.Item2 = len; | ||
fixed (byte* ptr = output.Item1.Memory.Span) | ||
{ | ||
var curr = ptr; | ||
// NOTE: Expected to always have enough space to write into pre-allocated buffer | ||
var success = RespWriteUtils.WriteNull(ref curr, ptr + len); | ||
Debug.Assert(success, "Insufficient space in pre-allocated buffer"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Create output as simple string, from given string | ||
/// </summary> | ||
public static unsafe void WriteSimpleString(ref (IMemoryOwner<byte>, int) output, string simpleString) | ||
{ | ||
var bytes = System.Text.Encoding.ASCII.GetBytes(simpleString); | ||
// Get space for simple string | ||
var len = 1 + bytes.Length + 2; | ||
output.Item1 = MemoryPool.Rent(len); | ||
fixed (byte* ptr = output.Item1.Memory.Span) | ||
{ | ||
var curr = ptr; | ||
// NOTE: Expected to always have enough space to write into pre-allocated buffer | ||
var success = RespWriteUtils.WriteSimpleString(bytes, ref curr, ptr + len); | ||
Debug.Assert(success, "Insufficient space in pre-allocated buffer"); | ||
} | ||
output.Item2 = len; | ||
} | ||
} | ||
} |
Oops, something went wrong.