Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.0 KiB
140 lines
3.0 KiB
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 |
|
}
|
|
|