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.

259 lines
6.3 KiB

  1. package embedded_filer
  2. import (
  3. "bufio"
  4. "fmt"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "github.com/chrislusf/weed-fs/go/filer"
  12. "github.com/chrislusf/weed-fs/go/util"
  13. )
  14. var writeLock sync.Mutex //serialize changes to dir.log
  15. type DirectoryEntryInMap struct {
  16. Name string
  17. Parent *DirectoryEntryInMap
  18. SubDirectories map[string]*DirectoryEntryInMap
  19. Id filer.DirectoryId
  20. }
  21. type DirectoryManagerInMap struct {
  22. Root *DirectoryEntryInMap
  23. max filer.DirectoryId
  24. logFile *os.File
  25. isLoading bool
  26. }
  27. func (dm *DirectoryManagerInMap) NewDirectoryEntryInMap(parent *DirectoryEntryInMap, name string) (d *DirectoryEntryInMap, err error) {
  28. writeLock.Lock()
  29. defer writeLock.Unlock()
  30. d = &DirectoryEntryInMap{Name: name, Parent: parent, SubDirectories: make(map[string]*DirectoryEntryInMap)}
  31. var parts []string
  32. for p := d; p != nil && p.Name != ""; p = p.Parent {
  33. parts = append(parts, p.Name)
  34. }
  35. n := len(parts)
  36. if n <= 0 {
  37. return nil, fmt.Errorf("Failed to create folder %s/%s", parent.Name, name)
  38. }
  39. for i := 0; i < n/2; i++ {
  40. parts[i], parts[n-1-i] = parts[n-1-i], parts[i]
  41. }
  42. dm.max++
  43. d.Id = dm.max
  44. dm.log("add", "/"+strings.Join(parts, "/"), strconv.Itoa(int(d.Id)))
  45. return d, nil
  46. }
  47. func (dm *DirectoryManagerInMap) log(words ...string) {
  48. if !dm.isLoading {
  49. dm.logFile.WriteString(strings.Join(words, "\t") + "\n")
  50. }
  51. }
  52. func NewDirectoryManagerInMap(dirLogFile string) (dm *DirectoryManagerInMap, err error) {
  53. dm = &DirectoryManagerInMap{}
  54. //dm.Root do not use NewDirectoryEntryInMap, since dm.max will be changed
  55. dm.Root = &DirectoryEntryInMap{SubDirectories: make(map[string]*DirectoryEntryInMap)}
  56. if dm.logFile, err = os.OpenFile(dirLogFile, os.O_RDWR|os.O_CREATE, 0644); err != nil {
  57. return nil, fmt.Errorf("cannot write directory log file %s.idx: %v", dirLogFile, err)
  58. }
  59. return dm, dm.load()
  60. }
  61. func (dm *DirectoryManagerInMap) processEachLine(line string) error {
  62. if strings.HasPrefix(line, "#") {
  63. return nil
  64. }
  65. if line == "" {
  66. return nil
  67. }
  68. parts := strings.Split(line, "\t")
  69. if len(parts) == 0 {
  70. return nil
  71. }
  72. switch parts[0] {
  73. case "add":
  74. v, pe := strconv.Atoi(parts[2])
  75. if pe != nil {
  76. return pe
  77. }
  78. if e := dm.loadDirectory(parts[1], filer.DirectoryId(v)); e != nil {
  79. return e
  80. }
  81. case "mov":
  82. newName := ""
  83. if len(parts) >= 4 {
  84. newName = parts[3]
  85. }
  86. if e := dm.MoveUnderDirectory(parts[1], parts[2], newName); e != nil {
  87. return e
  88. }
  89. case "del":
  90. if e := dm.DeleteDirectory(parts[1]); e != nil {
  91. return e
  92. }
  93. default:
  94. fmt.Printf("line %s has %s!\n", line, parts[0])
  95. return nil
  96. }
  97. return nil
  98. }
  99. func (dm *DirectoryManagerInMap) load() error {
  100. dm.max = 0
  101. lines := bufio.NewReader(dm.logFile)
  102. dm.isLoading = true
  103. defer func() { dm.isLoading = false }()
  104. for {
  105. line, err := util.Readln(lines)
  106. if err != nil && err != io.EOF {
  107. return err
  108. }
  109. if pe := dm.processEachLine(string(line)); pe != nil {
  110. return pe
  111. }
  112. if err == io.EOF {
  113. return nil
  114. }
  115. }
  116. }
  117. func (dm *DirectoryManagerInMap) findDirectory(dirPath string) (*DirectoryEntryInMap, error) {
  118. if dirPath == "" {
  119. return dm.Root, nil
  120. }
  121. dirPath = filepath.Clean(dirPath)
  122. if dirPath == "/" {
  123. return dm.Root, nil
  124. }
  125. parts := strings.Split(dirPath, "/")
  126. dir := dm.Root
  127. for i := 1; i < len(parts); i++ {
  128. if sub, ok := dir.SubDirectories[parts[i]]; ok {
  129. dir = sub
  130. } else {
  131. return dm.Root, fmt.Errorf("Directory %s Not Found", dirPath)
  132. }
  133. }
  134. return dir, nil
  135. }
  136. func (dm *DirectoryManagerInMap) FindDirectory(dirPath string) (filer.DirectoryId, error) {
  137. d, e := dm.findDirectory(dirPath)
  138. if e == nil {
  139. return d.Id, nil
  140. }
  141. return dm.Root.Id, e
  142. }
  143. func (dm *DirectoryManagerInMap) loadDirectory(dirPath string, dirId filer.DirectoryId) error {
  144. dirPath = filepath.Clean(dirPath)
  145. if dirPath == "/" {
  146. return nil
  147. }
  148. parts := strings.Split(dirPath, "/")
  149. dir := dm.Root
  150. for i := 1; i < len(parts); i++ {
  151. sub, ok := dir.SubDirectories[parts[i]]
  152. if !ok {
  153. if i != len(parts)-1 {
  154. return fmt.Errorf("%s should be created after parent %s", dirPath, parts[i])
  155. }
  156. var err error
  157. sub, err = dm.NewDirectoryEntryInMap(dir, parts[i])
  158. if err != nil {
  159. return err
  160. }
  161. if sub.Id != dirId {
  162. return fmt.Errorf("%s should be have id %v instead of %v", dirPath, sub.Id, dirId)
  163. }
  164. dir.SubDirectories[parts[i]] = sub
  165. }
  166. dir = sub
  167. }
  168. return nil
  169. }
  170. func (dm *DirectoryManagerInMap) makeDirectory(dirPath string) (dir *DirectoryEntryInMap, created bool) {
  171. dirPath = filepath.Clean(dirPath)
  172. if dirPath == "/" {
  173. return dm.Root, false
  174. }
  175. parts := strings.Split(dirPath, "/")
  176. dir = dm.Root
  177. for i := 1; i < len(parts); i++ {
  178. sub, ok := dir.SubDirectories[parts[i]]
  179. if !ok {
  180. var err error
  181. sub, err = dm.NewDirectoryEntryInMap(dir, parts[i])
  182. if err != nil {
  183. return nil, false
  184. }
  185. dir.SubDirectories[parts[i]] = sub
  186. created = true
  187. }
  188. dir = sub
  189. }
  190. return dir, created
  191. }
  192. func (dm *DirectoryManagerInMap) MakeDirectory(dirPath string) (filer.DirectoryId, error) {
  193. dir, _ := dm.makeDirectory(dirPath)
  194. return dir.Id, nil
  195. }
  196. func (dm *DirectoryManagerInMap) MoveUnderDirectory(oldDirPath string, newParentDirPath string, newName string) error {
  197. writeLock.Lock()
  198. defer writeLock.Unlock()
  199. oldDir, oe := dm.findDirectory(oldDirPath)
  200. if oe != nil {
  201. return oe
  202. }
  203. parentDir, pe := dm.findDirectory(newParentDirPath)
  204. if pe != nil {
  205. return pe
  206. }
  207. dm.log("mov", oldDirPath, newParentDirPath, newName)
  208. delete(oldDir.Parent.SubDirectories, oldDir.Name)
  209. if newName == "" {
  210. newName = oldDir.Name
  211. }
  212. parentDir.SubDirectories[newName] = oldDir
  213. oldDir.Name = newName
  214. oldDir.Parent = parentDir
  215. return nil
  216. }
  217. func (dm *DirectoryManagerInMap) ListDirectories(dirPath string) (dirNames []filer.DirectoryEntry, err error) {
  218. d, e := dm.findDirectory(dirPath)
  219. if e != nil {
  220. return dirNames, e
  221. }
  222. for k, v := range d.SubDirectories {
  223. dirNames = append(dirNames, filer.DirectoryEntry{Name: k, Id: v.Id})
  224. }
  225. return dirNames, nil
  226. }
  227. func (dm *DirectoryManagerInMap) DeleteDirectory(dirPath string) error {
  228. writeLock.Lock()
  229. defer writeLock.Unlock()
  230. if dirPath == "/" {
  231. return fmt.Errorf("Can not delete %s", dirPath)
  232. }
  233. d, e := dm.findDirectory(dirPath)
  234. if e != nil {
  235. return e
  236. }
  237. if len(d.SubDirectories) != 0 {
  238. return fmt.Errorf("dir %s still has sub directories", dirPath)
  239. }
  240. delete(d.Parent.SubDirectories, d.Name)
  241. d.Parent = nil
  242. dm.log("del", dirPath)
  243. return nil
  244. }