Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
22029c1
lazy uuid generation for SentryId and SpanId
lbloder Oct 7, 2024
f947f82
add changelog
lbloder Oct 7, 2024
debd140
Merge branch '8.x.x' into feat/lazy-span-id-v8
adinauer Oct 9, 2024
e6df0ad
add tests for lazy init, rework SentryId to cache string result
lbloder Oct 11, 2024
8a93fec
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 11, 2024
fe8ccb0
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 15, 2024
28b5bde
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 18, 2024
f2fba85
fix changelog
lbloder Oct 18, 2024
3e1a32c
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 21, 2024
c7ab294
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
f1e66b2
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
76b23c8
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
8599535
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
3bae1d7
Update sentry/src/main/java/io/sentry/protocol/SentryId.java
lbloder Oct 22, 2024
edba0c7
Format code
getsentry-bot Oct 22, 2024
c18a74d
Add object comparison to SpanFrameMetricsCollector only check for tim…
lbloder Oct 22, 2024
35b17db
Merge branch 'feat/lazy-span-id-v8' of github.com:getsentry/sentry-ja…
lbloder Oct 22, 2024
a50d881
add proposed SentryUUID class
lbloder Oct 22, 2024
149d59c
[WIP] use SentryUUID instead of UUID.random().toString
lbloder Oct 22, 2024
6418a33
Format code
getsentry-bot Oct 23, 2024
5314e83
split SentryUUID internals into separate classes for easier attribution
lbloder Oct 29, 2024
58a00c4
Merge branch '8.x.x' into feat/lazy-span-id-v8
lbloder Oct 29, 2024
097738b
add changelog
lbloder Oct 29, 2024
3518fce
Merge branch 'feat/lazy-span-id-v8' into feat/fast-id-generation
lbloder Oct 29, 2024
d11c3cc
fix tests
lbloder Oct 29, 2024
1ea4212
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Oct 29, 2024
81a3bdb
fix SpanId.EMPTY_ID
lbloder Oct 29, 2024
5d00ae5
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Nov 4, 2024
fac412e
test normalized is never called in no-arg constructor, only called on…
lbloder Nov 8, 2024
9f360d1
Merge branch '8.x.x' into feat/fast-id-generation
lbloder Nov 8, 2024
30b2602
fix test
lbloder Nov 8, 2024
05540a3
Format code
getsentry-bot Nov 8, 2024
143c26e
use new Random Generator
lbloder Nov 8, 2024
57d0a9b
Merge branch 'feat/fast-id-generation' of github.com:getsentry/sentry…
lbloder Nov 8, 2024
45c3cbe
fix Sentry Empty ID, replace dashes if 36 char uuid String is passed …
lbloder Nov 8, 2024
5c2c580
fix Tests for SpanId, add tests for SentryUUID and UUIDStringUtils
lbloder Nov 8, 2024
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
Prev Previous commit
Next Next commit
add proposed SentryUUID class
  • Loading branch information
lbloder committed Oct 22, 2024
commit a50d8817909247ed4049e4451df465c78ce9af67
306 changes: 306 additions & 0 deletions sentry/src/main/java/io/sentry/SentryUUID.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
package io.sentry;

import java.util.Arrays;
import java.util.Random;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import java.util.Random;
import io.sentry.util.Random;

import java.util.UUID;

