use of org.syncany.database.MemoryDatabase in project syncany by syncany.
the class MemoryDatabaseCacheTest method testMultiChunkCache.
@Test
public void testMultiChunkCache() throws IOException {
MemoryDatabase database = new MemoryDatabase();
// Round 1: Add chunk to multichunk
DatabaseVersion databaseVersion1 = TestDatabaseUtil.createDatabaseVersion();
MultiChunkEntry multiChunkP1 = new MultiChunkEntry(new MultiChunkId(new byte[] { 8, 8, 8, 8, 8, 8, 8, 8 }), 10);
ChunkEntry chunkA1 = new ChunkEntry(new ChunkChecksum(new byte[] { 1, 2, 3, 4, 5, 7, 8, 9, 0 }), 12);
multiChunkP1.addChunk(chunkA1.getChecksum());
databaseVersion1.addChunk(chunkA1);
databaseVersion1.addMultiChunk(multiChunkP1);
database.addDatabaseVersion(databaseVersion1);
assertEquals(chunkA1, database.getChunk(new ChunkChecksum(new byte[] { 1, 2, 3, 4, 5, 7, 8, 9, 0 })));
assertEquals(multiChunkP1, database.getMultiChunk(new MultiChunkId(new byte[] { 8, 8, 8, 8, 8, 8, 8, 8 })));
// Round 2: Add chunk to multichunk
DatabaseVersion databaseVersion2 = TestDatabaseUtil.createDatabaseVersion(databaseVersion1);
MultiChunkEntry multiChunkP2 = new MultiChunkEntry(new MultiChunkId(new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7 }), 11);
MultiChunkEntry multiChunkP3 = new MultiChunkEntry(new MultiChunkId(new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5 }), 12);
ChunkEntry chunkA2 = new ChunkEntry(new ChunkChecksum(new byte[] { 9, 2, 3, 4, 5, 7, 8, 9, 0 }), 912);
ChunkEntry chunkA3 = new ChunkEntry(new ChunkChecksum(new byte[] { 8, 2, 3, 4, 5, 7, 8, 9, 0 }), 812);
ChunkEntry chunkA4 = new ChunkEntry(new ChunkChecksum(new byte[] { 7, 2, 3, 4, 5, 7, 8, 9, 0 }), 712);
multiChunkP2.addChunk(chunkA2.getChecksum());
multiChunkP2.addChunk(chunkA3.getChecksum());
multiChunkP3.addChunk(chunkA4.getChecksum());
databaseVersion2.addChunk(chunkA2);
databaseVersion2.addChunk(chunkA3);
databaseVersion2.addChunk(chunkA4);
databaseVersion2.addMultiChunk(multiChunkP2);
databaseVersion2.addMultiChunk(multiChunkP3);
database.addDatabaseVersion(databaseVersion2);
// fail("xx");
assertEquals(chunkA1, database.getChunk(new ChunkChecksum(new byte[] { 1, 2, 3, 4, 5, 7, 8, 9, 0 })));
assertEquals(chunkA2, database.getChunk(new ChunkChecksum(new byte[] { 9, 2, 3, 4, 5, 7, 8, 9, 0 })));
assertEquals(chunkA3, database.getChunk(new ChunkChecksum(new byte[] { 8, 2, 3, 4, 5, 7, 8, 9, 0 })));
assertEquals(chunkA4, database.getChunk(new ChunkChecksum(new byte[] { 7, 2, 3, 4, 5, 7, 8, 9, 0 })));
assertEquals(multiChunkP1, database.getMultiChunk(new MultiChunkId(new byte[] { 8, 8, 8, 8, 8, 8, 8, 8 })));
assertEquals(multiChunkP2, database.getMultiChunk(new MultiChunkId(new byte[] { 7, 7, 7, 7, 7, 7, 7, 7, 7 })));
assertEquals(multiChunkP3, database.getMultiChunk(new MultiChunkId(new byte[] { 5, 5, 5, 5, 5, 5, 5, 5, 5 })));
}
use of org.syncany.database.MemoryDatabase in project syncany by syncany.
the class TestDatabaseUtil method readDatabaseFileFromDisk.
public static MemoryDatabase readDatabaseFileFromDisk(File databaseFile, Transformer transformer) throws IOException {
MemoryDatabase db = new MemoryDatabase();
DatabaseXmlSerializer dao = new DatabaseXmlSerializer(transformer);
dao.load(db, databaseFile, null, null, DatabaseReadType.FULL);
return db;
}
use of org.syncany.database.MemoryDatabase in project syncany by syncany.
the class UpOperation method attemptResumeDatabaseVersions.
private Collection<DatabaseVersion> attemptResumeDatabaseVersions(Collection<Long> versions) throws Exception {
try {
Collection<DatabaseVersion> databaseVersions = new ArrayList<>();
for (Long version : versions) {
File databaseFile = config.getTransactionDatabaseFile(version);
// If a single database file is missing, we should restart
if (!databaseFile.exists()) {
return null;
}
DatabaseXmlSerializer databaseSerializer = new DatabaseXmlSerializer();
MemoryDatabase memoryDatabase = new MemoryDatabase();
databaseSerializer.load(memoryDatabase, databaseFile, null, null, DatabaseReadType.FULL);
if (memoryDatabase.getDatabaseVersions().size() == 0) {
return null;
}
databaseVersions.add(memoryDatabase.getLastDatabaseVersion());
}
return databaseVersions;
} catch (Exception e) {
logger.log(Level.WARNING, "Cannot load database versions from 'state'. Cannot resume.");
return null;
}
}
use of org.syncany.database.MemoryDatabase in project syncany by syncany.
the class UpOperation method serializeRemoteTransactionsAndMetadata.
/**
* Serializes both the remote transaction and the current database version
* that would be added if Up was successful.
* @param newDatabaseVersion the current metadata
*/
private void serializeRemoteTransactionsAndMetadata(List<RemoteTransaction> remoteTransactions, List<DatabaseVersion> newDatabaseVersions) {
try {
logger.log(Level.INFO, "Persisting status of UpOperation to " + config.getStateDir() + " ...");
// Collect a list of all database version numbers that will be saved
List<Long> databaseVersionClocks = new ArrayList<>();
for (int i = 0; i < remoteTransactions.size(); i++) {
DatabaseVersion databaseVersion = newDatabaseVersions.get(i);
long databaseVersionClock = databaseVersion.getVectorClock().getClock(config.getMachineName());
databaseVersionClocks.add(databaseVersionClock);
}
// Write the list of version number to a file, before serializing any transactions!
// This ensures that no transaction files can exist without a "reference" to them.
File transactionListFile = config.getTransactionListFile();
PrintWriter transactionListWriter = new PrintWriter(new OutputStreamWriter(new FileOutputStream(transactionListFile), "UTF-8"));
for (Long databaseVersion : databaseVersionClocks) {
transactionListWriter.println(databaseVersion);
}
transactionListWriter.close();
// For each database version write the transaction and database files
for (int i = 0; i < remoteTransactions.size(); i++) {
DatabaseVersion databaseVersion = newDatabaseVersions.get(i);
long databaseVersionClock = databaseVersionClocks.get(i);
// Writing transaction file to state dir
remoteTransactions.get(i).writeToFile(null, config.getTransactionFile(databaseVersionClock));
// Writing database representation of new database version to state dir
MemoryDatabase memoryDatabase = new MemoryDatabase();
memoryDatabase.addDatabaseVersion(databaseVersion);
DatabaseXmlSerializer dao = new DatabaseXmlSerializer();
dao.save(memoryDatabase.getDatabaseVersions(), config.getTransactionDatabaseFile(databaseVersionClock));
}
// The first transaction may be resumable, so write it to the default transaction file
remoteTransactions.get(0).writeToFile(null, config.getTransactionFile());
} catch (Exception e) {
logger.log(Level.WARNING, "Failure when persisting status of Up: ", e);
}
}
use of org.syncany.database.MemoryDatabase in project syncany by syncany.
the class DatabaseFileReader method next.
/**
* Loads the winner's database branch into the memory in a {@link MemoryDatabase} object, by using
* the already downloaded list of remote database files.
*
* <p>Because database files can contain multiple {@link DatabaseVersion}s per client, a range for which
* to load the database versions must be determined.
*
* <p><b>Example 1:</b><br />
* <pre>
* db-A-0001 (A1) Already known Not loaded
* db-A-0005 (A2) Already known Not loaded
* (A3) Already known Not loaded
* (A4) Part of winner's branch Loaded
* (A5) Purge database version Ignored (only DEFAULT)
* db-B-0001 (A5,B1) Part of winner's branch Loaded
* db-A-0006 (A6,B1) Part of winner's branch Loaded
* </pre>
*
* <p>In example 1, only (A4)-(A5) must be loaded from db-A-0005, and not all four database versions.
*
* <p><b>Other example:</b><br />
* <pre>
* db-A-0005 (A1) Part of winner's branch Loaded
* db-A-0005 (A2) Part of winner's branch Loaded
* db-B-0001 (A2,B1) Part of winner's branch Loaded
* db-A-0005 (A3,B1) Part of winner's branch Loaded
* db-A-0005 (A4,B1) Part of winner's branch Loaded
* db-A-0005 (A5,B1) Purge database version Ignored (only DEFAULT)
* </pre>
*
* <p>In example 2, (A1)-(A5,B1) [except (A2,B1)] are contained in db-A-0005 (after merging!), so
* db-A-0005 must be processed twice; each time loading separate parts of the file. In this case:
* First load (A1)-(A2) from db-A-0005, then load (A2,B1) from db-B-0001, then load (A3,B1)-(A4,B1)
* from db-A-0005, and ignore (A5,B1).
* @param databaseFileList
* @param ignoredMostRecentPurgeVersions
*
* @return Returns a loaded memory database containing all metadata from the winner's branch
*/
@Override
public MemoryDatabase next() {
MemoryDatabase winnerBranchDatabase = new MemoryDatabase();
String rangeClientName = null;
VectorClock rangeVersionFrom = null;
VectorClock rangeVersionTo = null;
while (branchIndex < winnersApplyBranchList.size() && winnerBranchDatabase.getFileHistories().size() < MAX_FILES) {
DatabaseVersionHeader currentDatabaseVersionHeader = winnersApplyBranchList.get(branchIndex);
DatabaseVersionHeader nextDatabaseVersionHeader = (branchIndex + 1 < winnersApplyBranchList.size()) ? winnersApplyBranchList.get(branchIndex + 1) : null;
// First of range for this client
if (rangeClientName == null) {
rangeClientName = currentDatabaseVersionHeader.getClient();
rangeVersionFrom = currentDatabaseVersionHeader.getVectorClock();
rangeVersionTo = currentDatabaseVersionHeader.getVectorClock();
} else // Still in range for this client
{
rangeVersionTo = currentDatabaseVersionHeader.getVectorClock();
}
// Now load this stuff from the database file (or not)
// - If the database file exists, load the range and reset it
// - If not, only force a load if this is the range end
File databaseVersionFile = databaseVersionLocations.get(currentDatabaseVersionHeader);
if (databaseVersionFile == null) {
throw new RuntimeException("Could not find file corresponding to " + currentDatabaseVersionHeader + ", while it is in the winners branch.");
}
boolean lastDatabaseVersionHeader = nextDatabaseVersionHeader == null;
boolean nextDatabaseVersionInSameFile = lastDatabaseVersionHeader || databaseVersionFile.equals(databaseVersionLocations.get(nextDatabaseVersionHeader));
boolean rangeEnds = lastDatabaseVersionHeader || !nextDatabaseVersionInSameFile;
if (rangeEnds) {
try {
databaseSerializer.load(winnerBranchDatabase, databaseVersionFile, rangeVersionFrom, rangeVersionTo, DatabaseReadType.FULL);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
rangeClientName = null;
}
branchIndex++;
}
return winnerBranchDatabase;
}
Aggregations