diff options
Diffstat (limited to 'src/main/java/org/openslx/imagemaster/serverconnection')
5 files changed, 171 insertions, 629 deletions
diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/AbstractTransfer.java b/src/main/java/org/openslx/imagemaster/serverconnection/AbstractTransfer.java new file mode 100644 index 0000000..3acac5b --- /dev/null +++ b/src/main/java/org/openslx/imagemaster/serverconnection/AbstractTransfer.java @@ -0,0 +1,92 @@ +package org.openslx.imagemaster.serverconnection; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +public abstract class AbstractTransfer { + + /** + * How long to keep this transfer information when the transfer is + * (potentially) done + */ + private static final long FINISH_TIMEOUT = TimeUnit.MINUTES.toMillis(5); + + /** + * How long to keep this transfer information when there are no active + * connections and the transfer seems unfinished + */ + private static final long IDLE_TIMEOUT = TimeUnit.HOURS.toMillis(4); + + /** + * Time stamp of when (we think) the transfer finished. Clients can/might + * not tell us they're done, and simply taking "no active connection" as a + * sign the download is done might have unwanted effects if the user's + * connection drops for a minute. If this time stamp (plus a FINISH_TIMEOUT) + * passed, + * we consider the download done and flag it for removal. + * If set to zero, the transfer is not finished, or not assumed to have + * finished. + */ + protected final AtomicLong potentialFinishTime = new AtomicLong(0); + + /** + * Time of last activity on this transfer. + */ + protected final AtomicLong lastActivityTime = new AtomicLong(System.currentTimeMillis()); + + private final String transferId; + + public AbstractTransfer(String transferId) { + this.transferId = transferId; + } + + /** + * Returns true if the transfer is considered completed. + * + * @param now pass System.currentTimeMillis() + * @return true if the transfer is considered completed + */ + public boolean isComplete(long now) { + long val = potentialFinishTime.get(); + return val != 0 && val + FINISH_TIMEOUT < now; + } + + /** + * Returns true if there has been no activity on this transfer for a certain + * amount of time. + * + * @param now pass System.currentTimeMillis() + * @return true if the transfer reached its idle timeout + */ + public final boolean hasReachedIdleTimeout(long now) { + return getActiveConnectionCount() == 0 && lastActivityTime.get() + IDLE_TIMEOUT < now; + } + + public final String getId() { + return transferId; + } + + /** + * Returns true if this transfer would potentially accept new connections. + * This should NOT return false if there are too many concurrent + * connections, as this is used to signal the client whether to keep trying + * to connect. + * + * @return true if this transfer would potentially accept new connections + */ + public abstract boolean isActive(); + + /** + * Cancel this transfer, aborting all active connections and rejecting + * further incoming ones. + */ + public abstract void cancel(); + + /** + * Returns number of active transfer connections. + * + * @return number of active transfer connections + */ + public abstract int getActiveConnectionCount(); + +} diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java b/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java index 12b5701..9340706 100644 --- a/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java +++ b/src/main/java/org/openslx/imagemaster/serverconnection/ConnectionHandler.java @@ -1,17 +1,11 @@ package org.openslx.imagemaster.serverconnection; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.security.KeyManagementException; import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -20,16 +14,22 @@ import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import org.apache.commons.lang.mutable.MutableInt; import org.apache.log4j.Logger; +import org.openslx.bwlp.thrift.iface.ImagePublishData; +import org.openslx.bwlp.thrift.iface.InvocationError; +import org.openslx.bwlp.thrift.iface.TInvocationException; +import org.openslx.bwlp.thrift.iface.TTransferRejectedException; +import org.openslx.bwlp.thrift.iface.TransferInformation; import org.openslx.filetransfer.Downloader; -import org.openslx.filetransfer.FileRange; import org.openslx.filetransfer.IncomingEvent; import org.openslx.filetransfer.Listener; import org.openslx.filetransfer.Uploader; -import org.openslx.filetransfer.WantRangeCallback; import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.db.DbImage; +import org.openslx.imagemaster.crcchecker.CrcFile; +import org.openslx.imagemaster.db.mappers.DbOsVirt; +import org.openslx.imagemaster.db.mappers.DbUser; +import org.openslx.imagemaster.util.RandomString; +import org.openslx.imagemaster.util.Util; /** * Class to handle all incoming and outgoing connections. @@ -41,8 +41,8 @@ public class ConnectionHandler implements IncomingEvent private static Logger log = Logger.getLogger( ConnectionHandler.class ); private static SSLContext sslContext; - private static Map<String, UploadingImage> pendingIncomingUploads = new ConcurrentHashMap<>(); - private static Map<String, DbImage> pendingIncomingDownloads = new ConcurrentHashMap<>(); + private static Map<String, AbstractTransfer> pendingIncomingUploads = new ConcurrentHashMap<>(); + private static Map<String, AbstractTransfer> pendingIncomingDownloads = new ConcurrentHashMap<>(); private static IncomingEvent eventHandler = new ConnectionHandler(); private static ThreadPoolExecutor uploadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue<Runnable>() ); private static ThreadPoolExecutor downloadPool = new ThreadPoolExecutor( 0, 5, 6, TimeUnit.MINUTES, new SynchronousQueue<Runnable>() ); @@ -61,40 +61,75 @@ public class ConnectionHandler implements IncomingEvent sslContext = SSLContext.getInstance( "SSLv3" ); KeyManager[] keyManagers = kmf.getKeyManagers(); sslContext.init( keyManagers, null, null ); - listener = new Listener( eventHandler, sslContext, Globals.getSslSocketPort() ); + listener = new Listener( eventHandler, sslContext, Globals.getSslSocketPort(), 15000 ); listener.start(); - } catch ( FileNotFoundException e ) { - log.error( "Could not find keystore." ); - System.exit( 2 ); - } catch ( KeyStoreException e ) { - log.error( "KeyStore implemenation not supported." ); - System.exit( 2 ); - } catch ( NoSuchAlgorithmException e ) { - log.error( "Could not find such Algorithm" ); - System.exit( 2 ); - } catch ( CertificateException e ) { - log.error( "Certificate unvalid." ); - System.exit( 2 ); - } catch ( IOException e ) { - log.error( "Could not read keyfile" ); - System.exit( 2 ); - } catch ( UnrecoverableKeyException e ) { - log.error( "Key in keystore is not valid" ); - System.exit( 2 ); - } catch ( KeyManagementException e ) { - log.error( "Context initialization failed." ); + } catch ( Exception e ) { + log.error( "Initialization failed.", e ); System.exit( 2 ); } } /** + * Checks if this image is already uploading and returns a new list with missing blocks if so. + * Puts the new image into processing list else. + * + * @param serverSessionId The uploading server + * @param imageData The data of the image + * @return + * @throws UploadException If some error occurred during the process + */ + public static TransferInformation getUploadInfos( ImagePublishData imageData, List<Integer> crcSums ) + throws TTransferRejectedException, TInvocationException + { + // check image data + if ( Util.isEmpty( imageData.imageName ) ) + throw new TInvocationException( InvocationError.INVALID_DATA, "Image name not set" ); + if ( !DbUser.exists( imageData.user ) ) + throw new TInvocationException( InvocationError.INVALID_DATA, "Invalid or missing image owner" ); + if ( DbOsVirt.osExists( imageData.osId ) ) + throw new TInvocationException( InvocationError.INVALID_DATA, "Content operating system not set" ); + if ( DbOsVirt.virtExists( imageData.virtId ) ) + throw new TInvocationException( InvocationError.INVALID_DATA, "Content virtualizer system not set" ); + if ( imageData.fileSize <= 0 ) + throw new TInvocationException( InvocationError.INVALID_DATA, "File size is too small" ); + + log.debug( "A satellite is submitting " + imageData.imageVersionId ); + + final String uuid = imageData.imageVersionId; + final String filepathRelative; + final CrcFile crcFile; + if ( crcSums == null ) { + crcFile = null; + } else { + crcFile = new CrcFile( crcSums ); + } + ImagePublishData image; + + synchronized ( pendingIncomingUploads ) { + /* + // check if image is already uploading + if ( ( image = uploadingImages.get( uuid ) ) == null ) { + // TODO insert new image to DB + uploadingImages.put( uuid, image ); + } + */ + } + + final String token = RandomString.generate( 50, false ); + + // TODO addUpload( token, image ); + // TODO Set crc file on image - if there is already a crc file assigned, this does nothing + return new TransferInformation( token, Globals.getPlainSocketPort(), Globals.getSslSocketPort() ); + } + + /** * Add a new allowed incoming upload connection * for the given token and image. * * @param token The unique token * @param image Image being uploaded */ - public static void addUpload( String token, UploadingImage image ) + public static void addUpload( String token, AbstractTransfer image ) { pendingIncomingUploads.put( token, image ); log.debug( "Added upload" ); @@ -107,7 +142,7 @@ public class ConnectionHandler implements IncomingEvent * @param token The unique token * @param image Image being uploaded */ - public static void addDownload( String token, DbImage image ) + public static void addDownload( String token, AbstractTransfer image ) { pendingIncomingDownloads.put( token, image ); log.debug( "Added download" ); @@ -117,94 +152,21 @@ public class ConnectionHandler implements IncomingEvent * Server is uploading - client is downloading! */ @Override - public void incomingUploader( final Uploader uploader ) + public void incomingDownloadRequest( final Uploader uploader ) { - String token = uploader.getToken(); - // check token to identify the client - if ( token == null ) { - uploader.sendErrorCode( "No token available." ); - uploader.close( null ); - return; - } - - final DbImage image = pendingIncomingDownloads.remove( token ); - if ( image == null ) { - uploader.sendErrorCode( "Token not accepted." ); - uploader.close( null ); - return; - } - - try { - uploadPool.execute( new Runnable() { - @Override - public void run() - { - uploader.upload( image.getAbsolutePath() ); - } - } ); - } catch ( RejectedExecutionException e ) { - uploader.sendErrorCode( "Too many concurrent uploads." ); - uploader.close( null ); - } + // TODO + uploader.sendErrorCode( "Too many concurrent uploads." ); + uploader.cancel(); } /** * Server is downloading - client is uploading! */ @Override - public void incomingDownloader( final Downloader downloader ) throws IOException + public void incomingUploadRequest( final Downloader downloader ) throws IOException { - log.debug( "Client wants to upload" ); - String token = downloader.getToken(); - if ( token == null ) - { - downloader.sendErrorCode( "No token available." ); - downloader.close( null ); - return; - } - - final UploadingImage image = pendingIncomingUploads.remove( token ); - if ( image == null ) { - downloader.sendErrorCode( "Token not accepted." ); - downloader.close( null ); - return; - } - final MutableInt lastBlock = new MutableInt( -1 ); - - try { - downloadPool.execute( new Runnable() { - @Override - public void run() - { - downloader.download( image.getAbsolutePath(), new WantRangeCallback() { - @Override - public FileRange get() - { - if ( lastBlock.intValue() != -1 ) { - image.setNeedsCheck( lastBlock.intValue() ); - image.increaseTransmittedTimes( lastBlock.intValue() ); - } - // get start of range. - int blockNumber = image.getNextMissingBlock(); - if ( blockNumber == -1 ) { - log.debug( "Download complete." ); - return null; - } - lastBlock.setValue( blockNumber ); - log.debug( "Block " + blockNumber + " was transmitted " + image.getTimesTransmitted( blockNumber ) + " time(s)." ); - - long startOfRange = image.getNextMissingBlock() * Globals.blockSize; - long endOfRange = Math.min( startOfRange + Globals.blockSize, image.getFileSize() ); - FileRange range = new FileRange( startOfRange, endOfRange ); - return range; - } - } ); - image.updateDb(); - } - } ); - } catch ( RejectedExecutionException e ) { - downloader.sendErrorCode( "Too many concurrent downloads." ); - downloader.close( null ); - } + // TODO + downloader.sendErrorCode( "Too many concurrent downloads." ); + downloader.cancel(); } } diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/CrcScheduler.java b/src/main/java/org/openslx/imagemaster/serverconnection/CrcScheduler.java deleted file mode 100644 index 031a807..0000000 --- a/src/main/java/org/openslx/imagemaster/serverconnection/CrcScheduler.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.openslx.imagemaster.serverconnection; - -import java.io.IOException; -import java.util.Iterator; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import org.apache.log4j.Logger; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.crcchecker.CrcChecker; - -/** - * Class to schedule CRC checks. - * CRC checks of uploading images are so done parallel to the connection. - */ -public class CrcScheduler extends TimerTask -{ - - private static Logger log = Logger.getLogger( CrcScheduler.class ); - - @Override - public void run() - { - List<UploadingImage> list = ImageProcessor.getImagesToCheck(); - if ( list == null || list.isEmpty() ) - return; - log.debug( "Starting checks: " + list ); - Iterator<UploadingImage> iter = list.iterator(); - // iterate over the uploading images that need to be checked - while ( iter.hasNext() ) { - UploadingImage image = iter.next(); - log.debug( "Checking blocks of " + image.getUuid() ); - CrcChecker crcChecker = new CrcChecker( image.getImageFile(), image.getCrcFile() ); - log.debug( "CRCFile is valid: " + crcChecker.hasValidCrcFile() ); - if ( !crcChecker.hasValidCrcFile() ) { - image.setCrcFile( null ); // set crc file to null, so that the image processor will try to write it again. - crcChecker.done(); - continue; - } - for ( int block = 0; block < image.getNumberOfBlocks(); block++ ) { - if ( image.needsCheck( block ) ) { - try { - if ( crcChecker.checkBlock( block ) ) { - image.setValid( block ); - log.debug( block + " was valid" ); - } else { - image.setNeedsRequest( block ); - log.debug( block + " was NOT valid" ); - } - } catch ( IOException e ) { - if ( e.getMessage().equalsIgnoreCase( "crc" ) ) { - image.setCrcFile( null ); // set crc file to null, so that the imageprocessor will try to write it again. - image.updateDb(); - crcChecker.done(); - break; - } else { - // could not read image file - log.error( "Could not read from image file on disk. Pleas contact the server administrator. Image: '" + image.getImageFile().toString() + "'" ); - } - } - } - } - image.updateDb(); // writes valid blocks to database - crcChecker.done(); // closes image file - } - log.debug( "... done" ); - } - - public static void startScheduling() - { - Timer timer = new Timer( "CRCScheduler" ); - - // start now and fire every 60 s - timer.schedule( new CrcScheduler(), 0, Globals.getCrcSchedulingInterval() * 1000L ); - } - -} diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java deleted file mode 100644 index 15de77b..0000000 --- a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java +++ /dev/null @@ -1,191 +0,0 @@ -package org.openslx.imagemaster.serverconnection; - -import java.io.File; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.log4j.Logger; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.crcchecker.CrcFile; -import org.openslx.imagemaster.db.DbImage; -import org.openslx.imagemaster.db.DbUser; -import org.openslx.imagemaster.thrift.iface.DownloadData; -import org.openslx.imagemaster.thrift.iface.ImageData; -import org.openslx.imagemaster.thrift.iface.ImageDataError; -import org.openslx.imagemaster.thrift.iface.ImageDataException; -import org.openslx.imagemaster.thrift.iface.UploadData; -import org.openslx.imagemaster.thrift.iface.UploadError; -import org.openslx.imagemaster.thrift.iface.UploadException; -import org.openslx.imagemaster.util.RandomString; -import org.openslx.imagemaster.util.Util; - -/** - * Processing the up- and download of images. - * Handles who is authorized and knows which blocks are missing / need to be sent - */ -public class ImageProcessor -{ - - private static final Logger log = Logger.getLogger( ImageProcessor.class ); - - /** - * The uploading images. - * Key: imageUUID, - * Value: uploadingImageInfos - */ - private static Map<String, UploadingImage> uploadingImages = new ConcurrentHashMap<>(); - - /** - * The UUIDs of the images that need to be checked by the crc checker. - */ - private static List<String> imagesToCheck = new ArrayList<>(); - - /** - * Checks if this image is already uploading and returns a new list with missing blocks if so. - * Puts the new image into processing list else. - * - * @param serverSessionId The uploading server - * @param imageData The data of the image - * @return - * @throws UploadException If some error occurred during the process - */ - public static UploadData getUploadInfos( ImageData imageData, List<Integer> crcSums ) - throws UploadException, ImageDataException - { - // check image data - if ( imageData.title == null || imageData.title.isEmpty() ) - throw new ImageDataException( ImageDataError.INVALID_DATA, "Image name not set." ); - if ( imageData.ownerLogin == null || !DbUser.exists( imageData.ownerLogin ) ) - throw new ImageDataException( ImageDataError.INVALID_DATA, "Invalid image owner: " + imageData.ownerLogin ); - if ( !imageData.isSetOperatingSystem() ) - throw new ImageDataException( ImageDataError.INVALID_DATA, "Content operating system not set." ); - if ( imageData.fileSize <= 0 ) - throw new ImageDataException( ImageDataError.INVALID_DATA, "File size is too small." ); - - log.debug( "Satellite is submitting " + imageData.uuid ); - - final String uuid = imageData.uuid; - final String filepathRelative; - final CrcFile crcFile; - if ( crcSums == null ) { - crcFile = null; - } else { - crcFile = new CrcFile( crcSums ); - } - UploadingImage image; - - synchronized ( uploadingImages ) { - // check if image is already uploading - if ( ( image = uploadingImages.get( uuid ) ) == null ) { - // insert new image - if ( crcSums != null && !crcFile.isValid() ) - throw new UploadException( UploadError.INVALID_CRC, "CRC sums were invalid." ); - filepathRelative = generateFilepathOfImage( imageData ); - DbImage.insert( imageData, filepathRelative ); // Make sure it exists in DB - try { - image = new UploadingImage( uuid ); - } catch ( Exception e ) { - throw new UploadException( UploadError.GENERIC_ERROR, "Internal error" ); - } - uploadingImages.put( uuid, image ); - } - } - - final String token = RandomString.generate( 50, false ); - - ConnectionHandler.addUpload( token, image ); - // Set crc file on image - if there is already a crc file assigned, this does nothing - image.setCrcFile( crcFile ); - if ( image.allBlocksValid() ) - removeFinishedUploads(); - return new UploadData( token, Globals.getSslSocketPort() ); - } - - public static DownloadData getDownloadInfos( String uuid ) throws ImageDataException - { - DbImage image = DbImage.getImageByUuid( uuid ); - if ( image == null ) - throw new ImageDataException( ImageDataError.UNKNOWN_IMAGE, "UUID '" + uuid + "' does not map to a known image." ); - // server was downloading another image and now gets a new connection for this new download - String token = RandomString.generate( 50, false ); - ConnectionHandler.addDownload( token, image ); - return new DownloadData( token, Globals.getSslSocketPort(), null ); // TODO: Return crc list - } - - /** - * Go though list of active uploading images and remove - * those that are finished. - */ - public static void removeFinishedUploads() - { - - for ( Iterator<UploadingImage> it = uploadingImages.values().iterator(); it.hasNext(); ) { - UploadingImage image = it.next(); - if ( image.allBlocksValid() ) { - synchronized ( imagesToCheck ) { - imagesToCheck.remove( image.getUuid() ); - image.updateMissingBlocks( null ); - } - it.remove(); - } - } - } - - public static List<UploadingImage> getImagesToCheck() - { - synchronized ( imagesToCheck ) { - if ( imagesToCheck.isEmpty() ) - return null; - List<UploadingImage> result = new ArrayList<>( imagesToCheck.size() ); - for ( String uuid : imagesToCheck ) { - result.add( uploadingImages.get( uuid ) ); - } - return result; - } - } - - public static List<Integer> getRequestedBlocks( String token ) - { - // for the downloader - // TODO - return null; - } - - /** - * Generates the filePath of an image. - * And creates the folder if wanted. - * The crc file is found under filePath + ".crc" - * - * @param imageData The data of the image - * @return The filePath of the given image - */ - public static String generateFilepathOfImage( ImageData imageData ) - { - return generateFilePathOfImage( imageData.uuid, imageData.title, imageData.revision ); - } - - public static String generateFilePathOfImage( String uuid, String imageName, int imageVersion ) - { - String result = Util.sanitizeFileName( uuid ) + "/"; - File dir = new File( Globals.getImageDir() + "/" + result ); - if ( !dir.exists() ) { - dir.mkdirs(); - } - result += imageName + "-rev" + String.valueOf( imageVersion ); - return result; - } - - public static String generateFilepathOfCrcFile( ImageData imageData ) - { - return generateFilepathOfImage( imageData ) + ".crc"; - } - - public static String generateFilepathOfCrcFile( String uuid, String imageName, int imageVersion ) - { - return generateFilePathOfImage( uuid, imageName, imageVersion ) + ".crc"; - } - -} diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/UploadingImage.java b/src/main/java/org/openslx/imagemaster/serverconnection/UploadingImage.java deleted file mode 100644 index 46e6c91..0000000 --- a/src/main/java/org/openslx/imagemaster/serverconnection/UploadingImage.java +++ /dev/null @@ -1,243 +0,0 @@ -package org.openslx.imagemaster.serverconnection; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.apache.log4j.Logger; -import org.openslx.imagemaster.Globals; -import org.openslx.imagemaster.crcchecker.CrcFile; -import org.openslx.imagemaster.crcchecker.ImageFile; -import org.openslx.imagemaster.db.DbImage; - -/** - * Helper class for ImageProcessor and ConnectionHandler to save some infos about the images in the - * process list. - */ -public class UploadingImage -{ - - public static final Logger log = Logger.getLogger( UploadingImage.class ); - - /** - * The status list of the blocks. - * x = 0 block is missing - * x = 200 block arrived and is valid - * x > 0 block is invalid and was transmitted x times (needs request) - * x < 0 block is invalid and was transmitted x times (needs check) - */ - private final int[] blockStatus; - /** - * Remember last position in blockStatus array that was returned, so we don't always - * iterate from the beginning. - */ - private int lastStatusPos = 0; - - public static final int VALID = 200; - public static final int MISSING = 0; - - private DbImage dbImage = null; // the DB representation of this image - /** - * Class for accessing the file (read blocks from it) - */ - private ImageFile imageFile = null; - private CrcFile crcFile = null; - - protected UploadingImage( String uuid ) - { - this.dbImage = DbImage.getImageByUuid( uuid ); - if ( this.dbImage == null ) - throw new RuntimeException( "Unknown image " + uuid + " on UploadingImage creation" ); - this.blockStatus = this.dbImage.blockStatus; - } - - protected void setValid( int index ) - { - synchronized ( blockStatus ) { - blockStatus[index] = VALID; - } - } - - protected void updateDb() - { - List<Integer> missingBlocks = new ArrayList<>(); - synchronized ( blockStatus ) { - for ( int block = 0; block < blockStatus.length; block++ ) { - if ( blockStatus[block] != VALID ) { - missingBlocks.add( block ); - } - } - } - dbImage.updateMissingBlocks( missingBlocks ); - } - - protected void setMissing( int index ) - { - synchronized ( blockStatus ) { - blockStatus[index] = MISSING; - } - } - - protected void setNeedsRequest( int index ) - { - synchronized ( blockStatus ) { - blockStatus[index] = Math.abs( blockStatus[index] ); // switch to positive value if needed - } - } - - protected void setNeedsCheck( int index ) - { - synchronized ( blockStatus ) { - if ( crcFile == null ) { - blockStatus[index] = VALID; - } else { - blockStatus[index] = -Math.abs( blockStatus[index] ); // switch to negative value if needed - } - } - } - - protected void increaseTransmittedTimes( int index ) - { - synchronized ( blockStatus ) { - if ( blockStatus[index] == VALID ) - return; - blockStatus[index] += ( blockStatus[index] <= MISSING ) ? -1 : 1; // increase in both directions - } - } - - protected int getTimesTransmitted( int index ) - { - synchronized ( blockStatus ) { - return Math.abs( blockStatus[index] ); - } - } - - protected boolean needsRequest( int index ) - { - synchronized ( blockStatus ) { - return ( ( blockStatus[index] >= MISSING ) && ( blockStatus[index] != VALID ) ); - } - } - - protected boolean needsCheck( int index ) - { - synchronized ( blockStatus ) { - return ( blockStatus[index] < MISSING ); - } - } - - protected int getNumberOfBlocks() - { - return blockStatus.length; - } - - protected int getNextMissingBlock() - { - synchronized ( blockStatus ) { - for ( int i = 0; i < blockStatus.length; i++ ) { - int index = ( i + lastStatusPos ) % blockStatus.length; - if ( blockStatus[index] == MISSING ) - return lastStatusPos = index; - } - for ( int index = 0; index < blockStatus.length; index++ ) { - if ( blockStatus[index] > MISSING && blockStatus[index] < VALID ) - return lastStatusPos = index; - } - for ( int index = 0; index < blockStatus.length; index++ ) { - if ( blockStatus[index] < MISSING ) - return lastStatusPos = index; - } - } - return -1; - } - - /* - protected long getTimestamp() - { - return this.timestamp; - } - */ - - protected ImageFile getImageFile() - { - if ( imageFile == null ) { - imageFile = new ImageFile( dbImage.getAbsolutePath(), Globals.blockSize ); - } - return imageFile; - } - - protected CrcFile getCrcFile() - { - if ( crcFile == null ) { - try { - crcFile = new CrcFile( dbImage.getAbsolutePath() + ".crc" ); - } catch ( IOException e ) { - // Not found... return null - } - } - return crcFile; - } - - protected void setCrcFile( CrcFile crcFile ) - { - if ( crcFile == null ) - return; - if ( getCrcFile() == null && crcFile.isValid() ) { - this.crcFile = crcFile; - crcFile.writeCrcFile( dbImage.getAbsolutePath() + ".crc" ); - } - } - - public int getAmountOfBlocksNeedingRequest() - { - if ( blockStatus == null ) - return 0; - int result = 0; - for ( int i = 0; i < blockStatus.length; i++ ) { - if ( needsRequest( i ) ) - result++; - } - return result; - } - - public boolean allBlocksValid() - { - if ( blockStatus == null ) - return false; - synchronized ( blockStatus ) { - for ( int i : blockStatus ) { - if ( i != 200 ) - return false; - } - } - return true; - } - - @Override - public String toString() - { - return "UUID: " + dbImage.uuid + ", filename " + dbImage.relativePath + "\nmissing blocks " + getAmountOfBlocksNeedingRequest() + - ", number of blocks " + getNumberOfBlocks(); - - } - - public String getAbsolutePath() - { - return dbImage.getAbsolutePath(); - } - - public long getFileSize() - { - return dbImage.fileSize; - } - - public String getUuid() - { - return dbImage.uuid; - } - - public void updateMissingBlocks( List<Integer> missingBlocks ) - { - dbImage.updateMissingBlocks( missingBlocks ); - } -} |