Search in sources :

Example 1 with DatabaseVersionHeader

use of org.syncany.database.DatabaseVersionHeader in project syncany by syncany.

the class DatabaseVersionDaoTest method testNonEmptyDatabaseVersionHeaders.

@Test
public void testNonEmptyDatabaseVersionHeaders() throws Exception {
    // Setup
    Config testConfig = TestConfigUtil.createTestLocalConfig();
    Connection databaseConnection = testConfig.createDatabaseConnection();
    // Run
    TestSqlUtil.runSqlFromResource(databaseConnection, "test.insert.set1.sql");
    ChunkSqlDao chunkDao = new ChunkSqlDao(databaseConnection);
    MultiChunkSqlDao multiChunkDao = new MultiChunkSqlDao(databaseConnection);
    FileVersionSqlDao fileVersionDao = new FileVersionSqlDao(databaseConnection);
    FileHistorySqlDao fileHistoryDao = new FileHistorySqlDao(databaseConnection, fileVersionDao);
    FileContentSqlDao fileContentDao = new FileContentSqlDao(databaseConnection);
    DatabaseVersionSqlDao databaseVersionDao = new DatabaseVersionSqlDao(databaseConnection, chunkDao, fileContentDao, fileVersionDao, fileHistoryDao, multiChunkDao);
    List<DatabaseVersionHeader> databaseVersionHeaders = databaseVersionDao.getNonEmptyDatabaseVersionHeaders();
    Collection<String> databaseVersionHeaderStrings = databaseVersionHeaders.stream().map(dbv -> dbv.toString()).collect(Collectors.toCollection(ArrayList::new));
    // Test
    assertNotNull(databaseVersionHeaders);
    assertEquals(6, databaseVersionHeaders.size());
    assertTrue(CollectionUtil.containsExactly(Arrays.asList(new String[] { "A/(A1)/T=1388589969000", "A/(A2)/T=1388676369000", "A/(A3)/T=1388762769000", "A/(A4)/T=1388849289000", "A/(A5)/T=1388935689000", "B/(B1)/T=1388849289000" }), databaseVersionHeaderStrings));
    TestSqlUtil.runSql("DELETE FROM fileversion WHERE databaseversion_id = 0", databaseConnection);
    // Tear down
    databaseConnection.close();
    TestConfigUtil.deleteTestLocalConfigAndData(testConfig);
}
Also used : ChunkSqlDao(org.syncany.database.dao.ChunkSqlDao) Arrays(java.util.Arrays) ChunkChecksum(org.syncany.database.ChunkEntry.ChunkChecksum) FileHistorySqlDao(org.syncany.database.dao.FileHistorySqlDao) Connection(java.sql.Connection) Date(java.util.Date) TestDatabaseUtil(org.syncany.tests.util.TestDatabaseUtil) MultiChunkId(org.syncany.database.MultiChunkEntry.MultiChunkId) ChunkEntry(org.syncany.database.ChunkEntry) ArrayList(java.util.ArrayList) FileType(org.syncany.database.FileVersion.FileType) TestConfigUtil(org.syncany.tests.util.TestConfigUtil) FileChecksum(org.syncany.database.FileContent.FileChecksum) MultiChunkSqlDao(org.syncany.database.dao.MultiChunkSqlDao) CollectionUtil(org.syncany.util.CollectionUtil) Map(java.util.Map) FileVersion(org.syncany.database.FileVersion) FileStatus(org.syncany.database.FileVersion.FileStatus) TestSqlUtil(org.syncany.tests.util.TestSqlUtil) DatabaseVersion(org.syncany.database.DatabaseVersion) DatabaseBranch(org.syncany.operations.down.DatabaseBranch) MultiChunkEntry(org.syncany.database.MultiChunkEntry) Iterator(java.util.Iterator) TestCollectionUtil(org.syncany.tests.util.TestCollectionUtil) Assert.assertNotNull(org.junit.Assert.assertNotNull) Collection(java.util.Collection) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) Collectors(java.util.stream.Collectors) FileContentSqlDao(org.syncany.database.dao.FileContentSqlDao) FileVersionSqlDao(org.syncany.database.dao.FileVersionSqlDao) List(java.util.List) Config(org.syncany.config.Config) Assert.assertNull(org.junit.Assert.assertNull) FileHistoryId(org.syncany.database.PartialFileHistory.FileHistoryId) DatabaseVersionSqlDao(org.syncany.database.dao.DatabaseVersionSqlDao) PartialFileHistory(org.syncany.database.PartialFileHistory) FileContent(org.syncany.database.FileContent) Assert.assertEquals(org.junit.Assert.assertEquals) DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader) Config(org.syncany.config.Config) Connection(java.sql.Connection) DatabaseVersionSqlDao(org.syncany.database.dao.DatabaseVersionSqlDao) MultiChunkSqlDao(org.syncany.database.dao.MultiChunkSqlDao) ChunkSqlDao(org.syncany.database.dao.ChunkSqlDao) MultiChunkSqlDao(org.syncany.database.dao.MultiChunkSqlDao) FileVersionSqlDao(org.syncany.database.dao.FileVersionSqlDao) FileContentSqlDao(org.syncany.database.dao.FileContentSqlDao) DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader) FileHistorySqlDao(org.syncany.database.dao.FileHistorySqlDao) Test(org.junit.Test)

