File tree Expand file tree Collapse file tree 2 files changed +54
-1
lines changed
main/kotlin/com/statsig/sdk
test/java/com/statsig/sdk Expand file tree Collapse file tree 2 files changed +54
-1
lines changed Original file line number Diff line number Diff line change @@ -14,6 +14,10 @@ enum class HashAlgo {
14
14
15
15
class Hashing {
16
16
companion object {
17
+ private val threadLocalDigest: ThreadLocal <MessageDigest > = ThreadLocal .withInitial {
18
+ MessageDigest .getInstance(" SHA-256" )
19
+ }
20
+
17
21
fun djb2 (input : String ): String {
18
22
var hash = 0
19
23
for (element in input) {
@@ -36,7 +40,8 @@ class Hashing {
36
40
}
37
41
38
42
fun sha256ToLong (input : String ): Long {
39
- val md = MessageDigest .getInstance(" SHA-256" )
43
+ val md = threadLocalDigest.get()
44
+ md.reset()
40
45
val hashBytes = md.digest(input.toByteArray(Charsets .UTF_8 ))
41
46
// Combine more bytes to increase randomness
42
47
val buffer = ByteBuffer .wrap(hashBytes)
Original file line number Diff line number Diff line change
1
+ package com.statsig.sdk
2
+
3
+ import org.junit.Assert.assertEquals
4
+ import org.junit.Test
5
+ import java.nio.ByteBuffer
6
+ import java.security.MessageDigest
7
+ import java.util.concurrent.Executors
8
+ import java.util.concurrent.TimeUnit
9
+ import kotlin.math.absoluteValue
10
+
11
+ class ThreadLocalHashingTest {
12
+
13
+ @Test
14
+ fun testSingleSha256ToLong () {
15
+ val input = " test"
16
+ val expected = generateSha256ToLongExpected(input)
17
+ val result = Hashing .sha256ToLong(input)
18
+ assertEquals(expected, result)
19
+ }
20
+
21
+ @Test
22
+ fun testConcurrentSha256ToLong () {
23
+ val executor = Executors .newFixedThreadPool(10 )
24
+ val tasks = List (10 ) {
25
+ Runnable {
26
+ repeat(100 ) {
27
+ val input = " test$it "
28
+ val expected = generateSha256ToLongExpected(input)
29
+ val result = Hashing .sha256ToLong(input)
30
+ assertEquals(expected, result)
31
+ }
32
+ }
33
+ }
34
+ tasks.forEach { executor.submit(it) }
35
+ executor.shutdown()
36
+ executor.awaitTermination(1 , TimeUnit .MINUTES )
37
+ }
38
+
39
+ private fun generateSha256ToLongExpected (input : String ): Long {
40
+ val md = MessageDigest .getInstance(" SHA-256" )
41
+ val hashBytes = md.digest(input.toByteArray(Charsets .UTF_8 ))
42
+ val buffer = ByteBuffer .wrap(hashBytes)
43
+ val high = buffer.long
44
+ val low = buffer.long
45
+
46
+ return (high xor low).absoluteValue
47
+ }
48
+ }
You can’t perform that action at this time.
0 commit comments