Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 9 additions & 1 deletion submitqueue/extension/conflict/tango/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
load("@rules_go//go:def.bzl", "go_library")
load("@rules_go//go:def.bzl", "go_library", "go_test")

go_library(
name = "go_default_library",
srcs = [
"mock_store.go",
"signature.go",
"store.go",
"target_label.go",
"target_signature.go",
Expand All @@ -12,3 +13,10 @@ go_library(
visibility = ["//visibility:public"],
deps = ["@org_uber_go_mock//gomock:go_default_library"],
)

go_test(
name = "go_default_test",
srcs = ["signature_test.go"],
embed = [":go_default_library"],
deps = ["@com_github_stretchr_testify//assert:go_default_library"],
)
88 changes: 88 additions & 0 deletions submitqueue/extension/conflict/tango/signature.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2026 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package tango converts Tango's changed-target responses into target
// signatures and defines the signature and dictionary records.
package tango

import (
"cmp"
"crypto/sha256"
"encoding/binary"
"slices"
)

// targetIDBytes is how much of a label's SHA-256 digest forms its target ID.
// 8 bytes fit a uint64; a collision only adds a false conflict.
const targetIDBytes = 8

// LabelDistance is one affected target: its label exactly as Tango reported it
// and its distance from the nearest directly changed source.
type LabelDistance struct {
// Label is the target label, unmodified from Tango's response.
Label string

// Distance is 0 for a target a change touches directly and grows by one for each dependency edge away from one.
Distance int32
}

// hashedLabel records a label under the target ID it hashes to.
type hashedLabel struct {
id uint64
label string
}

type hashedTarget struct {
hashedLabel
distance int32
}

// targetID returns the first 8 bytes of the SHA-256 of label, read big-endian.
func targetID(label string) uint64 {
digest := sha256.Sum256([]byte(label))
return binary.BigEndian.Uint64(digest[:targetIDBytes])
}

// toSignatureTargets returns the signature targets sorted ascending by ID, one
// per ID at the smallest distance reported for it, and every distinct (ID,
// label) pair sorted by ID then label. targets is not modified. An empty input
// yields nil results, which is a valid signature that conflicts with nothing.
func toSignatureTargets(targets []LabelDistance) ([]SignatureTarget, []hashedLabel) {
hashed := make([]hashedTarget, len(targets))
for i, target := range targets {
hashed[i] = hashedTarget{hashedLabel: hashedLabel{id: targetID(target.Label), label: target.Label}, distance: target.Distance}
}
return mergeHashedTargetsByID(hashed)
}

// mergeHashedTargetsByID sorts hashed in place; callers hand over ownership.
func mergeHashedTargetsByID(hashed []hashedTarget) ([]SignatureTarget, []hashedLabel) {
slices.SortFunc(hashed, func(a, b hashedTarget) int {
return cmp.Or(cmp.Compare(a.id, b.id), cmp.Compare(a.label, b.label))
})

var signatureTargets []SignatureTarget
var labels []hashedLabel
for _, target := range hashed {
if n := len(labels); n == 0 || labels[n-1] != target.hashedLabel {
labels = append(labels, target.hashedLabel)
}
if n := len(signatureTargets); n > 0 && signatureTargets[n-1].ID == target.id {
signatureTargets[n-1].Distance = min(signatureTargets[n-1].Distance, target.distance)
continue
}
signatureTargets = append(signatureTargets, SignatureTarget{ID: target.id, Distance: target.distance})
}
return signatureTargets, labels
}
171 changes: 171 additions & 0 deletions submitqueue/extension/conflict/tango/signature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright (c) 2026 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tango

import (
"testing"

"github.com/stretchr/testify/assert"
)

const (
legacyLabel = "//lib/strutil:legacy"
strutilLabel = "//lib/strutil:strutil"
fuzzTestLabel = "//lib/strutil:fuzz_test"
apiLabel = "//svc/api:api"
apiTestLabel = "//svc/api:api_test"

legacyID = uint64(0x735cc8dafbb93f02)
strutilID = uint64(0x90afc9166e08f639)
fuzzTestID = uint64(0xa9becee9e924a370)
apiID = uint64(0xbb211c1937bbeab8)
apiTestID = uint64(0xc48fa23bb87b90f4)
)

func TestTargetID(t *testing.T) {
tests := []struct {
label string
want uint64
}{
{legacyLabel, legacyID},
{strutilLabel, strutilID},
{fuzzTestLabel, fuzzTestID},
{apiLabel, apiID},
{apiTestLabel, apiTestID},
}
for _, tt := range tests {
t.Run(tt.label, func(t *testing.T) {
assert.Equal(t, tt.want, targetID(tt.label))
})
}
}

func TestToSignatureTargets(t *testing.T) {
tests := []struct {
name string
targets []LabelDistance
wantTarget []SignatureTarget
wantLabels []hashedLabel
}{
{
name: "empty input is an empty signature",
targets: nil,
wantTarget: nil,
wantLabels: nil,
},
{
name: "single target",
targets: []LabelDistance{{Label: apiLabel, Distance: 1}},
wantTarget: []SignatureTarget{{ID: apiID, Distance: 1}},
wantLabels: []hashedLabel{{id: apiID, label: apiLabel}},
},
{
name: "response order is sorted by ID",
targets: []LabelDistance{
{Label: strutilLabel, Distance: 0},
{Label: apiLabel, Distance: 1},
{Label: apiTestLabel, Distance: 2},
{Label: fuzzTestLabel, Distance: 0},
{Label: legacyLabel, Distance: 0},
},
wantTarget: []SignatureTarget{
{ID: legacyID, Distance: 0},
{ID: strutilID, Distance: 0},
{ID: fuzzTestID, Distance: 0},
{ID: apiID, Distance: 1},
{ID: apiTestID, Distance: 2},
},
wantLabels: []hashedLabel{
{id: legacyID, label: legacyLabel},
{id: strutilID, label: strutilLabel},
{id: fuzzTestID, label: fuzzTestLabel},
{id: apiID, label: apiLabel},
{id: apiTestID, label: apiTestLabel},
},
},
{
name: "a repeated label keeps the smaller distance",
targets: []LabelDistance{
{Label: apiLabel, Distance: 3},
{Label: apiLabel, Distance: 1},
{Label: apiLabel, Distance: 2},
},
wantTarget: []SignatureTarget{{ID: apiID, Distance: 1}},
wantLabels: []hashedLabel{{id: apiID, label: apiLabel}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotTargets, gotLabels := toSignatureTargets(tt.targets)

assert.Equal(t, tt.wantTarget, gotTargets)
assert.Equal(t, tt.wantLabels, gotLabels)
})
}
}

func TestToSignatureTargets_LeavesInputUnchanged(t *testing.T) {
targets := []LabelDistance{
{Label: apiTestLabel, Distance: 2},
{Label: legacyLabel, Distance: 0},
{Label: apiLabel, Distance: 1},
}
original := append([]LabelDistance(nil), targets...)

toSignatureTargets(targets)

assert.Equal(t, original, targets)
}

func TestMergeHashedTargetsByID(t *testing.T) {
tests := []struct {
name string
hashed []hashedTarget
wantTarget []SignatureTarget
wantLabels []hashedLabel
}{
{
name: "labels sharing an ID collapse to the smaller distance and both stay in the dictionary",
hashed: []hashedTarget{
{hashedLabel: hashedLabel{id: 7, label: "//b:y"}, distance: 2},
{hashedLabel: hashedLabel{id: 7, label: "//a:x"}, distance: 5},
{hashedLabel: hashedLabel{id: 3, label: "//c:z"}, distance: 0},
},
wantTarget: []SignatureTarget{{ID: 3, Distance: 0}, {ID: 7, Distance: 2}},
wantLabels: []hashedLabel{
{id: 3, label: "//c:z"},
{id: 7, label: "//a:x"},
{id: 7, label: "//b:y"},
},
},
{
name: "colliding labels with equal distances keep one signature entry",
hashed: []hashedTarget{
{hashedLabel: hashedLabel{id: 9, label: "//b:y"}, distance: 1},
{hashedLabel: hashedLabel{id: 9, label: "//a:x"}, distance: 1},
},
wantTarget: []SignatureTarget{{ID: 9, Distance: 1}},
wantLabels: []hashedLabel{{id: 9, label: "//a:x"}, {id: 9, label: "//b:y"}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotTargets, gotLabels := mergeHashedTargetsByID(tt.hashed)

assert.Equal(t, tt.wantTarget, gotTargets)
assert.Equal(t, tt.wantLabels, gotLabels)
})
}
}
Loading