Example 2 with DatabaseVersionHeader

use of org.syncany.database.DatabaseVersionHeader in project syncany by syncany.

the class DownOperation method persistMuddyMultiChunks.

/**
 * Identifies and persists 'muddy' multichunks to the local database. Muddy multichunks are multichunks
 * that have been referenced by DIRTY database versions and might be reused in future database versions when
 * the other client cleans up its mess (performs another 'up').
 */
private void persistMuddyMultiChunks(Entry<String, DatabaseBranch> winnersBranch, DatabaseBranches allStitchedBranches, Map<DatabaseVersionHeader, File> databaseVersionLocations) throws StorageException, IOException, SQLException {
    // Find dirty database versions (from other clients!) and load them from files
    Map<DatabaseVersionHeader, Collection<MultiChunkEntry>> muddyMultiChunksPerDatabaseVersion = new HashMap<>();
    Set<DatabaseVersionHeader> winnersDatabaseVersionHeaders = Sets.newHashSet(winnersBranch.getValue().getAll());
    for (String otherClientName : allStitchedBranches.getClients()) {
        boolean isLocalMachine = config.getMachineName().equals(otherClientName);
        if (!isLocalMachine) {
            DatabaseBranch otherClientBranch = allStitchedBranches.getBranch(otherClientName);
            Set<DatabaseVersionHeader> otherClientDatabaseVersionHeaders = Sets.newHashSet(otherClientBranch.getAll());
            SetView<DatabaseVersionHeader> otherMuddyDatabaseVersionHeaders = Sets.difference(otherClientDatabaseVersionHeaders, winnersDatabaseVersionHeaders);
            boolean hasMuddyDatabaseVersionHeaders = otherMuddyDatabaseVersionHeaders.size() > 0;
            if (hasMuddyDatabaseVersionHeaders) {
                logger.log(Level.INFO, "DIRTY database version headers of " + otherClientName + ":  " + otherMuddyDatabaseVersionHeaders);
                for (DatabaseVersionHeader muddyDatabaseVersionHeader : otherMuddyDatabaseVersionHeaders) {
                    MemoryDatabase muddyMultiChunksDatabase = new MemoryDatabase();
                    File localFileForMuddyDatabaseVersion = databaseVersionLocations.get(muddyDatabaseVersionHeader);
                    VectorClock fromVersion = muddyDatabaseVersionHeader.getVectorClock();
                    VectorClock toVersion = muddyDatabaseVersionHeader.getVectorClock();
                    logger.log(Level.INFO, "  - Loading " + muddyDatabaseVersionHeader + " from file " + localFileForMuddyDatabaseVersion);
                    databaseSerializer.load(muddyMultiChunksDatabase, localFileForMuddyDatabaseVersion, fromVersion, toVersion, DatabaseReadType.FULL);
                    boolean hasMuddyMultiChunks = muddyMultiChunksDatabase.getMultiChunks().size() > 0;
                    if (hasMuddyMultiChunks) {
                        muddyMultiChunksPerDatabaseVersion.put(muddyDatabaseVersionHeader, muddyMultiChunksDatabase.getMultiChunks());
                    }
                }
            }
        }
    }
    // Add muddy multichunks to 'multichunks_muddy' database table
    boolean hasMuddyMultiChunks = muddyMultiChunksPerDatabaseVersion.size() > 0;
    if (hasMuddyMultiChunks) {
        localDatabase.writeMuddyMultiChunks(muddyMultiChunksPerDatabaseVersion);
    }
}
Also used : HashMap(java.util.HashMap) VectorClock(org.syncany.database.VectorClock) MemoryDatabase(org.syncany.database.MemoryDatabase) Collection(java.util.Collection) DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader) DatabaseRemoteFile(org.syncany.plugins.transfer.files.DatabaseRemoteFile) CleanupRemoteFile(org.syncany.plugins.transfer.files.CleanupRemoteFile) File(java.io.File)

Example 3 with DatabaseVersionHeader

