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 }