Search in sources :

Example 6 with TransactionTO

use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.

the class TransactionAwareFeatureTransferManager method cleanTransactions.

/**
	 * Checks if any transactions of the local machine were not completed and performs
	 * a rollback if any transactions were found. The rollback itself is performed in
	 * a transaction.
	 *
	 * <p>The method uses {@link #retrieveRemoteTransactions()} to download all transaction
	 * files and then rolls back the local machines's transactions:
	 *
	 * <ul>
	 *  <li>Files in the transaction marked "UPLOAD" are deleted.</li>
	 *  <li>Files in the transaction marked "DELETE" are moved back to their original place.</li>
	 * </ul>
	 *
	 * @throws BlockingTransfersException if we cannot proceed (Deleting transaction by another client exists).
	 */
public void cleanTransactions() throws StorageException, BlockingTransfersException {
    Objects.requireNonNull(config, "Cannot clean transactions if config is null.");
    Map<TransactionTO, TransactionRemoteFile> transactions = retrieveRemoteTransactions();
    boolean noBlockingTransactionsExist = true;
    for (TransactionTO potentiallyCancelledTransaction : transactions.keySet()) {
        boolean isCancelledOwnTransaction = potentiallyCancelledTransaction.getMachineName().equals(config.getMachineName());
        // If this transaction is from our machine, delete all permanent or temporary files in this transaction.
        if (isCancelledOwnTransaction) {
            rollbackSingleTransaction(potentiallyCancelledTransaction, transactions.get(potentiallyCancelledTransaction));
        } else if (noBlockingTransactionsExist) {
            // Only check if we have not yet found deleting transactions by others
            for (ActionTO action : potentiallyCancelledTransaction.getActions()) {
                if (action.getType().equals(ActionType.DELETE)) {
                    noBlockingTransactionsExist = false;
                }
            }
        }
    }
    logger.log(Level.INFO, "Done rolling back previous transactions.");
    if (!noBlockingTransactionsExist) {
        throw new BlockingTransfersException();
    }
}
Also used : ActionTO(org.syncany.plugins.transfer.to.ActionTO) TransactionRemoteFile(org.syncany.plugins.transfer.files.TransactionRemoteFile) BlockingTransfersException(org.syncany.operations.up.BlockingTransfersException) TransactionTO(org.syncany.plugins.transfer.to.TransactionTO)

Example 7 with TransactionTO

use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.

the class TransactionAwareFeatureTransferManager method getTransactionsByClient.

/**
	 * This function returns a list of all remote transaction files that belong to the client. If blocking transactions exist,
	 * this methods returns null, because we are not allowed to proceed.
	 */
public List<TransactionRemoteFile> getTransactionsByClient(String client) throws StorageException {
    Objects.requireNonNull(config, "Cannot get transactions if config is null.");
    Map<TransactionTO, TransactionRemoteFile> transactions = retrieveRemoteTransactions();
    List<TransactionRemoteFile> transactionsByClient = new ArrayList<TransactionRemoteFile>();
    for (TransactionTO potentiallyResumableTransaction : transactions.keySet()) {
        boolean isCancelledOwnTransaction = potentiallyResumableTransaction.getMachineName().equals(config.getMachineName());
        if (isCancelledOwnTransaction) {
            transactionsByClient.add(transactions.get(potentiallyResumableTransaction));
        } else {
            // Check for blocking transactions
            for (ActionTO action : potentiallyResumableTransaction.getActions()) {
                if (action.getType().equals(ActionType.DELETE)) {
                    return null;
                }
            }
        }
    }
    return transactionsByClient;
}
Also used : ActionTO(org.syncany.plugins.transfer.to.ActionTO) TransactionRemoteFile(org.syncany.plugins.transfer.files.TransactionRemoteFile) ArrayList(java.util.ArrayList) TransactionTO(org.syncany.plugins.transfer.to.TransactionTO)

Example 8 with TransactionTO

use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.

the class TransactionAwareFeatureTransferManager method retrieveRemoteTransactions.

private Map<TransactionTO, TransactionRemoteFile> retrieveRemoteTransactions() throws StorageException {
    Map<String, TransactionRemoteFile> transactionFiles = list(TransactionRemoteFile.class);
    Map<TransactionTO, TransactionRemoteFile> transactions = new HashMap<TransactionTO, TransactionRemoteFile>();
    for (TransactionRemoteFile transaction : transactionFiles.values()) {
        try {
            File transactionFile = createTempFile("transaction");
            try {
                // Download transaction file
                download(transaction, transactionFile);
            } catch (StorageFileNotFoundException e) {
                // This happens if the file is deleted between listing and downloading. It is now final, so we skip it.
                logger.log(Level.INFO, "Could not find transaction file: " + transaction);
                continue;
            }
            Transformer transformer = config == null ? null : config.getTransformer();
            TransactionTO transactionTO = TransactionTO.load(transformer, transactionFile);
            // Extract final locations
            transactions.put(transactionTO, transaction);
            transactionFile.delete();
        } catch (Exception e) {
            throw new StorageException("Failed to read transactionFile", e);
        }
    }
    return transactions;
}
Also used : StorageFileNotFoundException(org.syncany.plugins.transfer.StorageFileNotFoundException) TransactionRemoteFile(org.syncany.plugins.transfer.files.TransactionRemoteFile) Transformer(org.syncany.chunk.Transformer) HashMap(java.util.HashMap) RemoteFile(org.syncany.plugins.transfer.files.RemoteFile) TempRemoteFile(org.syncany.plugins.transfer.files.TempRemoteFile) TransactionRemoteFile(org.syncany.plugins.transfer.files.TransactionRemoteFile) File(java.io.File) StorageException(org.syncany.plugins.transfer.StorageException) StorageException(org.syncany.plugins.transfer.StorageException) BlockingTransfersException(org.syncany.operations.up.BlockingTransfersException) IOException(java.io.IOException) StorageMoveException(org.syncany.plugins.transfer.StorageMoveException) StorageFileNotFoundException(org.syncany.plugins.transfer.StorageFileNotFoundException) TransactionTO(org.syncany.plugins.transfer.to.TransactionTO)

