github.com/scottcagno/storage@v1.8.0/pkg/_junk/_binary/writer.go (about)

     1  package binary
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  	"os"
     7  )
     8  
     9  // Writer provides a write-only file descriptor
    10  type Writer struct {
    11  	path string   // path of the file that is currently open
    12  	fd   *os.File // underlying file to write to
    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  		open: true,
    33  	}, nil
    34  }
    35  
    36  // EncodeEntry writes the provided entry to disk
    37  func EncodeEntry(w io.WriteSeeker, e *Entry) (int64, error) {
    38  	// error check
    39  	if e == nil {
    40  		return -1, ErrBadEntry
    41  	}
    42  	// get the file pointer offset for the entry
    43  	offset, err := w.Seek(0, io.SeekCurrent)
    44  	if err != nil {
    45  		return -1, err
    46  	}
    47  	// make buffer
    48  	buf := make([]byte, 26)
    49  	// encode and write entry id
    50  	binary.PutVarint(buf[0:10], e.Id)
    51  	_, err = w.Write(buf[0:10])
    52  	if err != nil {
    53  		return -1, err
    54  	}
    55  	// encode and write entry key length
    56  	binary.LittleEndian.PutUint64(buf[10:18], uint64(len(e.Key)))
    57  	_, err = w.Write(buf[10:18])
    58  	if err != nil {
    59  		return -1, err
    60  	}
    61  	// encode and write entry value length
    62  	binary.LittleEndian.PutUint64(buf[18:26], uint64(len(e.Value)))
    63  	_, err = w.Write(buf[18:26])
    64  	if err != nil {
    65  		return -1, err
    66  	}
    67  	// write entry key
    68  	_, err = w.Write(e.Key)
    69  	if err != nil {
    70  		return -1, err
    71  	}
    72  	// write entry value
    73  	_, err = w.Write(e.Value)
    74  	if err != nil {
    75  		return -1, err
    76  	}
    77  	return offset, nil
    78  }
    79  
    80  // WriteEntryIndex writes the provided entry index to disk
    81  func (w *Writer) WriteEntryIndex(e *EntryIndex) (int64, error) {
    82  	// call encode entry
    83  	offset, err := EncodeEntryIndex(w.fd, e)
    84  	if err != nil {
    85  		return -1, err
    86  	}
    87  	// make sure we call sync!!
    88  	err = w.fd.Sync()
    89  	if err != nil {
    90  		return -1, err
    91  	}
    92  	return offset, err
    93  }
    94  
    95  // WriteEntry writes the provided entry to disk
    96  func (w *Writer) WriteEntry(e *Entry) (int64, error) {
    97  	// call encode entry
    98  	offset, err := EncodeEntry(w.fd, e)
    99  	if err != nil {
   100  		return -1, err
   101  	}
   102  	// make sure we call sync!!
   103  	err = w.fd.Sync()
   104  	if err != nil {
   105  		return -1, err
   106  	}
   107  	return offset, err
   108  }
   109  
   110  // Offset returns the *Writer's current file pointer offset
   111  func (w *Writer) Offset() (int64, error) {
   112  	// check to make sure file is not closed
   113  	if !w.open {
   114  		return -1, ErrFileClosed
   115  	}
   116  	// return current offset using seek
   117  	return w.fd.Seek(0, io.SeekCurrent)
   118  }
   119  
   120  // Close syncs and closes the *writer
   121  func (w *Writer) Close() error {
   122  	// ensure file is not closed
   123  	if !w.open {
   124  		return ErrFileClosed
   125  	}
   126  	// flush any cached or buffered data to the drive
   127  	err := w.fd.Sync()
   128  	if err != nil {
   129  		return err
   130  	}
   131  	// close writer
   132  	err = w.fd.Close()
   133  	if err != nil {
   134  		return err
   135  	}
   136  	w.open = false
   137  	w.path = ""
   138  	return nil
   139  }