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.

107 lines
2.7 KiB

  1. package command
  2. import (
  3. "github.com/chrislusf/seaweedfs/weed/server"
  4. "github.com/spf13/viper"
  5. "github.com/chrislusf/seaweedfs/weed/filer2"
  6. "github.com/chrislusf/seaweedfs/weed/glog"
  7. )
  8. func init() {
  9. cmdFilerExport.Run = runFilerExport // break init cycle
  10. }
  11. var cmdFilerExport = &Command{
  12. UsageLine: "filer.export -sourceStore=mysql -targetStroe=cassandra",
  13. Short: "export meta data in filer store",
  14. Long: `Iterate the file tree and export all metadata out
  15. Both source and target store:
  16. * should be a store name already specified in filer.toml
  17. * do not need to be enabled state
  18. If target store is empty, only the directory tree will be listed.
  19. `,
  20. }
  21. var (
  22. // filerExportOutputFile = cmdFilerExport.Flag.String("output", "", "the output file. If empty, only list out the directory tree")
  23. filerExportSourceStore = cmdFilerExport.Flag.String("sourceStore", "", "the source store name in filer.toml")
  24. )
  25. type statistics struct {
  26. directoryCount int
  27. fileCount int
  28. }
  29. func runFilerExport(cmd *Command, args []string) bool {
  30. weed_server.LoadConfiguration("filer", true)
  31. config := viper.GetViper()
  32. var sourceStore filer2.FilerStore
  33. for _, store := range filer2.Stores {
  34. if store.GetName() == *filerExportSourceStore {
  35. viperSub := config.Sub(store.GetName())
  36. if err := store.Initialize(viperSub); err != nil {
  37. glog.Fatalf("Failed to initialize store for %s: %+v",
  38. store.GetName(), err)
  39. } else {
  40. sourceStore = store
  41. }
  42. break
  43. }
  44. }
  45. if sourceStore == nil {
  46. glog.Errorf("Failed to find source store %s", *filerExportSourceStore)
  47. println("existing data sources are:")
  48. for _, store := range filer2.Stores {
  49. println(" " + store.GetName())
  50. }
  51. return false
  52. }
  53. stat := statistics{}
  54. doTraverse(&stat, sourceStore, filer2.FullPath("/"), 0, printout)
  55. glog.Infof("processed %d directories, %d files", stat.directoryCount, stat.fileCount)
  56. return true
  57. }
  58. func doTraverse(stat *statistics, filerStore filer2.FilerStore, parentPath filer2.FullPath, level int, fn func(level int, entry *filer2.Entry) error) {
  59. limit := 1000
  60. lastEntryName := ""
  61. for {
  62. entries, err := filerStore.ListDirectoryEntries(parentPath, lastEntryName, false, limit)
  63. if err != nil {
  64. break
  65. }
  66. for _, entry := range entries {
  67. if fnErr := fn(level, entry); fnErr != nil {
  68. glog.Errorf("failed to process entry: %s", entry.FullPath)
  69. }
  70. if entry.IsDirectory() {
  71. stat.directoryCount++
  72. doTraverse(stat, filerStore, entry.FullPath, level+1, fn)
  73. } else {
  74. stat.fileCount++
  75. }
  76. }
  77. if len(entries) < limit {
  78. break
  79. }
  80. }
  81. }
  82. func printout(level int, entry *filer2.Entry) error {
  83. for i := 0; i < level; i++ {
  84. print(" ")
  85. }
  86. println(entry.FullPath.Name())
  87. return nil
  88. }