github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/twinj/uuid/saver.go (about)

     1  package uuid
     2  
     3  /****************
     4   * Date: 21/06/15
     5   * Time: 5:48 PM
     6   ***************/
     7  
     8  import (
     9  	"encoding/gob"
    10  	"log"
    11  	"os"
    12  	"time"
    13  )
    14  
    15  func init() {
    16  	gob.Register(stateEntity{})
    17  }
    18  
    19  func SetupFileSystemStateSaver(pConfig StateSaverConfig) {
    20  	saver := &FileSystemSaver{}
    21  	saver.saveReport = pConfig.SaveReport
    22  	saver.saveSchedule = int64(pConfig.SaveSchedule)
    23  	SetupCustomStateSaver(saver)
    24  }
    25  
    26  // A wrapper for default setup of the FileSystemStateSaver
    27  type StateSaverConfig struct {
    28  
    29  	// Print save log
    30  	SaveReport bool
    31  
    32  	// Save every x nanoseconds
    33  	SaveSchedule time.Duration
    34  }
    35  
    36  // ***********************************************  StateEntity
    37  
    38  // StateEntity acts as a marshaller struct for the state
    39  type stateEntity struct {
    40  	Past     Timestamp
    41  	Node     []byte
    42  	Sequence uint16
    43  }
    44  
    45  // This implements the StateSaver interface for UUIDs
    46  type FileSystemSaver struct {
    47  	cache        *os.File
    48  	saveState    uint64
    49  	saveReport   bool
    50  	saveSchedule int64
    51  }
    52  
    53  // Saves the current state of the generator
    54  // If the scheduled file save is reached then the file is synced
    55  func (o *FileSystemSaver) Save(pState *State) {
    56  	if pState.past >= pState.next {
    57  		err := o.open()
    58  		defer o.cache.Close()
    59  		if err != nil {
    60  			log.Println("uuid.State.save:", err)
    61  			return
    62  		}
    63  		// do the save
    64  		o.encode(pState)
    65  		// a tick is 100 nano seconds
    66  		pState.next = pState.past + Timestamp(o.saveSchedule / 100)
    67  		if o.saveReport {
    68  			log.Printf("UUID STATE: SAVED %d", pState.past)
    69  		}
    70  	}
    71  }
    72  
    73  func (o *FileSystemSaver) Init(pState *State) {
    74  	pState.saver = o
    75  	err := o.open()
    76  	defer o.cache.Close()
    77  	if err != nil {
    78  		if os.IsNotExist(err) {
    79  			log.Printf("'%s' created\n", "uuid.SaveState")
    80  			var err error
    81  			o.cache, err = os.Create(os.TempDir() + "/state.unique")
    82  			if err != nil {
    83  				log.Println("uuid.State.init: SaveState error:", err)
    84  				goto pastInit
    85  			}
    86  			o.encode(pState)
    87  		} else {
    88  			log.Println("uuid.State.init: SaveState error:", err)
    89  			goto pastInit
    90  		}
    91  	}
    92  	err = o.decode(pState)
    93  	if err != nil {
    94  		goto pastInit
    95  	}
    96  	pState.randomSequence = false
    97  pastInit:
    98  	if timestamp() <= pState.past {
    99  		pState.sequence++
   100  	}
   101  	pState.next = pState.past
   102  }
   103  
   104  func (o *FileSystemSaver) reset() {
   105  	o.cache.Seek(0, 0)
   106  }
   107  
   108  func (o *FileSystemSaver) open() error {
   109  	var err error
   110  	o.cache, err = os.OpenFile(os.TempDir()+"/state.unique", os.O_RDWR, os.ModeExclusive)
   111  	return err
   112  }
   113  
   114  // Encodes State generator data into a saved file
   115  func (o *FileSystemSaver) encode(pState *State) {
   116  	// ensure reader state is ready for use
   117  	o.reset()
   118  	enc := gob.NewEncoder(o.cache)
   119  	// Wrap private State data into the StateEntity
   120  	err := enc.Encode(&stateEntity{pState.past, pState.node, pState.sequence})
   121  	if err != nil {
   122  		log.Panic("UUID.encode error:", err)
   123  	}
   124  }
   125  
   126  // Decodes StateEntity data into the main State
   127  func (o *FileSystemSaver) decode(pState *State) error {
   128  	o.reset()
   129  	dec := gob.NewDecoder(o.cache)
   130  	entity := stateEntity{}
   131  	err := dec.Decode(&entity)
   132  	if err != nil {
   133  		log.Println("uuid.decode error:", err)
   134  		return err
   135  	}
   136  	pState.past = entity.Past
   137  	pState.node = entity.Node
   138  	pState.sequence = entity.Sequence
   139  	return nil
   140  }