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.

232 lines
5.7 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. if e := dm.MoveUnderDirectory(parts[1], parts[2]); e != nil {
  78. return e
  79. }
  80. case "del":
  81. if e := dm.DeleteDirectory(parts[1]); e != nil {
  82. return e
  83. }
  84. default:
  85. fmt.Printf("line %s has %s!\n", line, parts[0])
  86. return nil
  87. }
  88. return nil
  89. }
  90. func (dm *DirectoryManagerInMap) load() error {
  91. dm.max = 0
  92. lines := bufio.NewReader(dm.logFile)
  93. dm.isLoading = true
  94. defer func() { dm.isLoading = false }()
  95. for {
  96. line, err := util.Readln(lines)
  97. if err != nil && err != io.EOF {
  98. return err
  99. }
  100. if pe := dm.processEachLine(string(line)); pe != nil {
  101. return pe
  102. }
  103. if err == io.EOF {
  104. return nil
  105. }
  106. }
  107. }
  108. func (dm *DirectoryManagerInMap) findDirectory(dirPath string) (*DirectoryEntryInMap, error) {
  109. if dirPath == "" {
  110. return dm.Root, nil
  111. }
  112. dirPath = filepath.Clean(dirPath)
  113. if dirPath == "/" {
  114. return dm.Root, nil
  115. }
  116. parts := strings.Split(dirPath, "/")
  117. dir := dm.Root
  118. for i := 1; i < len(parts); i++ {
  119. if sub, ok := dir.SubDirectories[parts[i]]; ok {
  120. dir = sub
  121. } else {
  122. return dm.Root, fmt.Errorf("Directory %s Not Found", dirPath)
  123. }
  124. }
  125. return dir, nil
  126. }
  127. func (dm *DirectoryManagerInMap) FindDirectory(dirPath string) (DirectoryId, error) {
  128. d, e := dm.findDirectory(dirPath)
  129. if e == nil {
  130. return d.Id, nil
  131. }
  132. return dm.Root.Id, e
  133. }
  134. func (dm *DirectoryManagerInMap) loadDirectory(dirPath string, dirId DirectoryId) error {
  135. dirPath = filepath.Clean(dirPath)
  136. if dirPath == "/" {
  137. return nil
  138. }
  139. parts := strings.Split(dirPath, "/")
  140. dir := dm.Root
  141. for i := 1; i < len(parts); i++ {
  142. sub, ok := dir.SubDirectories[parts[i]]
  143. if !ok {
  144. if i != len(parts)-1 {
  145. return fmt.Errorf("%s should be created after parent %s!", dirPath, parts[i])
  146. }
  147. sub = dm.NewDirectoryEntryInMap(dir, parts[i])
  148. if sub.Id != dirId {
  149. return fmt.Errorf("%s should be have id %v instead of %v!", dirPath, sub.Id, dirId)
  150. }
  151. dir.SubDirectories[parts[i]] = sub
  152. }
  153. dir = sub
  154. }
  155. return nil
  156. }
  157. func (dm *DirectoryManagerInMap) makeDirectory(dirPath string) (dir *DirectoryEntryInMap, created bool) {
  158. dirPath = filepath.Clean(dirPath)
  159. if dirPath == "/" {
  160. return dm.Root, false
  161. }
  162. parts := strings.Split(dirPath, "/")
  163. dir = dm.Root
  164. for i := 1; i < len(parts); i++ {
  165. sub, ok := dir.SubDirectories[parts[i]]
  166. if !ok {
  167. sub = dm.NewDirectoryEntryInMap(dir, parts[i])
  168. dir.SubDirectories[parts[i]] = sub
  169. created = true
  170. }
  171. dir = sub
  172. }
  173. return dir, created
  174. }
  175. func (dm *DirectoryManagerInMap) MakeDirectory(dirPath string) (DirectoryId, error) {
  176. dir, _ := dm.makeDirectory(dirPath)
  177. return dir.Id, nil
  178. }
  179. func (dm *DirectoryManagerInMap) MoveUnderDirectory(oldDirPath string, newParentDirPath string) error {
  180. oldDir, oe := dm.findDirectory(oldDirPath)
  181. if oe != nil {
  182. return oe
  183. }
  184. parentDir, pe := dm.findDirectory(newParentDirPath)
  185. if pe != nil {
  186. return pe
  187. }
  188. delete(oldDir.Parent.SubDirectories, oldDir.Name)
  189. parentDir.SubDirectories[oldDir.Name] = oldDir
  190. oldDir.Parent = parentDir
  191. dm.log("mov", oldDirPath, newParentDirPath)
  192. return nil
  193. }
  194. func (dm *DirectoryManagerInMap) ListDirectories(dirPath string) (dirNames []DirectoryEntry, err error) {
  195. d, e := dm.findDirectory(dirPath)
  196. if e != nil {
  197. return dirNames, e
  198. }
  199. for k, v := range d.SubDirectories {
  200. dirNames = append(dirNames, DirectoryEntry{Name: k, Id: v.Id})
  201. }
  202. return dirNames, nil
  203. }
  204. func (dm *DirectoryManagerInMap) DeleteDirectory(dirPath string) error {
  205. if dirPath == "/" {
  206. return fmt.Errorf("Can not delete %s", dirPath)
  207. }
  208. d, e := dm.findDirectory(dirPath)
  209. if e != nil {
  210. return e
  211. }
  212. if len(d.SubDirectories) != 0 {
  213. return fmt.Errorf("dir %s still has sub directories", dirPath)
  214. }
  215. delete(d.Parent.SubDirectories, d.Name)
  216. d.Parent = nil
  217. dm.log("del", dirPath)
  218. return nil
  219. }