mirror of
1
Fork 0
forgejo/vendor/github.com/twinj/uuid/saver.go

141 lines
3.0 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
}