/**
* Utility class for faster id generation for SentryId, SpanId, and unique filenames uses throughout the SDK
* It uses our vendored Random class instead of SecureRandom for improved performance
* It directly creates a correctly formatted String to be used as IDs in the Sentry context.
*
* Id generation is sped up by 4 to 10 times based on the underlying java version.
*
* Based on the work of <a href="https://github.com/jchambers/">Jon Chambers</a>
* Here: https://github.com/jchambers/fast-uuid
*/
public class SentryUUID {

private static final int UUID_STRING_LENGTH = 36;
private static final int SENTRY_UUID_STRING_LENGTH = 32;
private static final int SENTRY_SPAN_UUID_STRING_LENGTH = 16;

private static final char[] HEX_DIGITS =
new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

private static final long[] HEX_VALUES = new long[128];

static {
Arrays.fill(HEX_VALUES, -1);

HEX_VALUES['0'] = 0x0;
HEX_VALUES['1'] = 0x1;
HEX_VALUES['2'] = 0x2;
HEX_VALUES['3'] = 0x3;
HEX_VALUES['4'] = 0x4;
HEX_VALUES['5'] = 0x5;
HEX_VALUES['6'] = 0x6;
HEX_VALUES['7'] = 0x7;
HEX_VALUES['8'] = 0x8;
HEX_VALUES['9'] = 0x9;

HEX_VALUES['a'] = 0xa;
HEX_VALUES['b'] = 0xb;
HEX_VALUES['c'] = 0xc;
HEX_VALUES['d'] = 0xd;
HEX_VALUES['e'] = 0xe;
HEX_VALUES['f'] = 0xf;

HEX_VALUES['A'] = 0xa;
HEX_VALUES['B'] = 0xb;
HEX_VALUES['C'] = 0xc;
HEX_VALUES['D'] = 0xd;
HEX_VALUES['E'] = 0xe;
HEX_VALUES['F'] = 0xf;
}

private SentryUUID() {
// A private constructor prevents callers from accidentally instantiating FastUUID objects
}

/**
* Parses a UUID from the given character sequence. The character sequence must represent a UUID as described in
* {@link UUID#toString()}.
*
* @param uuidSequence the character sequence from which to parse a UUID
*
* @return the UUID represented by the given character sequence
*
* @throws IllegalArgumentException if the given character sequence does not conform to the string representation as
* described in {@link UUID#toString()}
*/
public static UUID parseUUID(final CharSequence uuidSequence) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we even need this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume no, as long as we use String values in the SDK.

if (uuidSequence.length() != UUID_STRING_LENGTH ||
uuidSequence.charAt(8) != '-' ||
uuidSequence.charAt(13) != '-' ||
uuidSequence.charAt(18) != '-' ||
uuidSequence.charAt(23) != '-') {

throw new IllegalArgumentException("Illegal UUID string: " + uuidSequence);
}

long mostSignificantBits = getHexValueForChar(uuidSequence.charAt(0)) << 60;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(1)) << 56;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(2)) << 52;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(3)) << 48;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(4)) << 44;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(5)) << 40;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(6)) << 36;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(7)) << 32;

mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(9)) << 28;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(10)) << 24;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(11)) << 20;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(12)) << 16;

mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(14)) << 12;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(15)) << 8;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(16)) << 4;
mostSignificantBits |= getHexValueForChar(uuidSequence.charAt(17));

long leastSignificantBits = getHexValueForChar(uuidSequence.charAt(19)) << 60;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(20)) << 56;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(21)) << 52;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(22)) << 48;

leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(24)) << 44;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(25)) << 40;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(26)) << 36;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(27)) << 32;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(28)) << 28;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(29)) << 24;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(30)) << 20;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(31)) << 16;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(32)) << 12;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(33)) << 8;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(34)) << 4;
leastSignificantBits |= getHexValueForChar(uuidSequence.charAt(35));

return new UUID(mostSignificantBits, leastSignificantBits);
}

public static String generateSentryId() {
return toSentryIdString(SentryUUID.randomUUID());
}

public static String generateSpanId() {
return toSentrySpanIdString(SentryUUID.randomHalfLengthUUID());
}

/**
* Returns a string representation of the given UUID. The returned string is formatted as described in
* {@link UUID#toString()}.
*
* @param uuid the UUID to represent as a string
*
* @return a string representation of the given UUID
*/
public static String toString(final UUID uuid) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This returns an acutal UUID String including -. Do we need this for our purposes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to replace all UUID usages that have - with simply using the String value without - as it should mostly be for our own IDs and some unique paths.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, will remove this method then.


final long mostSignificantBits = uuid.getMostSignificantBits();
final long leastSignificantBits = uuid.getLeastSignificantBits();

final char[] uuidChars = new char[UUID_STRING_LENGTH];