use of org.syncany.database.DatabaseVersionHeader in project syncany by syncany.

the class DownOperation method populateDatabaseBranches.

/**
 * This methods takes a Map containing DatabaseVersions (headers only) and loads these headers into {@link DatabaseBranches}.
 * In addition, the local branch is added to this. The resulting DatabaseBranches will contain all headers exactly once,
 * for the client that created that version.
 *
 * @param localBranch {@link DatabaseBranch} containing the locally known headers.
 * @param remoteDatabaseHeaders Map from {@link DatabaseRemoteFile}s (important for client names) to the {@link DatabaseVersion}s that are
 *        contained in these files.
 *
 * @return DatabaseBranches filled with all the headers that originated from either of the parameters.
 */
private DatabaseBranches populateDatabaseBranches(DatabaseBranch localBranch, SortedMap<DatabaseRemoteFile, List<DatabaseVersion>> remoteDatabaseHeaders) {
    DatabaseBranches allBranches = new DatabaseBranches();
    allBranches.put(config.getMachineName(), localBranch.clone());
    for (DatabaseRemoteFile remoteDatabaseFile : remoteDatabaseHeaders.keySet()) {
        // Populate branches
        DatabaseBranch remoteClientBranch = allBranches.getBranch(remoteDatabaseFile.getClientName(), true);
        for (DatabaseVersion remoteDatabaseVersion : remoteDatabaseHeaders.get(remoteDatabaseFile)) {
            DatabaseVersionHeader header = remoteDatabaseVersion.getHeader();
            remoteClientBranch.add(header);
        }
    }
    logger.log(Level.INFO, "Populated unknown branches: " + allBranches);
    return allBranches;
}
Also used : DatabaseRemoteFile(org.syncany.plugins.transfer.files.DatabaseRemoteFile) DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader) DatabaseVersion(org.syncany.database.DatabaseVersion)

Example 4 with DatabaseVersionHeader

use of org.syncany.database.DatabaseVersionHeader in project syncany by syncany.

the class DatabaseReconciliator method findWinnersNameAndBranch.

/**
 * Algorithm to find the winner's database branch (client name and branch).
 * The winner's branch is used to determine the local file system actions.
 *
 * <p>Basic algorithm: Sort all databaseversions by vectorclocks, tiebreaking with timestamps and machinenames.
 * Iterate over this list, adding databaseversions to the winning branch if they are not simultaneous with the
 * winning branch up until this point.
 *
 * <p><b>Illustration:</b><br />
 * Suppose the following branches exist.
 * Naming: <em>created-by / vector clock / local time</em>.
 *
 * <pre>
 *    A               B                C
 * --|-------------------------------------------------
 * 0 | A/(A1)/T=10    B/(A3,B1)/T=20   C/(A1,C1)/T=14
 * 1 | A/(A2)/T=13                     C/(A1,C2)/T=15
 * 2 | A/(A3)/T=19
 * 3 | A/(A4)/T=23
 * </pre>
 *
 * <b>Sorted Database versions:</b>
 * <ol>
 * 	<li>A[0]:A/(A1)/T=10</li>
 *  <li>A[1]:A/(A2)/T=13</li>
 *  <li>C[0]:C/(A1,C1)/T=14</li>
 *  <li>C[1]:C/(A1,C2)/T=15</li>
 *  <li>A[2]:A/(A3)/T=19</li>
 *  <li>B[0]:B/(A3,B1)/T=20</li>
 *  <li>A[3]:A/(A4)/T=23</li>
 * </ol>
 *
 * <b>Iterating through the list:</b>
 * <ol>
 *  <li>A[0] is the first version. Add it.</li>
 *  <li>A[1] > A[0]. Add it.</li>
 *  <li>C[0] is simultaneous with A[1]. Ignore it.</li>
 *  <li>C[1] is simultaneous with A[1]. Ignore it.</li>
 *  <li>A[2] > A[1]. Add it.</li>
 *  <li>B[0] > A[2]. Add it.</li>
 *  <li>A[3] is simultaneous with B[0]. Ignore it.</li>
 * </ol>
 *
 * <b>Winning branch:</b>
 * <ol>
 * 	<li>A[0]:A/(A1)/T=10</li>
 *  <li>A[1]:A/(A2)/T=13</li>
 *  <li>A[2]:A/(A3)/T=19</li>
 *  <li>B[0]:B/(A3,B1)/T=20</li>
 * </ol>
 *
 * Last version matches last version of B. Hence B wins.
 *
 * @param allStitchedBranches All branches of all machines (including local)
 * @return Returns the name and the branch of the winning machine
 */
