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.

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