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.

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