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.

240 lines
5.8 KiB

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