func()

in component/azstorage/block_blob.go [344:415]


func (bb *BlockBlob) RenameFile(source string, target string, srcAttr *internal.ObjAttr) error {
	log.Trace("BlockBlob::RenameFile : %s -> %s", source, target)

	blobClient := bb.Container.NewBlockBlobClient(filepath.Join(bb.Config.prefixPath, source))
	newBlobClient := bb.Container.NewBlockBlobClient(filepath.Join(bb.Config.prefixPath, target))

	// not specifying source blob metadata, since passing empty metadata headers copies
	// the source blob metadata to destination blob
	copyResponse, err := newBlobClient.StartCopyFromURL(context.Background(), blobClient.URL(), &blob.StartCopyFromURLOptions{
		Tier: bb.Config.defaultTier,
	})

	if err != nil {
		serr := storeBlobErrToErr(err)
		if serr == ErrFileNotFound {
			//Ideally this case doesn't hit as we are checking for the existence of src
			//before making the call for RenameFile
			log.Err("BlockBlob::RenameFile : Src Blob doesn't Exist %s [%s]", source, err.Error())
			return syscall.ENOENT
		}
		log.Err("BlockBlob::RenameFile : Failed to start copy of file %s [%s]", source, err.Error())
		return err
	}

	var dstLMT *time.Time = copyResponse.LastModified
	var dstETag string = sanitizeEtag(copyResponse.ETag)

	copyStatus := copyResponse.CopyStatus
	var prop blob.GetPropertiesResponse
	pollCnt := 0
	for copyStatus != nil && *copyStatus == blob.CopyStatusTypePending {
		time.Sleep(time.Second * 1)
		pollCnt++
		prop, err = newBlobClient.GetProperties(context.Background(), &blob.GetPropertiesOptions{
			CPKInfo: bb.blobCPKOpt,
		})
		if err != nil {
			log.Err("BlockBlob::RenameFile : CopyStats : Failed to get blob properties for %s [%s]", source, err.Error())
		}
		copyStatus = prop.CopyStatus
	}

	if pollCnt > 0 {
		dstLMT = prop.LastModified
		dstETag = sanitizeEtag(prop.ETag)
	}

	if copyStatus != nil && *copyStatus == blob.CopyStatusTypeSuccess {
		modifyLMTandEtag(srcAttr, dstLMT, dstETag)
	}

	log.Trace("BlockBlob::RenameFile : %s -> %s done", source, target)

	// Copy of the file is done so now delete the older file
	err = bb.DeleteFile(source)
	for retry := 0; retry < 3 && err == syscall.ENOENT; retry++ {
		// Sometimes backend is able to copy source file to destination but when we try to delete the
		// source files it returns back with ENOENT. If file was just created on backend it might happen
		// that it has not been synced yet at all layers and hence delete is not able to find the source file
		log.Trace("BlockBlob::RenameFile : %s -> %s, unable to find source. Retrying %d", source, target, retry)
		time.Sleep(1 * time.Second)
		err = bb.DeleteFile(source)
	}

	if err == syscall.ENOENT {
		// Even after 3 retries, 1 second apart if server returns 404 then source file no longer
		// exists on the backend and its safe to assume rename was successful
		err = nil
	}

	return err
}