Skip to content

Commit

Permalink
builtins: refactor bit shifting logic in mapToUnorderedUniqueInt
Browse files Browse the repository at this point in the history
This patch refactors the bit shifting logic in `mapToUnorderedUniqueInt`
to use constants instead of magic numbers.

Release note: None
  • Loading branch information
andyyang890 committed Aug 3, 2023
1 parent 56b8c1c commit a7fe6cf
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 17 deletions.
10 changes: 6 additions & 4 deletions pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -9796,11 +9796,13 @@ func GenerateUniqueUnorderedID(instanceID base.SQLInstanceID) tree.DInt {
// serial unique uint64 to an unordered unique int64. It accomplishes this by
// reversing the timestamp portion of the unique ID. This bit manipulation
// should preserve the number of 1-bits.
func mapToUnorderedUniqueInt(val uint64) uint64 {
func mapToUnorderedUniqueInt(uniqueInt uint64) uint64 {
// val is [0][48 bits of ts][15 bits of node id]
ts := (val & ((uint64(math.MaxUint64) >> 16) << 15)) >> 15
v := (bits.Reverse64(ts) >> 1) | (val & (1<<15 - 1))
return v
ts := uniqueInt & builtinconstants.UniqueIntTimestampMask
nodeID := uniqueInt & builtinconstants.UniqueIntNodeIDMask
reversedTS := bits.Reverse64(ts<<builtinconstants.UniqueIntLeadingZeroBits) << builtinconstants.UniqueIntNodeIDBits
unorderedUniqueInt := reversedTS | nodeID
return unorderedUniqueInt
}

// ProcessUniqueID is an ID which is unique to this process in the cluster.
Expand Down
60 changes: 47 additions & 13 deletions pkg/sql/sem/builtins/builtins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,54 @@ func TestGenerateUniqueIDOrder(t *testing.T) {
}
}

// TestMapToUniqueUnorderedID verifies that the mapping preserves the ones count.
func TestMapToUniqueUnorderedID(t *testing.T) {
func TestMapToUnorderedUniqueInt(t *testing.T) {
defer leaktest.AfterTest(t)()
for i := 0; i < 30; i++ {
// RandInput is [0][63 random bits].
randInput := uint64(rand.Int63())
output := mapToUnorderedUniqueInt(randInput)

inputOnesCount := bits.OnesCount64(randInput)
outputOnesCount := bits.OnesCount64(output)
require.Equalf(t, inputOnesCount, outputOnesCount, "input: %b, output: "+
"%b\nExpected: %d, got: %d", randInput, output, inputOnesCount,
outputOnesCount)
}
defer log.Scope(t).Close(t)

t.Run("preserves number of one bits", func(t *testing.T) {
for i := 0; i < 30; i++ {
// RandInput is [0][63 random bits].
randInput := uint64(rand.Int63())
output := mapToUnorderedUniqueInt(randInput)

inputOnesCount := bits.OnesCount64(randInput)
outputOnesCount := bits.OnesCount64(output)
require.Equalf(t, inputOnesCount, outputOnesCount, "input: %b, output: "+
"%b\nExpected: %d, got: %d", randInput, output, inputOnesCount,
outputOnesCount)
}
})

t.Run("correctly reverses timestamp", func(t *testing.T) {
for name, tc := range map[string]struct {
input uint64
expected uint64
}{
"asymmetrical timestamp": {
input: 0b0101100000000000000000000000000000000000000000000000000000000001,
expected: 0b0000000000000000000000000000000000000000000001101000000000000001,
},
"symmetrical timestamp": {
input: 0b0100000000000000000000000000000000000000000000001000000000000101,
expected: 0b0100000000000000000000000000000000000000000000001000000000000101,
},
"max timestamp": {
input: 0b0111111111111111111111111111111111111111111111111000000000000001,
expected: 0b0111111111111111111111111111111111111111111111111000000000000001,
},
} {
t.Run(name, func(t *testing.T) {
actual := mapToUnorderedUniqueInt(tc.input)
require.Equalf(t,
tc.expected, actual,
"actual unordered unique int does not match expected:\n"+
"%064b (expected)\n"+
"%064b (actual)",
tc.expected, actual,
)
})
}
})
}

// TestSerialNormalizationWithUniqueUnorderedID makes sure that serial
Expand Down

0 comments on commit a7fe6cf

Please sign in to comment.