uuidChars[0] = HEX_DIGITS[(int) ((mostSignificantBits & 0xf000000000000000L) >>> 60)];
uuidChars[1] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0f00000000000000L) >>> 56)];
uuidChars[2] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00f0000000000000L) >>> 52)];
uuidChars[3] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000f000000000000L) >>> 48)];
uuidChars[4] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000f00000000000L) >>> 44)];
uuidChars[5] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000f0000000000L) >>> 40)];
uuidChars[6] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000f000000000L) >>> 36)];
uuidChars[7] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000f00000000L) >>> 32)];
uuidChars[8] = '-';
uuidChars[9] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000f0000000L) >>> 28)];
uuidChars[10] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000f000000L) >>> 24)];
uuidChars[11] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000f00000L) >>> 20)];
uuidChars[12] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000f0000L) >>> 16)];
uuidChars[13] = '-';
uuidChars[14] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000000f000L) >>> 12)];
uuidChars[15] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000000f00L) >>> 8)];
uuidChars[16] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000000f0L) >>> 4)];
uuidChars[17] = HEX_DIGITS[(int) (mostSignificantBits & 0x000000000000000fL)];
uuidChars[18] = '-';
uuidChars[19] = HEX_DIGITS[(int) ((leastSignificantBits & 0xf000000000000000L) >>> 60)];
uuidChars[20] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0f00000000000000L) >>> 56)];
uuidChars[21] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00f0000000000000L) >>> 52)];
uuidChars[22] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000f000000000000L) >>> 48)];
uuidChars[23] = '-';
uuidChars[24] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000f00000000000L) >>> 44)];
uuidChars[25] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000f0000000000L) >>> 40)];
uuidChars[26] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000f000000000L) >>> 36)];
uuidChars[27] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000f00000000L) >>> 32)];
uuidChars[28] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000f0000000L) >>> 28)];
uuidChars[29] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000000f000000L) >>> 24)];
uuidChars[30] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000000f00000L) >>> 20)];
uuidChars[31] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000000f0000L) >>> 16)];
uuidChars[32] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000000000f000L) >>> 12)];
uuidChars[33] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000000000f00L) >>> 8)];
uuidChars[34] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000000000f0L) >>> 4)];
uuidChars[35] = HEX_DIGITS[(int) (leastSignificantBits & 0x000000000000000fL)];

return new String(uuidChars);
}

public static String toSentryIdString(final UUID uuid) {

final long mostSignificantBits = uuid.getMostSignificantBits();
final long leastSignificantBits = uuid.getLeastSignificantBits();

return toSentryIdString(mostSignificantBits, leastSignificantBits);
}

public static String toSentryIdString(long mostSignificantBits, long leastSignificantBits) {
final char[] uuidChars = new char[SENTRY_UUID_STRING_LENGTH];

fillMostSignificantBits(uuidChars, mostSignificantBits);

uuidChars[16] = HEX_DIGITS[(int) ((leastSignificantBits & 0xf000000000000000L) >>> 60)];
uuidChars[17] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0f00000000000000L) >>> 56)];
uuidChars[18] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00f0000000000000L) >>> 52)];
uuidChars[19] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000f000000000000L) >>> 48)];
uuidChars[20] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000f00000000000L) >>> 44)];
uuidChars[21] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000f0000000000L) >>> 40)];
uuidChars[22] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000f000000000L) >>> 36)];
uuidChars[23] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000f00000000L) >>> 32)];
uuidChars[24] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000f0000000L) >>> 28)];
uuidChars[25] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000000f000000L) >>> 24)];
uuidChars[26] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000000f00000L) >>> 20)];
uuidChars[27] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000000f0000L) >>> 16)];
uuidChars[28] = HEX_DIGITS[(int) ((leastSignificantBits & 0x000000000000f000L) >>> 12)];
uuidChars[29] = HEX_DIGITS[(int) ((leastSignificantBits & 0x0000000000000f00L) >>> 8)];
uuidChars[30] = HEX_DIGITS[(int) ((leastSignificantBits & 0x00000000000000f0L) >>> 4)];
uuidChars[31] = HEX_DIGITS[(int) (leastSignificantBits & 0x000000000000000fL)];

return new String(uuidChars);
}

public static String toSentrySpanIdString(final UUID uuid) {

final long mostSignificantBits = uuid.getMostSignificantBits();
return toSentrySpanIdString(mostSignificantBits);

}

public static String toSentrySpanIdString(long mostSignificantBits) {
final char[] uuidChars = new char[SENTRY_SPAN_UUID_STRING_LENGTH];

fillMostSignificantBits(uuidChars, mostSignificantBits);

return new String(uuidChars);
}

