@@ -13,6 +13,8 @@ import (
1313 "strconv"
1414 "sync"
1515 "sync/atomic"
16+
17+ "github.com/golang/snappy"
1618)
1719
1820// diskWAL contains multiple segment files. One segment is responsible for one partition.
@@ -28,6 +30,8 @@ type diskWAL struct {
2830 bufferedSize int
2931 // Buffered-writer to the active segment
3032 w * bufio.Writer
33+ // Snappy streaming writer
34+ sw * snappy.Writer
3135 // File descriptor to the active segment
3236 fd * os.File
3337 index uint32
@@ -46,12 +50,29 @@ func newDiskWAL(dir string, bufferedSize int) (wal, error) {
4650 if err != nil {
4751 return nil , err
4852 }
49- w .fd = f
50- w .w = bufio .NewWriterSize (f , bufferedSize )
53+ w .initWriter (f )
5154
5255 return w , nil
5356}
5457
58+ // initWriter sets up the writer chain: bufio.Writer → snappy.Writer → os.File.
59+ func (w * diskWAL ) initWriter (f * os.File ) {
60+ w .fd = f
61+ w .sw = snappy .NewBufferedWriter (f )
62+ w .w = bufio .NewWriterSize (w .sw , w .bufferedSize )
63+ }
64+
65+ // closeWriter flushes and closes the entire writer chain.
66+ func (w * diskWAL ) closeWriter () error {
67+ if err := w .w .Flush (); err != nil {
68+ return fmt .Errorf ("failed to flush buffered-data into the underlying WAL file: %w" , err )
69+ }
70+ if err := w .sw .Close (); err != nil {
71+ return fmt .Errorf ("failed to close snappy writer: %w" , err )
72+ }
73+ return w .fd .Close ()
74+ }
75+
5576// append appends the given entry to the end of a file via the file descriptor it has.
5677func (w * diskWAL ) append (op walOperation , rows []Row ) error {
5778 w .mu .Lock ()
@@ -103,25 +124,24 @@ func (w *diskWAL) flush() error {
103124 if err := w .w .Flush (); err != nil {
104125 return fmt .Errorf ("failed to flush buffered-data into the underlying WAL file: %w" , err )
105126 }
127+ if err := w .sw .Flush (); err != nil {
128+ return fmt .Errorf ("failed to flush snappy writer: %w" , err )
129+ }
106130 return nil
107131}
108132
109133// punctuate set boundary and creates a new segment.
110134func (w * diskWAL ) punctuate () error {
111135 w .mu .Lock ()
112136 defer w .mu .Unlock ()
113- if err := w .flush (); err != nil {
114- return err
115- }
116- if err := w .fd .Close (); err != nil {
137+ if err := w .closeWriter (); err != nil {
117138 return err
118139 }
119140 f , err := w .createSegmentFile (w .dir )
120141 if err != nil {
121142 return err
122143 }
123- w .fd = f
124- w .w = bufio .NewWriterSize (f , w .bufferedSize )
144+ w .initWriter (f )
125145 return nil
126146}
127147
@@ -143,6 +163,9 @@ func (w *diskWAL) removeOldest() error {
143163func (w * diskWAL ) removeAll () error {
144164 w .mu .Lock ()
145165 defer w .mu .Unlock ()
166+ // Best-effort flush/close of the writer chain before removing files.
167+ _ = w .w .Flush ()
168+ _ = w .sw .Close ()
146169 if err := w .fd .Close (); err != nil {
147170 return err
148171 }
@@ -164,8 +187,7 @@ func (w *diskWAL) refresh() error {
164187 if err != nil {
165188 return err
166189 }
167- w .fd = f
168- w .w = bufio .NewWriterSize (f , w .bufferedSize )
190+ w .initWriter (f )
169191 return nil
170192}
171193
@@ -216,7 +238,7 @@ func (f *diskWALReader) readAll() error {
216238 }
217239 segment := & segment {
218240 file : fd ,
219- r : bufio .NewReader (fd ),
241+ r : bufio .NewReader (snappy . NewReader ( fd ) ),
220242 }
221243 for segment .next () {
222244 rec := segment .record ()
@@ -230,7 +252,7 @@ func (f *diskWALReader) readAll() error {
230252 }
231253
232254 err = segment .error ()
233- if errors .Is (err , io .ErrUnexpectedEOF ) || errors .Is (err , io .EOF ) {
255+ if errors .Is (err , io .ErrUnexpectedEOF ) || errors .Is (err , io .EOF ) || errors . Is ( err , snappy . ErrCorrupt ) {
234256 // It is not unusual for a line to be invalid, as it may well terminate in the middle of writing to the WAL.
235257 return nil
236258 }
0 commit comments