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.

122 lines
3.7 KiB

6 years ago
6 years ago
6 years ago
6 years ago
  1. package command
  2. import (
  3. "fmt"
  4. "github.com/chrislusf/seaweedfs/weed/security"
  5. "github.com/chrislusf/seaweedfs/weed/server"
  6. "github.com/spf13/viper"
  7. "github.com/chrislusf/seaweedfs/weed/operation"
  8. "github.com/chrislusf/seaweedfs/weed/storage"
  9. )
  10. var (
  11. s BackupOptions
  12. )
  13. type BackupOptions struct {
  14. master *string
  15. collection *string
  16. dir *string
  17. volumeId *int
  18. }
  19. func init() {
  20. cmdBackup.Run = runBackup // break init cycle
  21. s.master = cmdBackup.Flag.String("server", "localhost:9333", "SeaweedFS master location")
  22. s.collection = cmdBackup.Flag.String("collection", "", "collection name")
  23. s.dir = cmdBackup.Flag.String("dir", ".", "directory to store volume data files")
  24. s.volumeId = cmdBackup.Flag.Int("volumeId", -1, "a volume id. The volume .dat and .idx files should already exist in the dir.")
  25. }
  26. var cmdBackup = &Command{
  27. UsageLine: "backup -dir=. -volumeId=234 -server=localhost:9333",
  28. Short: "incrementally backup a volume to local folder",
  29. Long: `Incrementally backup volume data.
  30. It is expected that you use this inside a script, to loop through
  31. all possible volume ids that needs to be backup to local folder.
  32. The volume id does not need to exist locally or even remotely.
  33. This will help to backup future new volumes.
  34. Usually backing up is just copying the .dat (and .idx) files.
  35. But it's tricky to incrementally copy the differences.
  36. The complexity comes when there are multiple addition, deletion and compaction.
  37. This tool will handle them correctly and efficiently, avoiding unnecessary data transportation.
  38. `,
  39. }
  40. func runBackup(cmd *Command, args []string) bool {
  41. weed_server.LoadConfiguration("security", false)
  42. grpcDialOption := security.LoadClientTLS(viper.Sub("grpc"), "client")
  43. if *s.volumeId == -1 {
  44. return false
  45. }
  46. vid := storage.VolumeId(*s.volumeId)
  47. // find volume location, replication, ttl info
  48. lookup, err := operation.Lookup(*s.master, vid.String())
  49. if err != nil {
  50. fmt.Printf("Error looking up volume %d: %v\n", vid, err)
  51. return true
  52. }
  53. volumeServer := lookup.Locations[0].Url
  54. stats, err := operation.GetVolumeSyncStatus(volumeServer, grpcDialOption, uint32(vid))
  55. if err != nil {
  56. fmt.Printf("Error get volume %d status: %v\n", vid, err)
  57. return true
  58. }
  59. ttl, err := storage.ReadTTL(stats.Ttl)
  60. if err != nil {
  61. fmt.Printf("Error get volume %d ttl %s: %v\n", vid, stats.Ttl, err)
  62. return true
  63. }
  64. replication, err := storage.NewReplicaPlacementFromString(stats.Replication)
  65. if err != nil {
  66. fmt.Printf("Error get volume %d replication %s : %v\n", vid, stats.Replication, err)
  67. return true
  68. }
  69. v, err := storage.NewVolume(*s.dir, *s.collection, vid, storage.NeedleMapInMemory, replication, ttl, 0)
  70. if err != nil {
  71. fmt.Printf("Error creating or reading from volume %d: %v\n", vid, err)
  72. return true
  73. }
  74. if v.SuperBlock.CompactRevision < uint16(stats.CompactRevision) {
  75. if err = v.Compact(0); err != nil {
  76. fmt.Printf("Compact Volume before synchronizing %v\n", err)
  77. return true
  78. }
  79. if err = v.CommitCompact(); err != nil {
  80. fmt.Printf("Commit Compact before synchronizing %v\n", err)
  81. return true
  82. }
  83. v.SuperBlock.CompactRevision = uint16(stats.CompactRevision)
  84. v.DataFile().WriteAt(v.SuperBlock.Bytes(), 0)
  85. }
  86. if uint64(v.Size()) > stats.TailOffset {
  87. // remove the old data
  88. v.Destroy()
  89. // recreate an empty volume
  90. v, err = storage.NewVolume(*s.dir, *s.collection, vid, storage.NeedleMapInMemory, replication, ttl, 0)
  91. if err != nil {
  92. fmt.Printf("Error creating or reading from volume %d: %v\n", vid, err)
  93. return true
  94. }
  95. }
  96. defer v.Close()
  97. if err := v.IncrementalBackup(volumeServer, grpcDialOption); err != nil {
  98. fmt.Printf("Error synchronizing volume %d: %v\n", vid, err)
  99. return true
  100. }
  101. return true
  102. }