Skip to content

Commit

Permalink
Use non-allocating Int64 key generation (#7413)
Browse files Browse the repository at this point in the history
  • Loading branch information
benaadams authored Sep 13, 2024
1 parent dfaed09 commit 969c4b9
Show file tree
Hide file tree
Showing 8 changed files with 21 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ public long MigratedBlockNumber
set
{
_migratedBlockNumber = value;
_defaultColumn.Set(MigrationBlockNumberKey, MigratedBlockNumber.ToBigEndianByteArrayWithoutLeadingZeros());
_defaultColumn.PutSpan(MigrationBlockNumberKey.Bytes, value.ToBigEndianSpanWithoutLeadingZeros(out _));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public void SetValidators(long finalizingBlockNumber, Address[] validators)
var validatorInfo = new ValidatorInfo(finalizingBlockNumber, _latestFinalizedValidatorsBlockNumber, validators);
var rlp = Rlp.Encode(validatorInfo);
_db.Set(GetKey(finalizingBlockNumber), rlp.Bytes);
_db.Set(LatestFinalizedValidatorsBlockNumberKey, finalizingBlockNumber.ToBigEndianByteArrayWithoutLeadingZeros());
_db.PutSpan(LatestFinalizedValidatorsBlockNumberKey.Bytes, finalizingBlockNumber.ToBigEndianSpanWithoutLeadingZeros(out _));
_latestFinalizedValidatorsBlockNumber = finalizingBlockNumber;
_latestValidatorInfo = validatorInfo;
Metrics.ValidatorsCount = validators.Length;
Expand Down
115 changes: 12 additions & 103 deletions src/Nethermind/Nethermind.Core/Extensions/Int64Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,120 +3,29 @@

using System;
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using Nethermind.Int256;

namespace Nethermind.Core.Extensions;

public static class Int64Extensions
{
public static byte[] ToBigEndianByteArrayWithoutLeadingZeros(this long value)
public static ReadOnlySpan<byte> ToBigEndianSpanWithoutLeadingZeros(this long value, out long buffer)
{
byte byte6 = (byte)(value >> 8);
byte byte5 = (byte)(value >> 16);
byte byte4 = (byte)(value >> 24);
byte byte3 = (byte)(value >> 32);
byte byte2 = (byte)(value >> 40);
byte byte1 = (byte)(value >> 48);
byte byte0 = (byte)(value >> 56);

if (byte0 == 0)
{
if (byte1 == 0)
{
if (byte2 == 0)
{
if (byte3 == 0)
{
if (byte4 == 0)
{
if (byte5 == 0)
{
if (byte6 == 0)
{
byte[] bytes = new byte[1];
bytes[0] = (byte)value;
return bytes;
}
else
{
byte[] bytes = new byte[2];
bytes[1] = (byte)value;
bytes[0] = byte6;
return bytes;
}
}
else
{
byte[] bytes = new byte[3];
bytes[2] = (byte)value;
bytes[1] = byte6;
bytes[0] = byte5;
return bytes;
}
}
else
{
byte[] bytes = new byte[4];
bytes[3] = (byte)value;
bytes[2] = byte6;
bytes[1] = byte5;
bytes[0] = byte4;
return bytes;
}
}
else
{
byte[] bytes = new byte[5];
bytes[4] = (byte)value;
bytes[3] = byte6;
bytes[2] = byte5;
bytes[1] = byte4;
bytes[0] = byte3;
return bytes;
}
}
else
{
byte[] bytes = new byte[6];
bytes[5] = (byte)value;
bytes[4] = byte6;
bytes[3] = byte5;
bytes[2] = byte4;
bytes[1] = byte3;
bytes[0] = byte2;
return bytes;
}
}
else
{
byte[] bytes = new byte[7];
bytes[6] = (byte)value;
bytes[5] = byte6;
bytes[4] = byte5;
bytes[3] = byte4;
bytes[2] = byte3;
bytes[1] = byte2;
bytes[0] = byte1;
return bytes;
}
}
else
{
byte[] bytes = new byte[8];
bytes[7] = (byte)value;
bytes[6] = byte6;
bytes[5] = byte5;
bytes[4] = byte4;
bytes[3] = byte3;
bytes[2] = byte2;
bytes[1] = byte1;
bytes[0] = byte0;
return bytes;
}
// Min 7 bytes as we still want a byte if the value is 0.
var start = Math.Min(BitOperations.LeadingZeroCount((ulong)value) / sizeof(long), sizeof(long) - 1);
// We create the span over the out value to ensure the span stack space remains valid.
buffer = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value;
ReadOnlySpan<byte> span = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref buffer, 1));
return span[start..];
}

public static byte[] ToBigEndianByteArrayWithoutLeadingZeros(this long value)
=> value.ToBigEndianSpanWithoutLeadingZeros(out _).ToArray();

public static byte[] ToBigEndianByteArray(this long value)
{
byte[] bytes = BitConverter.GetBytes(value);
Expand Down
2 changes: 0 additions & 2 deletions src/Nethermind/Nethermind.Core/IKeyValueStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Buffers;
using Nethermind.Core.Buffers;
using Nethermind.Core.Extensions;

namespace Nethermind.Core
Expand Down
10 changes: 5 additions & 5 deletions src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ public static bool KeyExists(this IReadOnlyKeyValueStore db, Hash256 key)

public static bool KeyExists(this IReadOnlyKeyValueStore db, long key)
{
return db.KeyExists(key.ToBigEndianByteArrayWithoutLeadingZeros());
return db.KeyExists(key.ToBigEndianSpanWithoutLeadingZeros(out _));
}

public static byte[]? Get(this IReadOnlyKeyValueStore db, long key) => db[key.ToBigEndianByteArrayWithoutLeadingZeros()];
public static byte[]? Get(this IReadOnlyKeyValueStore db, long key) => db[key.ToBigEndianSpanWithoutLeadingZeros(out _)];

/// <summary>
///
/// </summary>
/// <param name="db"></param>
/// <param name="key"></param>
/// <returns>Can return null or empty Span on missing key</returns>
public static Span<byte> GetSpan(this IReadOnlyKeyValueStore db, long key) => db.GetSpan(key.ToBigEndianByteArrayWithoutLeadingZeros());
public static Span<byte> GetSpan(this IReadOnlyKeyValueStore db, long key) => db.GetSpan(key.ToBigEndianSpanWithoutLeadingZeros(out _));

public static MemoryManager<byte>? GetOwnedMemory(this IReadOnlyKeyValueStore db, ReadOnlySpan<byte> key)
{
Expand Down Expand Up @@ -140,7 +140,7 @@ public static void Delete(this IWriteOnlyKeyValueStore db, Hash256 key)

public static void Delete(this IWriteOnlyKeyValueStore db, long key)
{
db.Remove(key.ToBigEndianByteArrayWithoutLeadingZeros());
db.Remove(key.ToBigEndianSpanWithoutLeadingZeros(out _));
}

[SkipLocalsInit]
Expand All @@ -153,7 +153,7 @@ public static void Delete(this IWriteOnlyKeyValueStore db, long blockNumber, Has

public static void Set(this IWriteOnlyKeyValueStore db, long key, byte[] value)
{
db[key.ToBigEndianByteArrayWithoutLeadingZeros()] = value;
db[key.ToBigEndianSpanWithoutLeadingZeros(out _)] = value;
}

#endregion
Expand Down
1 change: 0 additions & 1 deletion src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using ConcurrentCollections;
using Nethermind.Config;
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Db/Blooms/BloomStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public void Migrate(IEnumerable<BlockHeader> headers)

private void Set(Hash256 key, long value)
{
_bloomInfoDb.Set(key, value.ToBigEndianByteArrayWithoutLeadingZeros());
_bloomInfoDb.PutSpan(key.Bytes, value.ToBigEndianSpanWithoutLeadingZeros(out _));
}

public void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public static class KeyValueStoreRlpExtensions

public static TItem? Get<TItem>(this IReadOnlyKeyValueStore db, long key, IRlpStreamDecoder<TItem>? decoder, LruCache<long, TItem>? cache = null, RlpBehaviors rlpBehaviors = RlpBehaviors.None, bool shouldCache = true) where TItem : class
{
byte[] keyDb = key.ToBigEndianByteArrayWithoutLeadingZeros();
ReadOnlySpan<byte> keyDb = key.ToBigEndianSpanWithoutLeadingZeros(out _);
return Get(db, key, keyDb, decoder, cache, rlpBehaviors, shouldCache);
}

Expand Down

0 comments on commit 969c4b9

Please sign in to comment.