mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-04 15:35:38 +00:00
WIP
Change-Id: Ibc7de639b31ed85c1270f5f9a889b4e6b4228be7 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
ab60f28227
commit
4acfd07815
@ -424,11 +424,56 @@ func genHashPtrToMemoryRange(eleType reflect.Type) typeHasherFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const debug = false
|
const debug = true
|
||||||
|
|
||||||
|
// canMaybeFastPath reports whether t is a type that we might be able to
|
||||||
|
// hash quickly at runtime with a typeHasherFunc.
|
||||||
|
//
|
||||||
|
// If it returns false, the slow path should be used directly.
|
||||||
|
func canMaybeFastPath(t reflect.Type) (ret bool) {
|
||||||
|
defer func() {
|
||||||
|
if !ret {
|
||||||
|
log.Printf("Can't on %v", t)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
ti := getTypeInfo(t)
|
||||||
|
if ti.isRecursive {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Map, reflect.Interface, reflect.Func, reflect.UnsafePointer, reflect.Chan:
|
||||||
|
return false
|
||||||
|
case reflect.Array:
|
||||||
|
return t.Size() == 0 || canMaybeFastPath(t.Elem())
|
||||||
|
case reflect.Slice, reflect.Pointer:
|
||||||
|
return canMaybeFastPath(t.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
if t == timeTimeType || t.Implements(appenderToType) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for i, n := 0, t.NumField(); i < n; i++ {
|
||||||
|
sf := t.Field(i)
|
||||||
|
if sf.Type.Size() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !canMaybeFastPath(sf.Type) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func genTypeHasher(t reflect.Type) typeHasherFunc {
|
func genTypeHasher(t reflect.Type) typeHasherFunc {
|
||||||
|
fastable := canMaybeFastPath(t)
|
||||||
if debug {
|
if debug {
|
||||||
log.Printf("generating func for %v", t)
|
log.Printf("generating func for %v; fastable=%v", t, fastable)
|
||||||
|
}
|
||||||
|
if !fastable {
|
||||||
|
return func(h *hasher, v reflect.Value) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
@ -317,6 +317,45 @@ type RecursiveStruct struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCanMaybeFastPath(t *testing.T) {
|
||||||
|
type RecursiveStruct struct {
|
||||||
|
v *RecursiveStruct
|
||||||
|
}
|
||||||
|
type RecursiveChan chan *RecursiveChan
|
||||||
|
type FastStruct struct{ _, _ string }
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
val any
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{val: 42, want: true},
|
||||||
|
{val: "string", want: true},
|
||||||
|
{val: 1 + 2i, want: true},
|
||||||
|
{val: struct{}{}, want: true},
|
||||||
|
{val: (*RecursiveStruct)(nil), want: false},
|
||||||
|
{val: RecursiveStruct{}, want: false},
|
||||||
|
{val: FastStruct{}, want: true},
|
||||||
|
{val: time.Unix(0, 0), want: true},
|
||||||
|
{val: structs.Incomparable{}, want: true}, // ignore its [0]func()
|
||||||
|
{val: tailcfg.NetPortRange{}, want: true}, // uses structs.Incomparable
|
||||||
|
{val: (*tailcfg.Node)(nil), want: true},
|
||||||
|
{val: map[string]bool{}, want: false},
|
||||||
|
{val: func() {}, want: false},
|
||||||
|
{val: make(chan int), want: false},
|
||||||
|
{val: unsafe.Pointer(nil), want: false},
|
||||||
|
{val: make(RecursiveChan), want: false},
|
||||||
|
{val: make(chan int), want: false},
|
||||||
|
{val: tailcfg.SSHRule{}, want: false}, // contains a map
|
||||||
|
{val: (*tailcfg.SSHRule)(nil), want: false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := canMaybeFastPath(reflect.TypeOf(tt.val))
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("for type %T: got %v, want %v", tt.val, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type IntThenByte struct {
|
type IntThenByte struct {
|
||||||
i int
|
i int
|
||||||
b byte
|
b byte
|
||||||
@ -611,6 +650,17 @@ func TestGetTypeHasher(t *testing.T) {
|
|||||||
val: &tailcfg.Node{},
|
val: &tailcfg.Node{},
|
||||||
out: "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x140001-01-01T00:00:00Z\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x140001-01-01T00:00:00Z\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
out: "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x140001-01-01T00:00:00Z\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x140001-01-01T00:00:00Z\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "no_hashing_for_mixed_fast_slow_type",
|
||||||
|
val: struct {
|
||||||
|
A, B string
|
||||||
|
M map[string]string
|
||||||
|
}{
|
||||||
|
"foo", "bar", map[string]string{"alice": "bob"},
|
||||||
|
},
|
||||||
|
want: false,
|
||||||
|
out: "", // no "foo" or "bar" included
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user