package uuid /**************** * Date: 21/06/15 * Time: 5:48 PM ***************/ import ( "encoding/gob" "log" "os" "time" ) func init() { gob.Register(stateEntity{}) } func SetupFileSystemStateSaver(pConfig StateSaverConfig) { saver := &FileSystemSaver{} saver.saveReport = pConfig.SaveReport saver.saveSchedule = int64(pConfig.SaveSchedule) SetupCustomStateSaver(saver) } // A wrapper for default setup of the FileSystemStateSaver type StateSaverConfig struct { // Print save log SaveReport bool // Save every x nanoseconds SaveSchedule time.Duration } // *********************************************** StateEntity // StateEntity acts as a marshaller struct for the state type stateEntity struct { Past Timestamp Node []byte Sequence uint16 } // This implements the StateSaver interface for UUIDs type FileSystemSaver struct { cache *os.File saveState uint64 saveReport bool saveSchedule int64 } // Saves the current state of the generator // If the scheduled file save is reached then the file is synced func (o *FileSystemSaver) Save(pState *State) { if pState.past >= pState.next { err := o.open() defer o.cache.Close() if err != nil { log.Println("uuid.State.save:", err) return } // do the save o.encode(pState) // a tick is 100 nano seconds pState.next = pState.past + Timestamp(o.saveSchedule / 100) if o.saveReport { log.Printf("UUID STATE: SAVED %d", pState.past) } } } func (o *FileSystemSaver) Init(pState *State) { pState.saver = o err := o.open() defer o.cache.Close() if err != nil { if os.IsNotExist(err) { log.Printf("'%s' created\n", "uuid.SaveState") var err error o.cache, err = os.Create(os.TempDir() + "/state.unique") if err != nil { log.Println("uuid.State.init: SaveState error:", err) goto pastInit } o.encode(pState) } else { log.Println("uuid.State.init: SaveState error:", err) goto pastInit } } err = o.decode(pState) if err != nil { goto pastInit } pState.randomSequence = false pastInit: if timestamp() <= pState.past { pState.sequence++ } pState.next = pState.past } func (o *FileSystemSaver) reset() { o.cache.Seek(0, 0) } func (o *FileSystemSaver) open() error { var err error o.cache, err = os.OpenFile(os.TempDir()+"/state.unique", os.O_RDWR, os.ModeExclusive) return err } // Encodes State generator data into a saved file func (o *FileSystemSaver) encode(pState *State) { // ensure reader state is ready for use o.reset() enc := gob.NewEncoder(o.cache) // Wrap private State data into the StateEntity err := enc.Encode(&stateEntity{pState.past, pState.node, pState.sequence}) if err != nil { log.Panic("UUID.encode error:", err) } } // Decodes StateEntity data into the main State func (o *FileSystemSaver) decode(pState *State) error { o.reset() dec := gob.NewDecoder(o.cache) entity := stateEntity{} err := dec.Decode(&entity) if err != nil { log.Println("uuid.decode error:", err) return err } pState.past = entity.Past pState.node = entity.Node pState.sequence = entity.Sequence return nil }