OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / tmlibs / autofile / autofile.go
1 package autofile
2
3 import (
4         "os"
5         "sync"
6         "time"
7
8         . "github.com/tendermint/tmlibs/common"
9 )
10
11 /* AutoFile usage
12
13 // Create/Append to ./autofile_test
14 af, err := OpenAutoFile("autofile_test")
15 if err != nil {
16         panic(err)
17 }
18
19 // Stream of writes.
20 // During this time, the file may be moved e.g. by logRotate.
21 for i := 0; i < 60; i++ {
22         af.Write([]byte(Fmt("LOOP(%v)", i)))
23         time.Sleep(time.Second)
24 }
25
26 // Close the AutoFile
27 err = af.Close()
28 if err != nil {
29         panic(err)
30 }
31 */
32
33 const autoFileOpenDuration = 1000 * time.Millisecond
34
35 // Automatically closes and re-opens file for writing.
36 // This is useful for using a log file with the logrotate tool.
37 type AutoFile struct {
38         ID     string
39         Path   string
40         ticker *time.Ticker
41         mtx    sync.Mutex
42         file   *os.File
43 }
44
45 func OpenAutoFile(path string) (af *AutoFile, err error) {
46         af = &AutoFile{
47                 ID:     RandStr(12) + ":" + path,
48                 Path:   path,
49                 ticker: time.NewTicker(autoFileOpenDuration),
50         }
51         if err = af.openFile(); err != nil {
52                 return
53         }
54         go af.processTicks()
55         sighupWatchers.addAutoFile(af)
56         return
57 }
58
59 func (af *AutoFile) Close() error {
60         af.ticker.Stop()
61         err := af.closeFile()
62         sighupWatchers.removeAutoFile(af)
63         return err
64 }
65
66 func (af *AutoFile) processTicks() {
67         for {
68                 _, ok := <-af.ticker.C
69                 if !ok {
70                         return // Done.
71                 }
72                 af.closeFile()
73         }
74 }
75
76 func (af *AutoFile) closeFile() (err error) {
77         af.mtx.Lock()
78         defer af.mtx.Unlock()
79
80         file := af.file
81         if file == nil {
82                 return nil
83         }
84         af.file = nil
85         return file.Close()
86 }
87
88 func (af *AutoFile) Write(b []byte) (n int, err error) {
89         af.mtx.Lock()
90         defer af.mtx.Unlock()
91
92         if af.file == nil {
93                 if err = af.openFile(); err != nil {
94                         return
95                 }
96         }
97
98         n, err = af.file.Write(b)
99         return
100 }
101
102 func (af *AutoFile) Sync() error {
103         af.mtx.Lock()
104         defer af.mtx.Unlock()
105
106         if af.file == nil {
107                 if err := af.openFile(); err != nil {
108                         return err
109                 }
110         }
111         return af.file.Sync()
112 }
113
114 func (af *AutoFile) openFile() error {
115         file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
116         if err != nil {
117                 return err
118         }
119         af.file = file
120         return nil
121 }
122
123 func (af *AutoFile) Size() (int64, error) {
124         af.mtx.Lock()
125         defer af.mtx.Unlock()
126
127         if af.file == nil {
128                 err := af.openFile()
129                 if err != nil {
130                         if err == os.ErrNotExist {
131                                 return 0, nil
132                         } else {
133                                 return -1, err
134                         }
135                 }
136         }
137         stat, err := af.file.Stat()
138         if err != nil {
139                 return -1, err
140         }
141         return stat.Size(), nil
142
143 }