Ejemplo n.º 1
0
// Attentez: It is not atomic
// If byForce set to false and the destination file exists, an EX_FOLDER_ALREADY_EXIST will be returned
func (this *Fs) MvXParalleled(srcName, srcInode, desName, desInode string, byForce bool) error {
	//Insider.LogD("MvXParalleled start")
	//defer Insider.LogD("MvXParalleled end")
	if !CheckValidFilename(srcName) || !CheckValidFilename(desName) {
		return exception.EX_INVALID_FILENAME
	}
	if !byForce && outapi.ForceCheckExist(this.io.CheckExist(GenFileName(desInode, desName))) {
		return exception.EX_FOLDER_ALREADY_EXIST
	}

	var modifiedMeta = FileMeta(map[string]string{
		META_PARENT_INODE: desInode,
	})
	//Insider.LogD("MvXParalleled::copy start")
	if err := this.io.Copy(GenFileName(srcInode, srcName), GenFileName(desInode, desName), modifiedMeta); err != nil {
		return exception.EX_FILE_NOT_EXIST
	}
	//Insider.LogD("MvXParalleled::copy end")

	var globalError *errorgroup.ErrorAssembly = nil
	var geLock sync.Mutex
	var wg sync.WaitGroup

	var routineToUpdateDesParentMap = func(oriMeta FileMeta) {
		defer wg.Done()
		//Insider.LogD("routineToUpdateDesParentMap start")
		//defer Insider.LogD("routineToUpdateDesParentMap end")

		if oriMeta == nil {
			return
		}

		{
			var desParentMap = dvc.GetFD(GenFileName(desInode, FOLDER_MAP), this.io)
			//Insider.Log("routineToUpdateDesParentMap", "GOT FD")
			if desParentMap == nil {
				Secretary.Error("kernel.filesystem::MvXParalleled", "Fail to get foldermap fd for folder "+desInode)
				geLock.Lock()
				globalError = errorgroup.AddIn(globalError, exception.EX_IO_ERROR)
				geLock.Unlock()
				return
			}
			if err := desParentMap.Submit(fc.FastMakeWithMeta(desName, InferFMapMetaFromNNodeMeta(oriMeta))); err != nil {
				Secretary.Error("kernel.filesystem::MvXParalleled", "Fail to submit foldermap patch for folder "+desInode)
				desParentMap.Release()
				geLock.Lock()
				globalError = errorgroup.AddIn(globalError, err)
				geLock.Unlock()
				return
			}
			//Insider.Log("routineToUpdateDesParentMap", "SUBMITTED")
			desParentMap.Release()
			//Insider.Log("routineToUpdateDesParentMap", "RELEASED")
		}
	}

	var routineToRemoveOldNnode = func() {
		defer wg.Done()
		//Insider.LogD("routineToRemoveOldNnode start")
		//defer Insider.LogD("routineToRemoveOldNnode end")

		this.io.Delete(GenFileName(srcInode, srcName))
	}

	var routineToUpdateSrcParentMap = func() {
		defer wg.Done()
		//Insider.LogD("routineToUpdateSrcParentMap start")
		//defer Insider.LogD("routineToUpdateSrcParentMap end")

		{
			var srcParentMap = dvc.GetFD(GenFileName(srcInode, FOLDER_MAP), this.io)
			//Insider.Log("routineToUpdateSrcParentMap", "GOT FD")
			if srcParentMap == nil {
				Secretary.Error("kernel.filesystem::MvXParalleled", "Fail to get foldermap fd for folder "+srcInode)
				geLock.Lock()
				globalError = errorgroup.AddIn(globalError, exception.EX_IO_ERROR)
				geLock.Unlock()
				return
			}
			if err := srcParentMap.Submit(filetype.FastAntiMake(srcName)); err != nil {
				Secretary.Error("kernel.filesystem::MvXParalleled", "Fail to submit foldermap patch for folder "+srcInode)
				srcParentMap.Release()
				geLock.Lock()
				globalError = errorgroup.AddIn(globalError, err)
				geLock.Unlock()
				return
			}
			//Insider.Log("routineToUpdateSrcParentMap", "SUBMITTED")
			srcParentMap.Release()
			//Insider.Log("routineToUpdateSrcParentMap", "RELEASED")
		}
	}

	var routineToUpdateDotDot = func() {
		defer wg.Done()
		//Insider.LogD("routineToUpdateDotDot start")
		//defer Insider.LogD("routineToUpdateDotDot end")

		var dstNnodeMeta, dstFileNnodeOriginal, _ = this.io.Get(GenFileName(desInode, desName))
		go routineToUpdateDesParentMap(dstNnodeMeta)

		var dstFileNnode, _ = dstFileNnodeOriginal.(*filetype.Nnode)
		if dstFileNnode == nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to read nnode "+GenFileName(desInode, desName)+".")
			geLock.Lock()
			globalError = errorgroup.AddIn(globalError, exception.EX_IO_ERROR)
			geLock.Unlock()

			return
		}
		var target = GenFileName(dstFileNnode.DesName, "..")
		if err := this.io.Put(target, filetype.NewNnode(desInode), nil); err != nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to modify .. link for "+dstFileNnode.DesName+".")
			geLock.Lock()
			globalError = errorgroup.AddIn(globalError, err)
			geLock.Unlock()
			return
		} else {
			// Secretary.Log("kernel.filesystem::MvX", "Update file "+target)
		}
	}

	wg.Add(4)
	// routineToUpdateDesParentMap() is invoked in routineToUpdateDotDot()
	go routineToRemoveOldNnode()
	go routineToUpdateSrcParentMap()
	go routineToUpdateDotDot()
	wg.Wait()

	return globalError
}
Ejemplo n.º 2
0
// 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
}
Ejemplo n.º 3
0
func (this *Fs) Put(filename string, frominode string, meta FileMeta /*=nil*/, dataSource io.Reader) (error, string) {
	var targetFileinode string
	var oldOriName string
	if filename != "" {
		// CREATE MODE
		if !CheckValidFilename(filename) {
			return exception.EX_INVALID_FILENAME, ""
		}
		// set inode
		targetFileinode = uniqueid.GenGlobalUniqueNameWithTag("Stream")
	} else {
		// OVERRIDE MODE
		var oldMeta, err = this.io.Getinfo(frominode)
		if oldMeta == nil {
			if err != nil {
				return err, ""
			}
			return exception.EX_FILE_NOT_EXIST, ""
		}
		oldOriName = oldMeta[META_ORIGINAL_NAME]
		targetFileinode = frominode
	}

	// set object node
	if meta == nil {
		meta = NewMeta()
	}
	meta = meta.Clone()
	meta[METAKEY_TYPE] = STREAM_TYPE
	if filename != "" {
		meta[META_ORIGINAL_NAME] = filename
	} else {
		meta[META_ORIGINAL_NAME] = oldOriName
	}

	if wc, err := this.io.PutStream(targetFileinode, meta); err != nil {
		Secretary.Error("kernel.filesystem::Put", "Put stream for new file "+GenFileName(frominode, filename)+" failed.")
		return err, targetFileinode
	} else {
		if _, err2 := io.Copy(wc, dataSource); err2 != nil {
			wc.Close()
			Secretary.Error("kernel.filesystem::Put", "Piping stream for new file "+GenFileName(frominode, filename)+" failed.")
			return err2, targetFileinode
		}
		if err2 := wc.Close(); err2 != nil {
			Secretary.Error("kernel.filesystem::Put", "Close writer for new file "+GenFileName(frominode, filename)+" failed.")
			return err2, targetFileinode
		}
	}

	if filename != "" {
		// CREATE MODE. Set its parent node's foldermap and write the nnode concurrently
		var currentHeader, terr = this.io.GetinfoX(targetFileinode)
		if currentHeader == nil {
			if terr != nil {
				Secretary.Warn("kernel.filesystem::Put", "Fail to refetch supposed-to-be file meta: "+targetFileinode+". Error is "+terr.Error())
			} else {
				Secretary.Warn("kernel.filesystem::Put", "Fail to refetch supposed-to-be file meta: "+targetFileinode+". The file seems to be non-existence.")
			}

			return exception.EX_CONCURRENT_CHAOS, targetFileinode
		}
		//fmt.Println(currentHeader)
		var pointedMeta = ConvertFileHeaderToNNodeMeta(currentHeader)
		var metaToSet = pointedMeta
		metaToSet[META_PARENT_INODE] = frominode
		metaToSet[META_INODE_TYPE] = META_INODE_TYPE_FILE

		var wg = sync.WaitGroup{}
		var globalError *egg.ErrorAssembly = nil
		var geLock sync.Mutex

		wg.Add(2)
		go (func() {
			defer wg.Done()

			// Write the nnode

			if err := this.io.Put(GenFileName(frominode, filename), filetype.NewNnode(targetFileinode), metaToSet); err != nil {
				Secretary.Warn("kernel.filesystem::Put", "Put nnode for new file "+GenFileName(frominode, filename)+" failed.")
				geLock.Lock()
				globalError = egg.AddIn(globalError, err)
				geLock.Unlock()
				return
			}
		})()

		go (func() {
			// update parentNode's foldermap
			defer wg.Done()

			var parentFD = dvc.GetFD(GenFileName(frominode, FOLDER_MAP), this.io)
			if parentFD == nil {
				Secretary.Error("kernel.filesystem::Put", "Get FD for "+GenFileName(frominode, FOLDER_MAP)+" failed.")
				geLock.Lock()
				globalError = egg.AddIn(globalError, exception.EX_INDEX_ERROR)
				geLock.Unlock()
				return
			}
			if err := parentFD.Submit(fc.FastMakeWithMeta(filename, InferFMapMetaFromNNodeMeta(metaToSet))); err != nil {
				Secretary.Error("kernel.filesystem::Put", "Submit patch for "+GenFileName(frominode, filename)+" failed: "+err.Error())
				parentFD.Release()
				geLock.Lock()
				globalError = egg.AddIn(globalError, exception.EX_INDEX_ERROR)
				geLock.Unlock()
				return
			}
			parentFD.Release()
		})()
		wg.Wait()

		if globalError != nil {
			return globalError, targetFileinode
		}
	}

	return nil, targetFileinode
}