github.com/scottcagno/storage@v1.8.0/pkg/lsmtree/commitlog.go (about)

     1  package lsmtree
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path/filepath"
     7  )
     8  
     9  const defaultCommitLogFileName = "wal-backup.log"
    10  
    11  type commitLog struct {
    12  	baseDir     string
    13  	syncOnWrite bool
    14  	fd          *os.File
    15  	offsets     []int64
    16  }
    17  
    18  func openCommitLog(base string, syncOnWrite bool) (*commitLog, error) {
    19  	// initialize base path
    20  	base, err := initBasePath(base)
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  	// full file path
    25  	file := filepath.Join(base, defaultCommitLogFileName)
    26  	// open file
    27  	fd, err := os.OpenFile(file, os.O_CREATE, 0666)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	// create commit log instance
    32  	c := &commitLog{
    33  		baseDir:     base,
    34  		syncOnWrite: syncOnWrite,
    35  		fd:          fd,
    36  	}
    37  	// load entry index
    38  	err = c.loadIndex()
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	return c, nil
    43  }
    44  
    45  func (c *commitLog) loadIndex() error {
    46  	for {
    47  		// get offset of entry
    48  		offset, err := c.fd.Seek(0, io.SeekCurrent)
    49  		if err != nil {
    50  			return err
    51  		}
    52  		// read entry
    53  		_, err = readEntry(c.fd)
    54  		if err != nil {
    55  			if err == io.EOF || err == io.ErrUnexpectedEOF {
    56  				break
    57  			}
    58  			return err
    59  		}
    60  		// read entry successful, add to index
    61  		c.offsets = append(c.offsets, offset)
    62  	}
    63  	return nil
    64  }
    65  
    66  func (c *commitLog) get(offset int64) (*Entry, error) {
    67  	// read entry at provided offset
    68  	e, err := readEntryAt(c.fd, offset)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	// found it
    73  	return e, nil
    74  }
    75  
    76  func (c *commitLog) put(e *Entry) (int64, error) {
    77  	// write provided entry
    78  	offset, err := writeEntry(c.fd, e)
    79  	if err != nil {
    80  		return -1, err
    81  	}
    82  	// return offset
    83  	return offset, nil
    84  }
    85  
    86  func (c *commitLog) scan(iter func(e *Entry) bool) error {
    87  	for i := range c.offsets {
    88  		// read entry
    89  		e, err := readEntryAt(c.fd, c.offsets[i])
    90  		if err != nil {
    91  			if err == io.EOF || err == io.ErrUnexpectedEOF {
    92  				break
    93  			}
    94  			return err
    95  		}
    96  		// check entry against iterator boolean function
    97  		if !iter(e) {
    98  			// if it returns false, then process next segEntry
    99  			continue
   100  		}
   101  	}
   102  	return nil
   103  }
   104  
   105  func (c *commitLog) cycle() error {
   106  	// seek to start
   107  	_, err := c.fd.Seek(0, io.SeekStart)
   108  	if err != nil {
   109  		return err
   110  	}
   111  	// truncate file
   112  	err = c.fd.Truncate(0)
   113  	if err != nil {
   114  		return err
   115  	}
   116  	return nil
   117  }
   118  
   119  func (c *commitLog) sync() error {
   120  	// flush data
   121  	err := c.fd.Sync()
   122  	if err != nil {
   123  		return err
   124  	}
   125  	return nil
   126  }
   127  
   128  func (c *commitLog) size() int64 {
   129  	fi, err := c.fd.Stat()
   130  	if err != nil {
   131  		return -1
   132  	}
   133  	return fi.Size()
   134  }
   135  
   136  func (c *commitLog) close() error {
   137  	// flush data
   138  	err := c.fd.Sync()
   139  	if err != nil {
   140  		return err
   141  	}
   142  	// close that thing
   143  	err = c.fd.Close()
   144  	if err != nil {
   145  		return err
   146  	}
   147  	return nil
   148  }