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  }