diff options
author | Nils Schwabe | 2014-07-10 16:08:36 +0200 |
---|---|---|
committer | Nils Schwabe | 2014-07-10 16:08:36 +0200 |
commit | c89abbfa830876b7298eb96896a642bc74589651 (patch) | |
tree | ee3b0707be612d9147d23632713c61c52c6d27be /src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java | |
parent | Remove unintentionally added f3 docs (diff) | |
download | masterserver-c89abbfa830876b7298eb96896a642bc74589651.tar.gz masterserver-c89abbfa830876b7298eb96896a642bc74589651.tar.xz masterserver-c89abbfa830876b7298eb96896a642bc74589651.zip |
Add some better thread synchonization
Restructure some classes
Fix small connection issues
Diffstat (limited to 'src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java')
-rw-r--r-- | src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java | 150 |
1 files changed, 77 insertions, 73 deletions
diff --git a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java b/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java index ec043fa..8306280 100644 --- a/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java +++ b/src/main/java/org/openslx/imagemaster/serverconnection/ImageProcessor.java @@ -2,10 +2,13 @@ package org.openslx.imagemaster.serverconnection; import java.io.IOException; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.log4j.Logger; import org.openslx.imagemaster.Globals; @@ -34,8 +37,8 @@ public class ImageProcessor * Key: imageUUID, * Value: uploadingImageInfos */ - private static HashMap<String, UploadingImageInfos> uploadingImages = new HashMap<>(); - + private static Map<String, UploadingImage> uploadingImages = new ConcurrentHashMap<>(); + /** * The UUIDs of the images that need to be checked by the crc checker. */ @@ -46,7 +49,7 @@ public class ImageProcessor * Key: serverSessionId * Value: downloadingClientInfos */ - private static HashMap<String, DownloadingClientInfos> downloadingClients = new HashMap<>(); + private static HashMap<String, DownloadingClient> downloadingClients = new HashMap<>(); /** * Checks if this image is already uploading and returns a new list with missing blocks if so. @@ -56,63 +59,67 @@ public class ImageProcessor * @param imageData The data of the image * @return */ - public static UploadInfos getUploadInfos( String serverSessionId, ImageData imageData, List<Integer> crcSums) + public static UploadInfos getUploadInfos( String serverSessionId, ImageData imageData, List<Integer> crcSums ) { // check image data // TODO: do security checks - String uuid = imageData.uuid; + log.debug( "Trying to answer request:" + serverSessionId + ", " + imageData + ", " + crcSums ); - // check if image is already uploading TODO: what if two clients call this at the same time? -> Good question.. (Thought about not sending the last requested. But then the upload will never finish...) - if ( uploadingImages.containsKey( uuid ) ) { - List<Integer> missing = getMissingBlocks( uuid, AMOUNT ); - if ( missing.isEmpty() ) { - uploadDone( uuid ); - return new UploadInfos( null, 0, missing ); - } - uploadingImages.get( uuid ).addNotCheckedBlocks( missing ); - UploadingImageInfos image = uploadingImages.get( uuid ); - return new UploadInfos( image.getToken(), image.getPort(), missing ); - } + String uuid = imageData.uuid; + String token; + String filepath; + String crcPath; + + List<Integer> allBlocks; + UploadingImage image; - // insert new image and start listener synchronized ( uploadingImages ) { - String crcPath = Globals.getImageDir() + "/" + uuid + ".crc"; - try { - CRCFile crcFile = new CRCFile( crcSums, crcPath); - } catch (IOException e) { - return null; // TODO: what to do if we can not write the crc file to disk? + // check if image is already uploading TODO: what if two clients call this at the same time? -> Good question.. (Thought about not sending the last requested. But then the upload will never finish...) + if ( ( image = uploadingImages.get( uuid ) ) != null ) { + log.debug( "Image is already uploading" ); + List<Integer> missing = getNMissingBlocks( image, AMOUNT ); + if ( missing.isEmpty() ) { + uploadDone( uuid ); + return new UploadInfos( null, 0, missing ); + } + return new UploadInfos( image.getToken(), Globals.getSslSocketPort(), missing ); } + + // insert new image + log.debug( "Inserting new download" ); + filepath = Globals.getImageDir() + "/" + uuid + ".vmdk"; + token = RandomString.generate( 100, false ); + crcPath = Globals.getImageDir() + "/" + uuid + ".crc"; int nBlocks = (int)Math.ceil( imageData.fileSize / Globals.blockSize ); - List<Integer> allBlocks = new LinkedList<>(); - for ( int i = 0; i < nBlocks; i++ ) { // fill empty list with all block numbers + allBlocks = new ArrayList<>( nBlocks ); + for ( int i = nBlocks - 1; i >= 0; i-- ) { // fill empty list with all block numbers allBlocks.add( i ); } - String token = RandomString.generate( 100, false ); - String filepath = Globals.getImageDir() + "/" + uuid + ".vmdk"; - int port = ConnectionHandler.addConnection( token, filepath, ConnectionData.UPLOADING ); - // TODO: proper synchronization, interface is multi threaded. - // should synchronize operations on the map (use concurrent map) and then synchronize on the uploading image - // when handing the missing blocks etc... - uploadingImages.put( uuid, new UploadingImageInfos( token, port, allBlocks, serverSessionId, new Timestamp( System.currentTimeMillis() ), uuid, filepath, crcPath ) ); - DbImage.insert( imageData, System.currentTimeMillis(), token, allBlocks, serverSessionId, filepath ); - imagesToCheck.add( uuid ); - - List<Integer> missing = getMissingBlocks( uuid, AMOUNT ); - if ( missing.isEmpty() ) { - // TODO: if this is empty, check if there are pending blocks and if so, request them again - uploadDone( uuid ); - } - uploadingImages.get( uuid ).addNotCheckedBlocks( missing ); - return new UploadInfos( token, port, missing ); + image = new UploadingImage( token, allBlocks, new Timestamp( System.currentTimeMillis() ), uuid, filepath, crcPath ); + uploadingImages.put( uuid, image ); } + + try { + new CRCFile( crcSums, crcPath); + } catch (IOException e) { + log.debug( "Could not create crc file" ); + return null; // TODO: what to do if we can not write the crc file to disk? Give object to crcscheduler? + } + + ConnectionHandler.addConnection( token, filepath, Connection.UPLOADING ).image = image; + DbImage.insert( imageData, System.currentTimeMillis(), token, allBlocks, serverSessionId, filepath ); + imagesToCheck.add( uuid ); + + log.debug( "Returning UploadInfos" ); + return new UploadInfos( token, Globals.getSslSocketPort(), getNMissingBlocks( image, AMOUNT ) ); } public static DownloadInfos getDownloadInfos( String serverSessionId, String uuid, List<Integer> requestedBlocks ) { // check if server is already downloading if ( downloadingClients.containsKey( serverSessionId ) ) { - DownloadingClientInfos client = downloadingClients.get( serverSessionId ); + DownloadingClient client = downloadingClients.get( serverSessionId ); // remove download if done if ( requestedBlocks.isEmpty() ) @@ -126,36 +133,36 @@ public class ImageProcessor // client was downloading this image // update the requested blocks client.requestBlocks( uuid, requestedBlocks ); - return new DownloadInfos( client.getToken( uuid ), client.getPort( uuid ) ); + return new DownloadInfos( client.getToken( uuid ), Globals.getSslSocketPort() ); } // server was downloading another image and now gets a new connection for this new download String token = RandomString.generate( 100, false ); String filepath = DbImage.getImageByUUID( uuid ).imagePath; - int port = ConnectionHandler.addConnection( token, filepath, ConnectionData.DOWNLOADING ); + ConnectionHandler.addConnection( token, filepath, Connection.DOWNLOADING ); - client.addDownload( uuid, port, requestedBlocks, token ); + client.addDownload( uuid, requestedBlocks, token ); downloadingClients.put( serverSessionId, client ); - return new DownloadInfos( token, port ); + return new DownloadInfos( token, Globals.getSslSocketPort() ); } // insert new client and start listener synchronized ( downloadingClients ) { - DownloadingClientInfos client = new DownloadingClientInfos(); + DownloadingClient client = new DownloadingClient(); String token = RandomString.generate( 100, false ); String filepath = DbImage.getImageByUUID( uuid ).imagePath; - int port = ConnectionHandler.addConnection( token, filepath, ConnectionData.DOWNLOADING ); + ConnectionHandler.addConnection( token, filepath, Connection.DOWNLOADING ); - client.addDownload( uuid, port, requestedBlocks, token ); + client.addDownload( uuid, requestedBlocks, token ); downloadingClients.put( serverSessionId, client ); - return new DownloadInfos( token, port ); + return new DownloadInfos( token, Globals.getSslSocketPort() ); } } private static void downloadDone( String serverSessionId, String uuid ) { synchronized ( downloadingClients ) { - DownloadingClientInfos client = downloadingClients.get( serverSessionId ); + DownloadingClient client = downloadingClients.get( serverSessionId ); client.removeDownload( uuid ); ConnectionHandler.removeConnection( client.getToken( uuid ) ); if ( !client.hasDownloads() ) { @@ -171,23 +178,18 @@ public class ImageProcessor * @param amount The amount of blocks that you want to get * @return The missing blocks */ - private static List<Integer> getMissingBlocks( String imageUUID, int amount ) + private static List<Integer> getNMissingBlocks( UploadingImage image, int amount ) { - UploadingImageInfos image = uploadingImages.get( imageUUID ); - List<Integer> list = image.getMissingBlocks(); - List<Integer> result = new LinkedList<>(); + int size = image.amountOfMissingBlocks(); + if ( amount > size ) + amount = size; - if ( amount > list.size() ) - amount = list.size(); + List<Integer> result = new ArrayList<>( amount ); - for ( int i = 0; i < amount; i++ ) { - result.add( list.get( i ) ); + for ( int i = 1; i <= amount; i++ ) { + result.add( image.removeMissingBlock( size - i ) ); } - - synchronized ( image ) { - image.addNotCheckedBlocks( result ); - } - + return result; } @@ -199,10 +201,11 @@ public class ImageProcessor */ private static void uploadDone( String uuid ) { - synchronized (imagesToCheck) { + synchronized ( imagesToCheck ) { imagesToCheck.remove( uuid ); } - UploadingImageInfos image; + + UploadingImage image; synchronized ( uploadingImages ) { image = uploadingImages.remove( uuid ); } @@ -211,18 +214,18 @@ public class ImageProcessor // remove the connection so that it can be used by a new client ConnectionHandler.removeConnection( image.getToken() ); } - - public static List<UploadingImageInfos> getImagesToCheck() + + public static List<UploadingImage> getImagesToCheck() { - List<UploadingImageInfos> result = new LinkedList<>(); + List<UploadingImage> result = new LinkedList<>(); Iterator<String> iter = imagesToCheck.iterator(); while ( iter.hasNext() ) { result.add( uploadingImages.get( iter.next() ) ); } - + return result; } - + /** * Checks pending uploads in database and adds them to process list again. */ @@ -231,8 +234,9 @@ public class ImageProcessor List<DbImage> list = DbImage.getUploadingImages(); for ( DbImage image : list ) { String token = image.token; - int port = ConnectionHandler.addConnection( token, image.imagePath, ConnectionData.UPLOADING ); - UploadingImageInfos infos = new UploadingImageInfos( token, port, image.missingBlocks, image.serverSessionId, image.timestamp, image.uuid, image.imagePath, Globals.getImageDir() + "/" + image.uuid + ".crc" ); + ConnectionHandler.addConnection( token, image.imagePath, Connection.UPLOADING ); + UploadingImage infos = new UploadingImage( token, image.missingBlocks, image.timestamp, + image.uuid, image.imagePath, Globals.getImageDir() + "/" + image.uuid + ".crc" ); uploadingImages.put( image.uuid, infos ); } log.info( "Added " + list.size() + " pending upload(s) to process list again." ); |