...
1
16
17 package io
18
19 import (
20 "bytes"
21 "errors"
22 "fmt"
23 "io"
24 "io/ioutil"
25 )
26
27
28 var ErrLimitReached = errors.New("the read limit is reached")
29
30
31
32
33
34
35
36 func ConsistentRead(filename string, attempts int) ([]byte, error) {
37 return consistentReadSync(filename, attempts, nil)
38 }
39
40
41
42
43 func consistentReadSync(filename string, attempts int, sync func(int)) ([]byte, error) {
44 oldContent, err := ioutil.ReadFile(filename)
45 if err != nil {
46 return nil, err
47 }
48 for i := 0; i < attempts; i++ {
49 if sync != nil {
50 sync(i)
51 }
52 newContent, err := ioutil.ReadFile(filename)
53 if err != nil {
54 return nil, err
55 }
56 if bytes.Compare(oldContent, newContent) == 0 {
57 return newContent, nil
58 }
59
60 oldContent = newContent
61 }
62 return nil, InconsistentReadError{filename, attempts}
63 }
64
65
66
67
68 type InconsistentReadError struct {
69 filename string
70 attempts int
71 }
72
73 func (i InconsistentReadError) Error() string {
74 return fmt.Sprintf("could not get consistent content of %s after %d attempts", i.filename, i.attempts)
75 }
76
77 var _ error = InconsistentReadError{}
78
79 func IsInconsistentReadError(err error) bool {
80 if _, ok := err.(InconsistentReadError); ok {
81 return true
82 }
83 return false
84 }
85
86
87
88 func ReadAtMost(r io.Reader, limit int64) ([]byte, error) {
89 limitedReader := &io.LimitedReader{R: r, N: limit}
90 data, err := ioutil.ReadAll(limitedReader)
91 if err != nil {
92 return data, err
93 }
94 if limitedReader.N <= 0 {
95 return data, ErrLimitReached
96 }
97 return data, nil
98 }
99
View as plain text