// 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
}
Example #2
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) MvX(srcName, srcInode, desName, desInode string, byForce bool) error {
	// Create a mirror at destination position.
	// Then, remove the old one.
	// Third, modify the .. pointer.

	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,
	})
	if err := this.io.Copy(GenFileName(srcInode, srcName), GenFileName(desInode, desName), modifiedMeta); err != nil {
		return exception.EX_FILE_NOT_EXIST
	}

	// remove the old one.
	this.io.Delete(GenFileName(srcInode, srcName))

	{
		var srcParentMap = dvc.GetFD(GenFileName(srcInode, FOLDER_MAP), this.io)
		if srcParentMap == nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to get foldermap fd for folder "+srcInode)
			return exception.EX_IO_ERROR
		}
		if err := srcParentMap.Submit(filetype.FastAntiMake(srcName)); err != nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to submit foldermap patch for folder "+srcInode)
			srcParentMap.Release()
			return err
		}
		srcParentMap.Release()
	}

	// modify the .. pointer
	var dstMeta, dstFileNnodeOriginal, _ = this.io.Get(GenFileName(desInode, desName))
	var dstFileNnode, _ = dstFileNnodeOriginal.(*filetype.Nnode)
	if dstFileNnode == nil {
		Secretary.Error("kernel.filesystem::MvX", "Fail to read nnode "+GenFileName(desInode, desName)+".")
		return exception.EX_IO_ERROR
	}

	{
		var desParentMap = dvc.GetFD(GenFileName(desInode, FOLDER_MAP), this.io)
		if desParentMap == nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to get foldermap fd for folder "+desInode)
			return exception.EX_IO_ERROR
		}
		if err := desParentMap.Submit(fc.FastMakeWithMeta(desName, InferFMapMetaFromNNodeMeta(dstMeta))); err != nil {
			Secretary.Error("kernel.filesystem::MvX", "Fail to submit foldermap patch for folder "+desInode)
			desParentMap.Release()
			return err
		}
		desParentMap.Release()
	}

	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+".")
		return err
	} else {
		//Secretary.Log("kernel.filesystem::MvX", "Update file "+target)
	}

	// ALL DONE!
	return nil

}