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.

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