// If the file exist and forceMake==false, an error EX_FOLDER_ALREADY_EXIST will be returned func (this *Fs) MkdirParalleled(foldername string, frominode string, forceMake bool) error { if !CheckValidFilename(foldername) { return exception.EX_INVALID_FILENAME } // nnodeName: parentInode::foldername var nnodeName = GenFileName(frominode, foldername) if !forceMake { if tmeta, _ := this.io.Getinfo(nnodeName); tmeta != nil { return exception.EX_FOLDER_ALREADY_EXIST } } var newDomainname = uniqueid.GenGlobalUniqueName() var globalError *errorgroup.ErrorAssembly = nil var geLock sync.Mutex var wg sync.WaitGroup // create target inode and write parent folder map var routineToCreateInode = func() { defer wg.Done() var newNnode = filetype.NewNnode(newDomainname) var initMeta = FileMeta(map[string]string{ META_INODE_TYPE: META_INODE_TYPE_FOLDER, META_PARENT_INODE: frominode, }) if err := this.io.Put(nnodeName, newNnode, initMeta); err != nil { geLock.Lock() globalError = errorgroup.AddIn(globalError, err) geLock.Unlock() return } // submit patch to parent folder's map { var parentFolderMapFD = dvc.GetFD(GenFileName(frominode, FOLDER_MAP), this.io) if parentFolderMapFD == nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to create foldermap fd for new folder "+nnodeName+"'s parent map'") geLock.Lock() globalError = errorgroup.AddIn(globalError, exception.EX_IO_ERROR) geLock.Unlock() return } if err := parentFolderMapFD.Submit(fc.FastMakeFolderPatch(foldername)); err != nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to submit patch to foldermap for new folder "+nnodeName+"'s parent map'") parentFolderMapFD.Release() geLock.Lock() globalError = errorgroup.AddIn(globalError, err) geLock.Unlock() return } parentFolderMapFD.Release() } } var initMetaSelf = FileMeta(map[string]string{ META_INODE_TYPE: META_INODE_TYPE_FOLDER, META_PARENT_INODE: newDomainname, }) var routineToCreateDotDot = func() { defer wg.Done() if err := this.io.Put(GenFileName(newDomainname, ".."), filetype.NewNnode(frominode), initMetaSelf); err != nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to create .. link for new folder "+nnodeName+".") geLock.Lock() globalError = errorgroup.AddIn(globalError, err) geLock.Unlock() return } } var routineToCreateDot = func() { defer wg.Done() if err := this.io.Put(GenFileName(newDomainname, "."), filetype.NewNnode(newDomainname), initMetaSelf); err != nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to create . link for new folder "+nnodeName+".") geLock.Lock() globalError = errorgroup.AddIn(globalError, err) geLock.Unlock() return } } var routineToWriteNewMap = func() { defer wg.Done() { var newFolderMapFD = dvc.GetFD(GenFileName(newDomainname, FOLDER_MAP), this.io) if newFolderMapFD == nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to create foldermap fd for new folder "+nnodeName+".") geLock.Lock() globalError = errorgroup.AddIn(globalError, exception.EX_IO_ERROR) geLock.Unlock() return } if err := newFolderMapFD.Submit(fc.FastMakeFolderPatch(".", "..")); err != nil { Secretary.Error("kernel.filesystem::MkdirParalleled", "Fail to init foldermap for new folder "+nnodeName+".") newFolderMapFD.Release() geLock.Lock() globalError = errorgroup.AddIn(globalError, err) geLock.Unlock() return } newFolderMapFD.Release() } } wg.Add(4) go routineToCreateInode() go routineToCreateDotDot() go routineToCreateDot() go routineToWriteNewMap() wg.Wait() // NOW All the routines have returned and globalError stores all the errors // TODO: consider clearing roll-back return globalError }
// If the file exist and forceMake==false, an error EX_FOLDER_ALREADY_EXIST will be returned func (this *Fs) Mkdir(foldername string, frominode string, forceMake bool) error { if !CheckValidFilename(foldername) { return exception.EX_INVALID_FILENAME } // nnodeName: parentInode::foldername var nnodeName = GenFileName(frominode, foldername) if !forceMake { if tmeta, _ := this.io.Getinfo(nnodeName); tmeta != nil { return exception.EX_FOLDER_ALREADY_EXIST } } // newDomainname: <GENERATED> var newDomainname = uniqueid.GenGlobalUniqueName() var newNnode = filetype.NewNnode(newDomainname) var initMeta = FileMeta(map[string]string{ META_INODE_TYPE: META_INODE_TYPE_FOLDER, META_PARENT_INODE: frominode, }) if err := this.io.Put(nnodeName, newNnode, initMeta); err != nil { return err } // initialize two basic element var initMetaSelf = FileMeta(map[string]string{ META_INODE_TYPE: META_INODE_TYPE_FOLDER, META_PARENT_INODE: newDomainname, }) if err := this.io.Put(GenFileName(newDomainname, ".."), filetype.NewNnode(frominode), initMetaSelf); err != nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to create .. link for new folder "+nnodeName+".") return err } if err := this.io.Put(GenFileName(newDomainname, "."), filetype.NewNnode(newDomainname), initMetaSelf); err != nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to create . link for new folder "+nnodeName+".") return err } // write new folder's map { var newFolderMapFD = dvc.GetFD(GenFileName(newDomainname, FOLDER_MAP), this.io) if newFolderMapFD == nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to create foldermap fd for new folder "+nnodeName+".") return exception.EX_IO_ERROR } if err := newFolderMapFD.Submit(fc.FastMakeFolderPatch(".", "..")); err != nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to init foldermap for new folder "+nnodeName+".") newFolderMapFD.Release() return err } newFolderMapFD.Release() } // submit patch to parent folder's map { var parentFolderMapFD = dvc.GetFD(GenFileName(frominode, FOLDER_MAP), this.io) if parentFolderMapFD == nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to create foldermap fd for new folder "+nnodeName+"'s parent map'") return exception.EX_IO_ERROR } if err := parentFolderMapFD.Submit(fc.FastMakeFolderPatch(foldername)); err != nil { Secretary.Error("kernel.filesystem::Mkdir", "Fail to submit patch to foldermap for new folder "+nnodeName+"'s parent map'") parentFolderMapFD.Release() return err } parentFolderMapFD.Release() } return nil }