private static void fillMostSignificantBits(final char[] uuidChars, final long mostSignificantBits) {
uuidChars[0] = HEX_DIGITS[(int) ((mostSignificantBits & 0xf000000000000000L) >>> 60)];
uuidChars[1] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0f00000000000000L) >>> 56)];
uuidChars[2] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00f0000000000000L) >>> 52)];
uuidChars[3] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000f000000000000L) >>> 48)];
uuidChars[4] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000f00000000000L) >>> 44)];
uuidChars[5] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000f0000000000L) >>> 40)];
uuidChars[6] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000f000000000L) >>> 36)];
uuidChars[7] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000f00000000L) >>> 32)];
uuidChars[8] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000f0000000L) >>> 28)];
uuidChars[9] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000f000000L) >>> 24)];
uuidChars[10] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000f00000L) >>> 20)];
uuidChars[11] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000f0000L) >>> 16)];
uuidChars[12] = HEX_DIGITS[(int) ((mostSignificantBits & 0x000000000000f000L) >>> 12)];
uuidChars[13] = HEX_DIGITS[(int) ((mostSignificantBits & 0x0000000000000f00L) >>> 8)];
uuidChars[14] = HEX_DIGITS[(int) ((mostSignificantBits & 0x00000000000000f0L) >>> 4)];
uuidChars[15] = HEX_DIGITS[(int) (mostSignificantBits & 0x000000000000000fL)];
}

static long getHexValueForChar(final char c) {
try {
if (HEX_VALUES[c] < 0) {
throw new IllegalArgumentException("Illegal hexadecimal digit: " + c);
}
} catch (final ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Illegal hexadecimal digit: " + c);
}

return HEX_VALUES[c];
}

public static long randomHalfLengthUUID() {
Random random = SentryUUID.Holder.numberGenerator;
byte[] randomBytes = new byte[8];
random.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */

long msb = 0;

for (int i=0; i<8; i++)
msb = (msb << 8) | (randomBytes[i] & 0xff);

return msb;
}

public static UUID randomUUID() {
Random random = SentryUUID.Holder.numberGenerator;
byte[] randomBytes = new byte[16];
random.nextBytes(randomBytes);
randomBytes[6] &= 0x0f; /* clear version */
randomBytes[6] |= 0x40; /* set to version 4 */
randomBytes[8] &= 0x3f; /* clear variant */
randomBytes[8] |= (byte) 0x80; /* set to IETF variant */

long msb = 0;
long lsb = 0;

for (int i=0; i<8; i++)
msb = (msb << 8) | (randomBytes[i] & 0xff);

for (int i=8; i<16; i++)
lsb = (lsb << 8) | (randomBytes[i] & 0xff);

return new UUID(msb, lsb);
}

private static class Holder {
static final Random numberGenerator = new Random();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to https://docs.oracle.com/javase/7/docs/api/java/util/Random.html there might be poor performance when using Random from multiple threads.

Instances of java.util.Random are threadsafe. However, the concurrent use of the same java.util.Random instance across threads may encounter contention and consequent poor performance. Consider instead using ThreadLocalRandom in multithreaded designs.

Should we vendor ThreadLocalRandom as well and use that?

Did you also do (performance) testing in a multi threaded environment?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point. No, didn't do multithreaded perf testing. could try to spin up something to compare Random to ThreadLocalRandom

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this does make quite a difference. Below is a comparison for UUID generation:

Benchmark Score   Error Units Threads Comparison
uuidGenerationRandom 23789834,814 ± 117697,18 ops/s 1 100%
uuidGenerationRandomMultiThreaded 2280766,845 ± 263522,36 ops/s 10 10%
uuidGenerationThreadLocalRandomMultiThreaded 185639075,638 ± 5090316,9 ops/s 10 780%

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whew, what's the baseline we're comparing to here? are all of those using the FastUUID code just with a different Random implementation?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code from FastUUID is only responsible for converting the UUID to string. This was not done in this test.

I tested the SentryUUID.randomUUID() function, which is a clone of the java.util.UUID.randomUUID() function with java.util.Random as the random generator.

So, Results 1 and 2 test the above mentioned function in single-threaded vs multi-threaded scenarios.

Result 3 tests the same function with java.util.Random replaced with java.util.concurrent.ThreadLocalRandom. I replaced Random random = SentryUUID.Holder.numberGenerator; with Random random = ThreadLocalRandom.current();

Copy link
Collaborator Author

@lbloder lbloder Oct 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the benchmark code can now be found here: https://github.com/lbloder/sentry-uuid-bench


private Holder() {
}
}
}