Example #1
0
// FoldFile folds child snapshot data into its parent
func FoldFile(childFileName, parentFileName string) error {

	childFInfo, err := os.Stat(childFileName)
	if err != nil {
		panic("os.Stat(childFileName) failed, error: " + err.Error())
	}
	parentFInfo, err := os.Stat(parentFileName)
	if err != nil {
		panic("os.Stat(parentFileName) failed, error: " + err.Error())
	}

	// ensure no directory
	if childFInfo.IsDir() || parentFInfo.IsDir() {
		panic("at least one file is directory, not a normal file")
	}

	// ensure file sizes are equal
	if childFInfo.Size() != parentFInfo.Size() {
		panic("file sizes are not equal")
	}

	// open child and parent files
	childFile, err := fio.OpenFile(childFileName, os.O_RDONLY, 0)
	if err != nil {
		panic("Failed to open childFile, error: " + err.Error())
	}
	defer childFile.Close()

	parentFile, err := fio.OpenFile(parentFileName, os.O_WRONLY, 0)
	if err != nil {
		panic("Failed to open parentFile, error: " + err.Error())
	}
	defer parentFile.Close()

	return coalesce(parentFile, childFile)
}
Example #2
0
func syncFile(localPath string, addr TCPEndPoint, remotePath string, timeout int, retry bool) ([]byte, error) {
	file, err := fio.OpenFile(localPath, os.O_RDONLY, 0)
	if err != nil {
		log.Error("Failed to open local source file:", localPath)
		return nil, err
	}
	defer file.Close()

	size, err := file.Seek(0, os.SEEK_END)
	if err != nil {
		log.Error("Failed to get size of local source file:", localPath, err)
		return nil, err
	}

	SetupFileIO(size%Blocks == 0)

	conn := connect(addr.Host, strconv.Itoa(int(addr.Port)), timeout)
	if nil == conn {
		err = fmt.Errorf("Failed to connect to %v", addr)
		log.Error(err)
		return nil, err
	}
	defer conn.Close()

	encoder := gob.NewEncoder(conn)
	decoder := gob.NewDecoder(conn)

	// Use unix time as hash salt
	salt := make([]byte, binary.MaxVarintLen64)
	binary.PutVarint(salt, time.Now().UnixNano())
	status := sendSyncRequest(encoder, decoder, remotePath, size, salt)
	if !status {
		err = fmt.Errorf("Sync request to %v failed", remotePath)
		log.Error(err)
		return nil, err
	}

	abortStream := make(chan error)
	layoutStream := make(chan FileInterval, 128)
	errStream := make(chan error)

	// Initiate interval loading...
	err = loadFileLayout(abortStream, file, layoutStream, errStream)
	if err != nil {
		log.Error("Failed to retrieve local file layout:", err)
		return nil, err
	}

	fileStream := make(chan FileInterval, 128)
	unorderedStream := make(chan HashedDataInterval, 128)
	orderedStream := make(chan HashedDataInterval, 128)

	go IntervalSplitter(layoutStream, fileStream)
	FileReaderGroup(fileReaders, salt, fileStream, localPath, unorderedStream)
	go OrderIntervals("src:", unorderedStream, orderedStream)

	// Get remote file intervals and their hashes
	netInStream := make(chan HashedInterval, 128)
	netInStreamDone := make(chan bool)
	go netDstReceiver(decoder, netInStream, netInStreamDone)

	return processDiff(salt, abortStream, errStream, encoder, decoder, orderedStream, netInStream, netInStreamDone, retry)
}