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.

96 lines
2.4 KiB

  1. package sequence
  2. import (
  3. "bytes"
  4. "code.google.com/p/weed-fs/go/glog"
  5. "code.google.com/p/weed-fs/go/metastore"
  6. "encoding/gob"
  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. fileFullPath string
  17. volumeLock sync.Mutex
  18. sequenceLock sync.Mutex
  19. FileIdSequence uint64
  20. fileIdCounter uint64
  21. metaStore *metastore.MetaStore
  22. }
  23. func NewFileSequencer(filepath string) (m *SequencerImpl) {
  24. m = &SequencerImpl{fileFullPath: filepath}
  25. m.metaStore = &metastore.MetaStore{metastore.NewMetaStoreFileBacking()}
  26. m.initilize()
  27. return
  28. }
  29. func NewEtcdSequencer(etcdCluster string) (m *SequencerImpl) {
  30. m = &SequencerImpl{fileFullPath: "/weedfs/default/sequence"}
  31. m.metaStore = &metastore.MetaStore{metastore.NewMetaStoreEtcdBacking(etcdCluster)}
  32. m.initilize()
  33. return
  34. }
  35. func (m *SequencerImpl) initilize() {
  36. if !m.metaStore.Has(m.fileFullPath) {
  37. m.FileIdSequence = FileIdSaveInterval
  38. glog.V(0).Infoln("Setting file id sequence", m.FileIdSequence)
  39. } else {
  40. var err error
  41. if m.FileIdSequence, err = m.metaStore.GetUint64(m.fileFullPath); err != nil {
  42. if data, err := m.metaStore.Get(m.fileFullPath); err == nil {
  43. m.FileIdSequence = decode(data)
  44. glog.V(0).Infoln("Decoding old version of FileIdSequence", m.FileIdSequence)
  45. } else {
  46. glog.V(0).Infof("No existing FileIdSequence: %s", err)
  47. }
  48. } else {
  49. glog.V(0).Infoln("Loading file id sequence", m.FileIdSequence)
  50. }
  51. //in case the server stops between intervals
  52. }
  53. return
  54. }
  55. //count should be 1 or more
  56. func (m *SequencerImpl) NextFileId(count int) (uint64, int) {
  57. if count <= 0 {
  58. return 0, 0
  59. }
  60. m.sequenceLock.Lock()
  61. defer m.sequenceLock.Unlock()
  62. if m.fileIdCounter < uint64(count) {
  63. m.fileIdCounter = FileIdSaveInterval
  64. m.FileIdSequence += FileIdSaveInterval
  65. m.saveSequence()
  66. }
  67. m.fileIdCounter = m.fileIdCounter - uint64(count)
  68. return m.FileIdSequence - m.fileIdCounter - uint64(count), count
  69. }
  70. func (m *SequencerImpl) saveSequence() {
  71. glog.V(0).Infoln("Saving file id sequence", m.FileIdSequence, "to", m.fileFullPath)
  72. if e := m.metaStore.SetUint64(m.fileFullPath, m.FileIdSequence); e != nil {
  73. glog.Fatalf("Sequence id Save [ERROR] %s", e)
  74. }
  75. }
  76. //decode are for backward compatible purpose
  77. func decode(input string) uint64 {
  78. var x uint64
  79. b := bytes.NewReader([]byte(input))
  80. decoder := gob.NewDecoder(b)
  81. if e := decoder.Decode(&x); e == nil {
  82. return x
  83. }
  84. return 0
  85. }