فهرست منبع

lib/ur: Track new folder feature usage (#6803)

Audrius Butkevicius 5 سال پیش
والد
کامیت
9d4a700829
4فایلهای تغییر یافته به همراه180 افزوده شده و 6 حذف شده
  1. 10 6
      lib/ur/contract/contract.go
  2. 13 0
      lib/ur/usage_report.go
  3. 32 0
      lib/util/utils.go
  4. 125 0
      lib/util/utils_test.go

+ 10 - 6
lib/ur/contract/contract.go

@@ -13,6 +13,8 @@ import (
 	"reflect"
 	"strconv"
 	"time"
+
+	"github.com/syncthing/syncthing/lib/util"
 )
 
 type Report struct {
@@ -119,6 +121,13 @@ type Report struct {
 		PullOrder               map[string]int `json:"pullOrder,omitempty" since:"3"`
 		FilesystemType          map[string]int `json:"filesystemType,omitempty" since:"3"`
 		FsWatcherDelays         []int          `json:"fsWatcherDelays,omitempty" since:"3"`
+		CustomMarkerName        int            `json:"customMarkerName,omitempty" since:"3"`
+		CopyOwnershipFromParent int            `json:"copyOwnershipFromParent,omitempty" since:"3"`
+		ModTimeWindowS          []int          `json:"modTimeWindowS,omitempty" since:"3"`
+		MaxConcurrentWrites     []int          `json:"maxConcurrentWrites,omitempty" since:"3"`
+		DisableFsync            int            `json:"disableFsync,omitempty" since:"3"`
+		BlockPullOrder          map[string]int `json:"blockPullOrder,omitempty" since:"3"`
+		CopyRangeMethod         map[string]int `json:"copyRangeMethod,omitempty" since:"3"`
 	} `json:"folderUsesV3,omitempty" since:"3"`
 
 	GUIStats struct {
@@ -164,12 +173,7 @@ type Report struct {
 
 func New() *Report {
 	r := &Report{}
-	r.FolderUsesV3.PullOrder = make(map[string]int)
-	r.FolderUsesV3.FilesystemType = make(map[string]int)
-	r.GUIStats.Theme = make(map[string]int)
-	r.TransportStats = make(map[string]int)
-	r.RescanIntvs = make([]int, 0)
-	r.FolderUsesV3.FsWatcherDelays = make([]int, 0)
+	util.FillNil(r)
 	return r
 }
 

+ 13 - 0
lib/ur/usage_report.go

@@ -256,6 +256,19 @@ func (s *Service) reportData(ctx context.Context, urVersion int, preview bool) (
 			report.FolderUsesV3.PullOrder[cfg.Order.String()]++
 			report.FolderUsesV3.FilesystemType[cfg.FilesystemType.String()]++
 			report.FolderUsesV3.FsWatcherDelays = append(report.FolderUsesV3.FsWatcherDelays, cfg.FSWatcherDelayS)
+			if cfg.MarkerName != config.DefaultMarkerName {
+				report.FolderUsesV3.CustomMarkerName++
+			}
+			if cfg.CopyOwnershipFromParent {
+				report.FolderUsesV3.CopyOwnershipFromParent++
+			}
+			report.FolderUsesV3.ModTimeWindowS = append(report.FolderUsesV3.ModTimeWindowS, int(cfg.ModTimeWindow().Seconds()))
+			report.FolderUsesV3.MaxConcurrentWrites = append(report.FolderUsesV3.MaxConcurrentWrites, cfg.MaxConcurrentWrites)
+			if cfg.DisableFsync {
+				report.FolderUsesV3.DisableFsync++
+			}
+			report.FolderUsesV3.BlockPullOrder[cfg.BlockPullOrder.String()]++
+			report.FolderUsesV3.CopyRangeMethod[cfg.CopyRangeMethod.String()]++
 		}
 		sort.Ints(report.FolderUsesV3.FsWatcherDelays)
 

+ 32 - 0
lib/util/utils.go

@@ -137,6 +137,38 @@ func UniqueTrimmedStrings(ss []string) []string {
 	return us
 }
 
+func FillNil(data interface{}) {
+	s := reflect.ValueOf(data).Elem()
+	for i := 0; i < s.NumField(); i++ {
+		f := s.Field(i)
+
+		for f.Kind() == reflect.Ptr && f.IsZero() && f.CanSet() {
+			newValue := reflect.New(f.Type().Elem())
+			f.Set(newValue)
+			f = f.Elem()
+		}
+
+		if f.CanSet() {
+			if f.IsZero() {
+				switch f.Kind() {
+				case reflect.Map:
+					f.Set(reflect.MakeMap(f.Type()))
+				case reflect.Slice:
+					f.Set(reflect.MakeSlice(f.Type(), 0, 0))
+				case reflect.Chan:
+					f.Set(reflect.MakeChan(f.Type(), 0))
+				}
+			}
+
+			if f.Kind() == reflect.Struct && f.CanAddr() {
+				if addr := f.Addr(); addr.CanInterface() {
+					FillNil(addr.Interface())
+				}
+			}
+		}
+	}
+}
+
 // FillNilSlices sets default value on slices that are still nil.
 func FillNilSlices(data interface{}) error {
 	s := reflect.ValueOf(data).Elem()

+ 125 - 0
lib/util/utils_test.go

@@ -287,3 +287,128 @@ func TestUtilStopTwicePanic(t *testing.T) {
 	}()
 	s.Stop()
 }
+
+func TestFillNil(t *testing.T) {
+	type A struct {
+		Slice []int
+		Map   map[string]string
+		Chan  chan int
+	}
+
+	type B struct {
+		Slice *[]int
+		Map   *map[string]string
+		Chan  *chan int
+	}
+
+	type C struct {
+		A A
+		B *B
+		D *****[]int
+	}
+
+	c := C{}
+	FillNil(&c)
+
+	if c.A.Slice == nil {
+		t.Error("c.A.Slice")
+	}
+	if c.A.Map == nil {
+		t.Error("c.A.Slice")
+	}
+	if c.A.Chan == nil {
+		t.Error("c.A.Chan")
+	}
+	if c.B == nil {
+		t.Error("c.B")
+	}
+	if c.B.Slice == nil {
+		t.Error("c.B.Slice")
+	}
+	if c.B.Map == nil {
+		t.Error("c.B.Slice")
+	}
+	if c.B.Chan == nil {
+		t.Error("c.B.Chan")
+	}
+	if *c.B.Slice == nil {
+		t.Error("*c.B.Slice")
+	}
+	if *c.B.Map == nil {
+		t.Error("*c.B.Slice")
+	}
+	if *c.B.Chan == nil {
+		t.Error("*c.B.Chan")
+	}
+	if *****c.D == nil {
+		t.Error("c.D")
+	}
+}
+
+func TestFillNilDoesNotBulldozeSetFields(t *testing.T) {
+	type A struct {
+		Slice []int
+		Map   map[string]string
+		Chan  chan int
+	}
+
+	type B struct {
+		Slice *[]int
+		Map   *map[string]string
+		Chan  *chan int
+	}
+
+	type C struct {
+		A A
+		B *B
+		D **[]int
+	}
+
+	ch := make(chan int, 10)
+	d := make([]int, 10)
+	dd := &d
+
+	c := C{
+		A: A{
+			Slice: []int{1},
+			Map: map[string]string{
+				"k": "v",
+			},
+			Chan: make(chan int, 10),
+		},
+		B: &B{
+			Slice: &[]int{1},
+			Map: &map[string]string{
+				"k": "v",
+			},
+			Chan: &ch,
+		},
+		D: &dd,
+	}
+	FillNil(&c)
+
+	if len(c.A.Slice) != 1 {
+		t.Error("c.A.Slice")
+	}
+	if len(c.A.Map) != 1 {
+		t.Error("c.A.Slice")
+	}
+	if cap(c.A.Chan) != 10 {
+		t.Error("c.A.Chan")
+	}
+	if c.B == nil {
+		t.Error("c.B")
+	}
+	if len(*c.B.Slice) != 1 {
+		t.Error("c.B.Slice")
+	}
+	if len(*c.B.Map) != 1 {
+		t.Error("c.B.Slice")
+	}
+	if cap(*c.B.Chan) != 10 {
+		t.Error("c.B.Chan")
+	}
+	if cap(**c.D) != 10 {
+		t.Error("c.D")
+	}
+}