[2.x] fix: Drop net.openhft farmNa, use MurmurHash3 in HashUtil

`HashUtil.farmHash` and `BootServerSocket.socketLocation` called
`LongHashFunction.farmNa()` from zero-allocation-hashing, whose impl
uses `sun.misc.Unsafe` and triggers the terminally-deprecated warning
on JDK 23+. Replaced with two `scala.util.hashing.MurmurHash3` calls
composed into a 64-bit Long. Matches @eed3si9n's suggestion in the
issue thread.

The `farmHash` method name and `"farm64-"` cache-string prefix are
kept for source compatibility. Existing on-disk caches keyed on
`farm64-<hex>` see a one-time cold rebuild after upgrade.

Fixes sbt/sbt#8073.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Brian Hotopp 2026-05-22 11:05:47 -04:00
parent 9583a97e89
commit 7ec0dbc4eb
4 changed files with 26 additions and 7 deletions

View File

@ -28,7 +28,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import net.openhft.hashing.LongHashFunction;
import org.scalasbt.ipcsocket.UnixDomainServerSocket;
import org.scalasbt.ipcsocket.Win32NamedPipeServerSocket;
import org.scalasbt.ipcsocket.Win32SecurityLevel;
@ -303,7 +302,7 @@ public class BootServerSocket implements AutoCloseable {
public static String socketLocation(final Path base)
throws UnsupportedEncodingException, IOException {
final Path target = base.resolve("project").resolve("target");
long hash = LongHashFunction.farmNa().hashBytes(target.toString().getBytes("UTF-8"));
long hash = sbt.util.HashUtil.farmHash(target.toString().getBytes("UTF-8"));
if (isWindows) {
return "sbt-load" + hash;
} else {

View File

@ -0,0 +1,18 @@
## Internal hash function: FarmHash → MurmurHash3
The internal `farmHash` used for cache-key derivation
(`HashUtil.farmHash`, `BootServerSocket.socketLocation`) is now
implemented as two `scala.util.hashing.MurmurHash3` calls composed
into a 64-bit `Long`. Previously it called
`net.openhft.hashing.LongHashFunction.farmNa()`, whose impl uses
`sun.misc.Unsafe` and triggers the terminally-deprecated warning
under JDK 23+.
The `"farm64-"` cache-string prefix is retained for source
compatibility. Existing on-disk caches keyed on `farm64-<hex>` will
see a one-time cold rebuild after upgrade — no data loss; first
build after upgrade recomputes the hash on touched inputs.
Fixes [#8073][i8073].
[i8073]: https://github.com/sbt/sbt/issues/8073

View File

@ -1,11 +1,13 @@
package sbt.util
import java.nio.file.{ Files, Path }
import net.openhft.hashing.LongHashFunction
import scala.util.hashing.MurmurHash3
object HashUtil:
private[sbt] def farmHash(bytes: Array[Byte]): Long =
LongHashFunction.farmNa().hashBytes(bytes)
val hi = MurmurHash3.bytesHash(bytes, 0x9747b28c)
val lo = MurmurHash3.bytesHash(bytes, 0x85ebca6b)
(hi.toLong << 32) | (lo.toLong & 0xffffffffL)
private[sbt] def farmHash(path: Path): Long =
import sbt.io.Hash

View File

@ -8,9 +8,9 @@ import xsbti.HashedVirtualFileRef
object HasherTest extends BasicTestSuite:
final val blankContentHash = -7286425919675154353L
val blankContentHashStr = "farm64-9ae16a3b2f90404f"
final val blankATxtHash = 1166939303L
final val blankContentHash = -1461767548567390449L
val blankContentHashStr = "farm64-ebb6c228cb72770f"
final val blankATxtHash = -1644914753
test("The IntJsonFormat should convert an Int to an int hash") {
import BasicJsonProtocol.given