private Entry<String, DatabaseBranch> findWinnersNameAndBranch(DatabaseBranches allBranches) {
    List<DatabaseVersionHeader> databaseVersionHeaders = sortBranches(allBranches);
    if (databaseVersionHeaders.size() == 0) {
        return null;
    }
    // Determine winning branch
    DatabaseBranch winnersBranch = new DatabaseBranch();
    DatabaseVersionHeaderComparator databaseVersionHeaderComparator = new DatabaseVersionHeaderComparator(false);
    for (DatabaseVersionHeader potentialWinner : databaseVersionHeaders) {
        boolean emptyWinnerBranch = winnersBranch.size() == 0;
        boolean potentialWinnerWins = !emptyWinnerBranch && databaseVersionHeaderComparator.compare(potentialWinner, winnersBranch.getLast()) > 0;
        if (emptyWinnerBranch || potentialWinnerWins) {
            logger.log(Level.INFO, "Adding database version to winning branch: " + potentialWinner);
            winnersBranch.add(potentialWinner);
        } else {
            logger.log(Level.INFO, "Ignoring databaseVersion: " + potentialWinner);
        }
    }
    // Determine client name for winning branch
    DatabaseVersionHeader winningLastDatabaseVersionHeader = winnersBranch.getLast();
    for (String currentClient : allBranches.getClients()) {
        DatabaseBranch currentBranch = allBranches.getBranch(currentClient);
        DatabaseVersionHeader currentBranchLastDatabaseVersionHeader = currentBranch.getLast();
        if (winningLastDatabaseVersionHeader.equals(currentBranchLastDatabaseVersionHeader)) {
            return new AbstractMap.SimpleEntry<String, DatabaseBranch>(currentClient, winnersBranch);
        }
    }
    return null;
}
Also used : DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader)

Example 5 with DatabaseVersionHeader

use of org.syncany.database.DatabaseVersionHeader in project syncany by syncany.

the class MultiChunkSqlDao method writeMuddyMultiChunks.

public void writeMuddyMultiChunks(Map<DatabaseVersionHeader, Collection<MultiChunkEntry>> muddyMultiChunksPerDatabaseVersion) throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk_muddy.insert.muddy.writeMuddyMultiChunks.sql");
    for (DatabaseVersionHeader muddyDatabaseVersionHeader : muddyMultiChunksPerDatabaseVersion.keySet()) {
        Collection<MultiChunkEntry> muddyMultiChunks = muddyMultiChunksPerDatabaseVersion.get(muddyDatabaseVersionHeader);
        for (MultiChunkEntry muddyMultiChunk : muddyMultiChunks) {
            String multiChunkIdStr = muddyMultiChunk.getId().toString();
            String clientName = muddyDatabaseVersionHeader.getClient();
            Long clientVersion = muddyDatabaseVersionHeader.getVectorClock().getClock(clientName);
            preparedStatement.setString(1, multiChunkIdStr);
            preparedStatement.setString(2, clientName);
            preparedStatement.setLong(3, clientVersion);
            preparedStatement.addBatch();
        }
    }
    preparedStatement.executeBatch();
    preparedStatement.close();
}
Also used : PreparedStatement(java.sql.PreparedStatement) DatabaseVersionHeader(org.syncany.database.DatabaseVersionHeader) MultiChunkEntry(org.syncany.database.MultiChunkEntry)

Aggregations

DatabaseVersionHeader (org.syncany.database.DatabaseVersionHeader)36 Test (org.junit.Test)19 DatabaseBranches (org.syncany.operations.down.DatabaseBranches)14 Date (java.util.Date)7 DatabaseVersion (org.syncany.database.DatabaseVersion)5 MultiChunkEntry (org.syncany.database.MultiChunkEntry)5 VectorClock (org.syncany.database.VectorClock)5 File (java.io.File)4 Connection (java.sql.Connection)4 Config (org.syncany.config.Config)4 ChunkEntry (org.syncany.database.ChunkEntry)4 FileContent (org.syncany.database.FileContent)4 MultiChunkId (org.syncany.database.MultiChunkEntry.MultiChunkId)4 PartialFileHistory (org.syncany.database.PartialFileHistory)4 ChunkSqlDao (org.syncany.database.dao.ChunkSqlDao)4 DatabaseVersionSqlDao (org.syncany.database.dao.DatabaseVersionSqlDao)4 FileContentSqlDao (org.syncany.database.dao.FileContentSqlDao)4 FileHistorySqlDao (org.syncany.database.dao.FileHistorySqlDao)4 FileVersionSqlDao (org.syncany.database.dao.FileVersionSqlDao)4 MultiChunkSqlDao (org.syncany.database.dao.MultiChunkSqlDao)4