Example 9 with TransactionTO

use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.

the class UploadInterruptedTest method testUnreliableUpload_Test4_2_FailsAtTXCommitDuring2ndMultiChunkMove.

@Test
public void testUnreliableUpload_Test4_2_FailsAtTXCommitDuring2ndMultiChunkMove() throws Exception {
    /*
		 * First run "Client A": This test fails when trying to execute the TX.commit() when moving the second multichunk. So the first multichunk was
		 * moved successfully.
		 *
		 * Double check by "Client B": Client B should not see this multichunk on TM.list()
		 *
		 * Second run "Client A": The second up() from Client A should revert the transaction. To verify this, we let the second run fail at the
		 * transaction file upload
		 *
		 * 1. upload(action-up-987, actions/action-up-987)
		 * 2. upload(transaction-123, transactions/transaction-123) <<< FAILS HERE (second run)
		 * 3. upload(multichunk-1, temp-1)
		 * 4. upload(multichunk-2, temp-2)
		 * 5. upload(database-123, temp-3)
		 * 6. move(temp-1, multichunks/multichunk-1)
		 * 7. move(temp-2, multichunks/multichunk-2) <<< FAILS HERE (first run)
		 * 8. move(temp-3, databases/database-123)
		 */
    // Setup
    UnreliableLocalTransferSettings testConnection = TestConfigUtil.createTestUnreliableLocalConnection(Arrays.asList(new String[] { "rel=[234].+move.+multichunk", "rel=(7|8|9).+upload.+transaction" }));
    TestClient clientA = new TestClient("A", testConnection);
    // << larger than one multichunk!
    clientA.createNewFile("A-original", 5 * 1024 * 1024);
    boolean firstUpFailed = false;
    try {
        clientA.up();
    } catch (StorageException e) {
        firstUpFailed = true;
        logger.log(Level.INFO, e.getMessage());
    }
    assertTrue(firstUpFailed);
    assertEquals(0, new File(testConnection.getPath() + "/databases/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/multichunks/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/actions/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/transactions/").listFiles().length);
    File[] tempFiles = new File(testConnection.getPath() + "/temporary/").listFiles();
    assertEquals(2, tempFiles.length);
    // The second multichunk should be >500 KB
    assertTrue(tempFiles[0].length() > 500 * 1024 || tempFiles[1].length() > 500 * 1024);
    // The database file should be <100 KB
    assertTrue(tempFiles[0].length() < 100 * 1024 || tempFiles[1].length() < 100 * 1024);
    File transactionFile = new File(testConnection.getPath() + "/transactions/").listFiles()[0];
    TransactionTO transactionTO = new Persister().read(TransactionTO.class, transactionFile);
    assertEquals(3, transactionTO.getActions().size());
    assertTrue(transactionTO.getActions().get(0).getRemoteFile().getName().contains("multichunk-"));
    assertTrue(transactionTO.getActions().get(1).getRemoteFile().getName().contains("multichunk-"));
    assertTrue(transactionTO.getActions().get(2).getRemoteFile().getName().contains("database-"));
    // 2. Double check if list() does not return the multichunk
    TransferManager transferManager = TransferManagerFactory.build(clientA.getConfig()).withFeature(TransactionAware.class).asDefault();
    Map<String, MultichunkRemoteFile> multiChunkList = transferManager.list(MultichunkRemoteFile.class);
    assertEquals(0, multiChunkList.size());
    // 3. Second try fails in the beginning, to see if cleanTransactions was successful
    boolean secondUpFailed = false;
    // Do not resume, since we want to clean transactions.
    UpOperationOptions upOptions = new UpOperationOptions();
    upOptions.setResume(false);
    try {
        clientA.up(upOptions);
    } catch (StorageException e) {
        secondUpFailed = true;
        logger.log(Level.INFO, e.getMessage());
    }
    assertTrue(secondUpFailed);
    assertEquals(0, new File(testConnection.getPath() + "/databases/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/multichunks/").listFiles().length);
    // Shouldn't this be 1
    assertEquals(2, new File(testConnection.getPath() + "/actions/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/transactions/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/").listFiles(new FilenameFilter() {

        public boolean accept(File dir, String name) {
            return name.contains("temp-");
        }
    }).length);
    // Tear down
    clientA.deleteTestData();
}
Also used : TransferManager(org.syncany.plugins.transfer.TransferManager) UpOperationOptions(org.syncany.operations.up.UpOperationOptions) TransactionTO(org.syncany.plugins.transfer.to.TransactionTO) FilenameFilter(java.io.FilenameFilter) MultichunkRemoteFile(org.syncany.plugins.transfer.files.MultichunkRemoteFile) TransactionAware(org.syncany.plugins.transfer.features.TransactionAware) UnreliableLocalTransferSettings(org.syncany.plugins.unreliable_local.UnreliableLocalTransferSettings) TestClient(org.syncany.tests.util.TestClient) Persister(org.simpleframework.xml.core.Persister) StorageException(org.syncany.plugins.transfer.StorageException) File(java.io.File) MultichunkRemoteFile(org.syncany.plugins.transfer.files.MultichunkRemoteFile) Test(org.junit.Test)

