github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/test/file.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package test 22 23 import ( 24 "math" 25 "math/rand" 26 27 "github.com/m3db/m3/src/x/os" 28 ) 29 30 // corruptingFile implements the xos.File interface and can corrupt all writes issued 31 // to it based on a configurable probability. 32 type corruptingFile struct { 33 fd xos.File 34 corruptionProbability float64 35 rng *rand.Rand 36 } 37 38 // NewCorruptingFile creates a new corrupting file. 39 func NewCorruptingFile( 40 fd xos.File, 41 corruptionProbability float64, 42 seed int64, 43 ) xos.File { 44 return &corruptingFile{ 45 fd: fd, 46 corruptionProbability: corruptionProbability, 47 rng: rand.New(rand.NewSource(seed)), 48 } 49 } 50 51 // Write to the underlying file with a chance of corrupting it. 52 func (c *corruptingFile) Write(p []byte) (int, error) { 53 threshold := uint64(c.corruptionProbability * float64(math.MaxUint64)) 54 if c.rng.Uint64() <= threshold { 55 var ( 56 byteStart int 57 byteOffset int 58 ) 59 if len(p) > 1 { 60 byteStart = rand.Intn(len(p) - 1) 61 byteOffset = rand.Intn(len(p) - 1 - byteStart) 62 } 63 64 if byteStart >= 0 && byteStart+byteOffset < len(p) { 65 copy(p[byteStart:byteStart+byteOffset], make([]byte, byteOffset)) 66 } 67 } 68 return c.fd.Write(p) 69 } 70 71 // Sync fsyncs the underlying file. 72 func (c *corruptingFile) Sync() error { 73 return c.fd.Sync() 74 } 75 76 // Close the underlying file. 77 func (c *corruptingFile) Close() error { 78 return c.fd.Close() 79 }