b6a95a8cb3
* Dropped unused codekit config * Integrated dynamic and static bindata for public * Ignore public bindata * Add a general generate make task * Integrated flexible public assets into web command * Updated vendoring, added all missiong govendor deps * Made the linter happy with the bindata and dynamic code * Moved public bindata definition to modules directory * Ignoring the new bindata path now * Updated to the new public modules import path * Updated public bindata command and drop the new prefix
140 lines
3 KiB
Go
140 lines
3 KiB
Go
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
|
|
}
|