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.

78 lines
2.0 KiB

  1. package sequence
  2. import (
  3. "encoding/gob"
  4. "log"
  5. "os"
  6. "path"
  7. "sync"
  8. )
  9. const (
  10. FileIdSaveInterval = 10000
  11. )
  12. type Sequencer interface {
  13. NextFileId(count int) (uint64, int)
  14. }
  15. type SequencerImpl struct {
  16. dir string
  17. fileName string
  18. volumeLock sync.Mutex
  19. sequenceLock sync.Mutex
  20. FileIdSequence uint64
  21. fileIdCounter uint64
  22. }
  23. func NewSequencer(dirname string, filename string) (m *SequencerImpl) {
  24. m = &SequencerImpl{dir: dirname, fileName: filename}
  25. seqFile, se := os.OpenFile(path.Join(m.dir, m.fileName+".seq"), os.O_RDONLY, 0644)
  26. if se != nil {
  27. m.FileIdSequence = FileIdSaveInterval
  28. log.Println("Setting file id sequence", m.FileIdSequence)
  29. } else {
  30. decoder := gob.NewDecoder(seqFile)
  31. defer seqFile.Close()
  32. if se = decoder.Decode(&m.FileIdSequence); se != nil {
  33. log.Printf("error decoding FileIdSequence: %s", se)
  34. m.FileIdSequence = FileIdSaveInterval
  35. log.Println("Setting file id sequence", m.FileIdSequence)
  36. } else {
  37. log.Println("Loading file id sequence", m.FileIdSequence, "=>", m.FileIdSequence+FileIdSaveInterval)
  38. m.FileIdSequence += FileIdSaveInterval
  39. }
  40. //in case the server stops between intervals
  41. }
  42. return
  43. }
  44. //count should be 1 or more
  45. func (m *SequencerImpl) NextFileId(count int) (uint64, int) {
  46. if count <= 0 {
  47. return 0, 0
  48. }
  49. m.sequenceLock.Lock()
  50. defer m.sequenceLock.Unlock()
  51. if m.fileIdCounter < uint64(count) {
  52. m.fileIdCounter = FileIdSaveInterval
  53. m.FileIdSequence += FileIdSaveInterval
  54. m.saveSequence()
  55. }
  56. m.fileIdCounter = m.fileIdCounter - uint64(count)
  57. return m.FileIdSequence - m.fileIdCounter - uint64(count), count
  58. }
  59. func (m *SequencerImpl) saveSequence() {
  60. log.Println("Saving file id sequence", m.FileIdSequence, "to", path.Join(m.dir, m.fileName+".seq"))
  61. seqFile, e := os.OpenFile(path.Join(m.dir, m.fileName+".seq"), os.O_CREATE|os.O_WRONLY, 0644)
  62. if e != nil {
  63. log.Fatalf("Sequence File Save [ERROR] %s\n", e)
  64. }
  65. defer seqFile.Close()
  66. encoder := gob.NewEncoder(seqFile)
  67. if e = encoder.Encode(m.FileIdSequence); e != nil {
  68. log.Fatalf("Sequence File Save [ERROR] %s\n", e)
  69. }
  70. }