Example 10 with TransactionTO

use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.

the class UploadInterruptedTest method testUnreliableUpload_Test3_FailsAtDatabaseFile.

@Test
public void testUnreliableUpload_Test3_FailsAtDatabaseFile() throws Exception {
    /*
		 * This test fails when trying to upload the first database file, but succeeds on retry
		 *
		 * 1. upload(action-up-987, actions/action-up-987)
		 * 2. upload(transaction-123, transactions/transaction-123)
		 * 3. upload(multichunk-1, temp-1)
		 * 5. upload(database-123, temp-2) <<< FAILS HERE
		 * 6. move(temp-1, multichunks/multichunk-1)
		 * 8. move(temp-2, databases/database-123)
		 */
    // Setup
    UnreliableLocalTransferSettings testConnection = TestConfigUtil.createTestUnreliableLocalConnection(Arrays.asList(new String[] { "rel=[456].+upload.+database" }));
    TestClient clientA = new TestClient("A", testConnection);
    // 1. First upload fails
    clientA.createNewFile("A-original", 10);
    boolean upFailed = false;
    try {
        clientA.up();
    } catch (StorageException e) {
        upFailed = true;
        logger.log(Level.INFO, e.getMessage());
    }
    assertTrue(upFailed);
    assertEquals(0, new File(testConnection.getPath() + "/databases/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/multichunks/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/actions/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/transactions/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/temporary/").listFiles().length);
    File transactionFile = new File(testConnection.getPath() + "/transactions/").listFiles()[0];
    TransactionTO transactionTO = new Persister().read(TransactionTO.class, transactionFile);
    assertEquals(2, transactionTO.getActions().size());
    assertTrue(transactionTO.getActions().get(0).getRemoteFile().getName().contains("multichunk-"));
    assertTrue(transactionTO.getActions().get(1).getRemoteFile().getName().contains("database-"));
    // 2. Second try succeeds and must clean up the transactions
    clientA.up();
    assertEquals(1, new File(testConnection.getPath() + "/databases/").listFiles().length);
    assertEquals(1, new File(testConnection.getPath() + "/multichunks/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/actions/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/transactions/").listFiles().length);
    assertEquals(0, new File(testConnection.getPath() + "/temporary/").listFiles().length);
    // Tear down
    clientA.deleteTestData();
}
Also used : UnreliableLocalTransferSettings(org.syncany.plugins.unreliable_local.UnreliableLocalTransferSettings) TestClient(org.syncany.tests.util.TestClient) Persister(org.simpleframework.xml.core.Persister) StorageException(org.syncany.plugins.transfer.StorageException) File(java.io.File) MultichunkRemoteFile(org.syncany.plugins.transfer.files.MultichunkRemoteFile) TransactionTO(org.syncany.plugins.transfer.to.TransactionTO) Test(org.junit.Test)

Aggregations

TransactionTO (org.syncany.plugins.transfer.to.TransactionTO)12 File (java.io.File)7 StorageException (org.syncany.plugins.transfer.StorageException)7 MultichunkRemoteFile (org.syncany.plugins.transfer.files.MultichunkRemoteFile)6 TransactionRemoteFile (org.syncany.plugins.transfer.files.TransactionRemoteFile)6 Test (org.junit.Test)5 Persister (org.simpleframework.xml.core.Persister)5 ActionTO (org.syncany.plugins.transfer.to.ActionTO)5 UnreliableLocalTransferSettings (org.syncany.plugins.unreliable_local.UnreliableLocalTransferSettings)5 TestClient (org.syncany.tests.util.TestClient)5 TempRemoteFile (org.syncany.plugins.transfer.files.TempRemoteFile)4 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 BlockingTransfersException (org.syncany.operations.up.BlockingTransfersException)2 UpOperationOptions (org.syncany.operations.up.UpOperationOptions)2 StorageFileNotFoundException (org.syncany.plugins.transfer.StorageFileNotFoundException)2 TransferManager (org.syncany.plugins.transfer.TransferManager)2 TransactionAware (org.syncany.plugins.transfer.features.TransactionAware)2