github.com/scottcagno/storage@v1.8.0/pkg/lsmt/binary/writer.go (about) 1 package binary 2 3 import ( 4 "io" 5 "os" 6 ) 7 8 // Writer provides a write-only file descriptor 9 type Writer struct { 10 path string // path of the file that is currently open 11 fd *os.File // underlying file to write to 12 doSync bool // should sync on every call (default: true) 13 open bool // is the file open 14 } 15 16 // OpenWriter returns a *writer for the file at the provided path 17 func OpenWriter(path string) (*Writer, error) { 18 // open file at specified path 19 fd, err := os.OpenFile(path, os.O_WRONLY, 0666) 20 if err != nil { 21 return nil, err 22 } 23 // seek to the end of the current file to continue appending data 24 _, err = fd.Seek(0, io.SeekEnd) 25 if err != nil { 26 return nil, err 27 } 28 // return new writer 29 return &Writer{ 30 path: path, 31 fd: fd, 32 doSync: true, 33 open: true, 34 }, nil 35 } 36 37 func OpenWriterWithSync(path string, doSync bool) (*Writer, error) { 38 w, err := OpenWriter(path) 39 if err != nil { 40 return nil, err 41 } 42 w.doSync = doSync 43 return w, nil 44 } 45 46 func (w *Writer) SetSyncOnWrite(ok bool) { 47 w.doSync = ok 48 } 49 50 // WriteIndex writes the provided entry index to disk 51 func (w *Writer) WriteIndex(e *Index) (int64, error) { 52 // call encode entry 53 offset, err := EncodeIndex(w.fd, e) 54 if err != nil { 55 return -1, err 56 } 57 // make sure we call sync!! 58 if w.doSync { 59 err = w.fd.Sync() 60 if err != nil { 61 return -1, err 62 } 63 } 64 return offset, err 65 } 66 67 // WriteEntry writes the provided entry to disk 68 func (w *Writer) WriteEntry(e *Entry) (int64, error) { 69 // call encode entry 70 offset, err := EncodeEntry(w.fd, e) 71 if err != nil { 72 return -1, err 73 } 74 // make sure we call sync!! 75 if w.doSync { 76 err = w.fd.Sync() 77 if err != nil { 78 return -1, err 79 } 80 } 81 return offset, err 82 } 83 84 // Offset returns the *Writer's current file pointer offset 85 func (w *Writer) Offset() (int64, error) { 86 // check to make sure file is not closed 87 if !w.open { 88 return -1, ErrFileClosed 89 } 90 // return current offset using seek 91 return w.fd.Seek(0, io.SeekCurrent) 92 } 93 94 // Offset returns the *ReadWriteSeeker's current file pointer offset 95 func Offset(rw io.ReadWriteSeeker) (int64, error) { 96 // check to make sure file is not closed 97 // return current offset using seek 98 return rw.Seek(0, io.SeekCurrent) 99 } 100 101 // Close syncs and closes the *writer 102 func (w *Writer) Close() error { 103 // ensure file is not closed 104 if !w.open { 105 return ErrFileClosed 106 } 107 // flush any cached or buffered data to the drive 108 err := w.fd.Sync() 109 if err != nil { 110 return err 111 } 112 // close writer 113 err = w.fd.Close() 114 if err != nil { 115 return err 116 } 117 w.open = false 118 w.path = "" 119 return nil 120 } 121 122 // Sync syncs 123 func (w *Writer) Sync() error { 124 // flush buffer to disk 125 err := w.fd.Sync() 126 if err != nil { 127 return err 128 } 129 return nil 130 }