io.milton.zsync.FileMaker Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/* FileMaker.java
FileMaker: File reading and making class
Copyright (C) 2011 Tomáš Hlavnička
This file is a part of Jazsync.
Jazsync is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
Jazsync is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jazsync; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place, Suite 330,
Boston, MA 02111-1307
USA
*/
package io.milton.zsync;
import io.milton.httpclient.zsyncclient.RangeLoader;
import io.milton.http.Range;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is normally used to create a copy of a remote file, where a local
* copy is already present which might contain some or all of the remote data.
*
* FileMaker implements an algorithm similar to rsync which optimises the amount
* of data downloaded by matching blocks of data in the local file against the
* remote and only downloading blocks which differ.
*
* The given local file is not updated by this class, instead a copy is produced
* as a temp file, and it is up to the calling code to replace the old local
* file with the new one.
*
* Most of the code in this package was taken from the jazsync project, please
* see the header comments for license details.
*
* @author Tomáš Hlavnička, modified by Brad McEvoy
*/
public class FileMaker {
private static final Logger log = LoggerFactory.getLogger(FileMaker.class);
private final MapMatcher mapMatcher = new MapMatcher();
private final FileUpdater fileUpdater = new FileUpdater();
private final FileDownloader fileDownloader = new FileDownloader();
public FileMaker() {
}
/**
*
* @param inputFile - the "local" file, containing data which needs to be
* merged with that on the server
* @param metafile - meta file, containing headers and checksums of the
* "remote", generated by MetaFileMaker
* @param rangeLoader - accessor object, to get the binary data of the
* "remote" file
*/
public File make(File inputFile, File metafile, RangeLoader rangeLoader) throws Exception {
MetaFileReader mfr = new MetaFileReader(metafile);
return make(mfr, inputFile, rangeLoader);
}
private File make(MetaFileReader mfr, File inputFile, RangeLoader rangeLoader) throws Exception {
MakeContext makeContext = new MakeContext(mfr.getHashtable(), new long[mfr.getBlockCount()]);
Arrays.fill(makeContext.fileMap, -1);
double complete = mapMatcher.mapMatcher(inputFile, mfr, makeContext);
File dest = null;
dest = File.createTempFile("zsyncM_", "_" + inputFile.getName());
if (complete == 0) {
log.info("local file has no corresponding blocks, so download whole file");
fileDownloader.downloadWholeFile(rangeLoader, dest);
} else {
fileUpdater.update(inputFile, mfr, rangeLoader, makeContext, dest);
}
return dest;
}
/**
* Determine what ranges need to be provided to sync the file.
*
* @param mfr
* @param inputFile
* @param rangeLoader
* @param dryRun
* @return - null indicates everything is needed, ie whole file
* @throws Exception
*/
public List findMissingRanges(File inputFile, File metafile) throws Exception {
MetaFileReader mfr = new MetaFileReader(metafile);
MakeContext mc = new MakeContext(mfr.getHashtable(), new long[mfr.getBlockCount()]);
Arrays.fill(mc.fileMap, -1);
double complete = mapMatcher.mapMatcher(inputFile, mfr, mc);
if (complete == 0) {
return null;
}
List ranges = new ArrayList<>();
int blocksize = mfr.getBlocksize();
for (int i = 0; i < mc.fileMap.length; i++) {
if (mc.fileMap[i] == -1) {
ranges.add(new Range((long)(i * blocksize), (long)(i * blocksize) + blocksize));
}
}
return ranges;
}
//
// public void make(File fLocal, MetaData metaData, LocalFileRangeLoader rangeLoader) {
// MetaFileReader mfr = new MetaFileReader(metaData);
// }
}