github.com/jeffjen/go-libkv@v0.0.0-20151212051932-5df59a45a168/libkv/persist.go (about)

     1  // Package libkv provides key value storage for embedded go application.
     2  package libkv
     3  
     4  import (
     5  	"encoding/gob"
     6  	"io"
     7  	"os"
     8  	p "path"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  const (
    14  	KV_FILE     = "kv.db"
    15  	KV_IDX_FILE = "kv.idx"
    16  )
    17  
    18  var (
    19  	g sync.Mutex
    20  )
    21  
    22  func init() {
    23  	gob.Register([]thing{})
    24  	gob.Register(thing{})
    25  }
    26  
    27  // Load restores kv object from file.
    28  // Method is protected by mutex to prevent multiple Load job.
    29  // NOTE: this is an experimental feature
    30  func Load(path string) (*Store, error) {
    31  	g.Lock()
    32  	defer g.Unlock()
    33  
    34  	var (
    35  		s = NewStore() // initiate kv store object
    36  
    37  		store map[string]thing
    38  	)
    39  
    40  	if fp, err := os.Open(p.Join(path, KV_FILE)); err != nil {
    41  		return s, err
    42  	} else {
    43  		defer fp.Close()
    44  		dec := gob.NewDecoder(fp)
    45  		if drr := dec.Decode(&store); drr != nil && drr != io.EOF {
    46  			return s, err
    47  		}
    48  	}
    49  
    50  	// loaded kv object file
    51  	s.m.store = store
    52  
    53  	// proceed to restore state
    54  	now := time.Now()
    55  	for k, v := range s.m.store {
    56  		if v.T != nil && now.After(*v.T) {
    57  			delete(store, k)
    58  		} else if v.T != nil {
    59  			s.expire(k, *v.T)
    60  		}
    61  	}
    62  
    63  	return s, nil
    64  }
    65  
    66  // Save stores the kv object and kv index object to designated path
    67  // kv object is put under read lock to prevent changes
    68  // Method is protected by mutex to prevent multiple Save job.
    69  // NOTE: this is an experimental feature.  Method best invoked in goroutine
    70  func (s *Store) Save(path string) error {
    71  	s.RLock()
    72  	defer s.RUnlock()
    73  
    74  	g.Lock()
    75  	defer g.Unlock()
    76  
    77  	if fp, err := os.Create(p.Join(path, KV_FILE)); err != nil {
    78  		return err
    79  	} else {
    80  		defer fp.Close()
    81  		enc := gob.NewEncoder(fp)
    82  		if err = enc.Encode(s.m.store); err != nil {
    83  			return err
    84  		}
    85  	}
    86  
    87  	return nil
    88  }