use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.
the class UploadInterruptedTest method testUnreliableUpload_Test4_1_FailsAtSecondMultiChunkUpload.
@Test
public void testUnreliableUpload_Test4_1_FailsAtSecondMultiChunkUpload() throws Exception {
/*
* This test fails when trying to upload the second multichunk, 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)
* 4. upload(multichunk-2, temp-2) <<< FAILS HERE
* 5. upload(database-123, temp-3) 6. move(temp-1, multichunks/multichunk-1)
* 7. move(temp-2, multichunks/multichunk-2)
* 8. move(temp-3, databases/database-123)
*/
// Setup
UnreliableLocalTransferSettings testConnection = TestConfigUtil.createTestUnreliableLocalConnection(Arrays.asList(new String[] { "rel=[456].+upload.+multichunk" }));
TestClient clientA = new TestClient("A", testConnection);
// << larger than one multichunk!
clientA.createNewFile("A-original", 5 * 1024 * 1024);
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);
File[] tempFiles = new File(testConnection.getPath() + "/temporary/").listFiles();
assertEquals(1, tempFiles.length);
// 1 MC with 1 MB, 1 with 4 MB; must be larger than 500 KB
assertTrue(tempFiles[0].length() > 500 * 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. Second try succeeds and must clean up the transactions
clientA.up();
assertEquals(1, new File(testConnection.getPath() + "/databases/").listFiles().length);
assertEquals(2, 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();
}
use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.
the class TransactionAwareFeatureTransferManager method addAndFilterFilesInTransaction.
/**
* Returns a list of remote files, excluding the files in transactions.
* The method is used to hide unfinished transactions from other clients.
*/
protected <T extends RemoteFile> Map<String, T> addAndFilterFilesInTransaction(Class<T> remoteFileClass, Map<String, T> remoteFiles) throws StorageException {
Map<String, T> filteredFiles = new HashMap<String, T>();
Set<TransactionTO> transactions = new HashSet<TransactionTO>();
Set<RemoteFile> dummyDeletedFiles = new HashSet<RemoteFile>();
Set<RemoteFile> filesToIgnore = new HashSet<RemoteFile>();
// Ignore files currently listed in a transaction,
// unless we are listing transaction files
boolean ignoreFilesInTransactions = !remoteFileClass.equals(TransactionRemoteFile.class);
if (ignoreFilesInTransactions) {
transactions = retrieveRemoteTransactions().keySet();
filesToIgnore = getFilesInTransactions(transactions);
dummyDeletedFiles = getDummyDeletedFiles(transactions);
}
for (RemoteFile deletedFile : dummyDeletedFiles) {
if (deletedFile.getClass().equals(remoteFileClass)) {
T concreteDeletedFile = remoteFileClass.cast(deletedFile);
filteredFiles.put(concreteDeletedFile.getName(), concreteDeletedFile);
}
}
for (String fileName : remoteFiles.keySet()) {
if (!filesToIgnore.contains(remoteFiles.get(fileName))) {
filteredFiles.put(fileName, remoteFiles.get(fileName));
}
}
return filteredFiles;
}
use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.
the class UpOperation method attemptResumeTransactions.
private Collection<RemoteTransaction> attemptResumeTransactions(Collection<Long> versions) {
try {
Collection<RemoteTransaction> remoteTransactions = new ArrayList<>();
for (Long version : versions) {
File transactionFile = config.getTransactionFile(version);
// If a single transaction file is missing, we should restart
if (!transactionFile.exists()) {
return null;
}
TransactionTO transactionTO = TransactionTO.load(null, transactionFile);
// Verify if all files needed are in cache.
for (ActionTO action : transactionTO.getActions()) {
if (action.getType() == ActionType.UPLOAD) {
if (action.getStatus() == ActionStatus.UNSTARTED) {
if (!action.getLocalTempLocation().exists()) {
// Unstarted upload has no cached local copy, abort
return null;
}
}
}
}
remoteTransactions.add(new RemoteTransaction(config, transferManager, transactionTO));
}
return remoteTransactions;
} catch (Exception e) {
logger.log(Level.WARNING, "Invalid transaction file. Cannot resume!");
return null;
}
}
use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.
the class TransactionAwareFeatureTransferManager method downloadDeletedTempFileInTransaction.
/**
* Downloads all transaction files and looks for the corresponding temporary file
* for the given remote file. If there is a temporary file, the file is downloaded
* instead of the original file.
*
* <p>This method is <b>expensive</b>, but it is only called by {@link #download(RemoteFile, File) download()}
* if a file does not exist.
*/
private void downloadDeletedTempFileInTransaction(RemoteFile remoteFile, File localFile) throws StorageException {
logger.log(Level.INFO, "File {0} not found, checking if it is being deleted ...", remoteFile.getName());
Set<TransactionTO> transactions = retrieveRemoteTransactions().keySet();
TempRemoteFile tempRemoteFile = null;
// Find file: If the file is being deleted and the name matches, download temporary file instead.
for (TransactionTO transaction : transactions) {
for (ActionTO action : transaction.getActions()) {
if (action.getType().equals(ActionType.DELETE) && action.getRemoteFile().equals(remoteFile)) {
tempRemoteFile = action.getTempRemoteFile();
break;
}
}
}
// Download file, or throw exception
if (tempRemoteFile != null) {
logger.log(Level.INFO, "-> File {0} in process of being deleted; downloading corresponding temp. file {1} ...", new Object[] { remoteFile.getName(), tempRemoteFile.getName() });
underlyingTransferManager.download(tempRemoteFile, localFile);
} else {
logger.log(Level.WARNING, "-> File {0} does not exist and is not in any transaction. Throwing exception.", remoteFile.getName());
throw new StorageFileNotFoundException("File " + remoteFile.getName() + " does not exist and is not in any transaction");
}
}
use of org.syncany.plugins.transfer.to.TransactionTO in project syncany by syncany.
the class TransactionAwareFeatureTransferManager method removeUnreferencedTemporaryFiles.
/**
* Removes temporary files on the offsite storage that are not listed in any
* of the {@link TransactionRemoteFile}s available remotely.
*
* <p>Temporary files might be left over from unfinished transactions.
*/
public void removeUnreferencedTemporaryFiles() throws StorageException {
// Retrieve all transactions
Map<TransactionTO, TransactionRemoteFile> transactions = retrieveRemoteTransactions();
Collection<TempRemoteFile> tempRemoteFiles = list(TempRemoteFile.class).values();
// Find all remoteFiles that are referenced in a transaction
Set<TempRemoteFile> tempRemoteFilesInTransactions = new HashSet<TempRemoteFile>();
for (TransactionTO transaction : transactions.keySet()) {
for (ActionTO action : transaction.getActions()) {
tempRemoteFilesInTransactions.add(action.getTempRemoteFile());
}
}
// Consider just those files that are not referenced and delete them.
tempRemoteFiles.removeAll(tempRemoteFilesInTransactions);
for (TempRemoteFile unreferencedTempRemoteFile : tempRemoteFiles) {
logger.log(Level.INFO, "Unreferenced temporary file found. Deleting {0}", unreferencedTempRemoteFile);
underlyingTransferManager.delete(unreferencedTempRemoteFile);
}
}
Aggregations