github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/cmd/mount/test/seekers.go (about) 1 // +build ignore 2 3 // Read lots files with lots of simultaneous seeking to stress test the seek code 4 package main 5 6 import ( 7 "flag" 8 "io" 9 "log" 10 "math/rand" 11 "os" 12 "path/filepath" 13 "sort" 14 "sync" 15 "time" 16 ) 17 18 var ( 19 // Flags 20 iterations = flag.Int("n", 1e6, "Iterations to try") 21 maxBlockSize = flag.Int("b", 1024*1024, "Max block size to read") 22 simultaneous = flag.Int("transfers", 16, "Number of simultaneous files to open") 23 seeksPerFile = flag.Int("seeks", 8, "Seeks per file") 24 mask = flag.Int64("mask", 0, "mask for seek, eg 0x7fff") 25 ) 26 27 func init() { 28 rand.Seed(time.Now().UnixNano()) 29 } 30 31 func seekTest(n int, file string) { 32 in, err := os.Open(file) 33 if err != nil { 34 log.Fatalf("Couldn't open %q: %v", file, err) 35 } 36 fi, err := in.Stat() 37 if err != nil { 38 log.Fatalf("Couldn't stat %q: %v", file, err) 39 } 40 size := fi.Size() 41 42 // FIXME make sure we try start and end 43 44 maxBlockSize := *maxBlockSize 45 if int64(maxBlockSize) > size { 46 maxBlockSize = int(size) 47 } 48 for i := 0; i < n; i++ { 49 start := rand.Int63n(size) 50 if *mask != 0 { 51 start &^= *mask 52 } 53 blockSize := rand.Intn(maxBlockSize) 54 beyondEnd := false 55 switch rand.Intn(10) { 56 case 0: 57 start = 0 58 case 1: 59 start = size - int64(blockSize) 60 case 2: 61 // seek beyond the end 62 start = size + int64(blockSize) 63 beyondEnd = true 64 default: 65 } 66 if !beyondEnd && int64(blockSize) > size-start { 67 blockSize = int(size - start) 68 } 69 log.Printf("%s: Reading %d from %d", file, blockSize, start) 70 71 _, err = in.Seek(start, io.SeekStart) 72 if err != nil { 73 log.Fatalf("Seek failed on %q: %v", file, err) 74 } 75 76 buf := make([]byte, blockSize) 77 n, err := io.ReadFull(in, buf) 78 if beyondEnd && err == io.EOF { 79 // OK 80 } else if err != nil { 81 log.Fatalf("Read failed on %q: %v (%d)", file, err, n) 82 } 83 } 84 85 err = in.Close() 86 if err != nil { 87 log.Fatalf("Error closing %q: %v", file, err) 88 } 89 } 90 91 // Find all the files in dir 92 func findFiles(dir string) (files []string) { 93 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { 94 if info.Mode().IsRegular() && info.Size() > 0 { 95 files = append(files, path) 96 } 97 return nil 98 }) 99 sort.Strings(files) 100 return files 101 } 102 103 func main() { 104 flag.Parse() 105 args := flag.Args() 106 if len(args) != 1 { 107 log.Fatalf("Require a directory as argument") 108 } 109 dir := args[0] 110 files := findFiles(dir) 111 jobs := make(chan string, *simultaneous) 112 var wg sync.WaitGroup 113 wg.Add(*simultaneous) 114 for i := 0; i < *simultaneous; i++ { 115 go func() { 116 defer wg.Done() 117 for file := range jobs { 118 seekTest(*seeksPerFile, file) 119 } 120 }() 121 } 122 for i := 0; i < *iterations; i++ { 123 i := rand.Intn(len(files)) 124 jobs <- files[i] 125 //jobs <- files[i] 126 } 127 close(jobs) 128 wg.Wait() 129 }