use of org.syncany.database.MultiChunkEntry in project syncany by syncany.
the class DatabaseVersionDaoTest method testRemoveDirtyDatabaseVersions.
@Test
public void testRemoveDirtyDatabaseVersions() 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);
// a. Test before
List<DatabaseVersion> dirtyDatabaseVersionsBefore = TestCollectionUtil.toList(databaseVersionDao.getDirtyDatabaseVersions());
assertNotNull(dirtyDatabaseVersionsBefore);
assertNotNull(chunkDao.getChunk(ChunkChecksum.parseChunkChecksum("beefbeefbeefbeefbeefbeefbeefbeefbeefbeef")));
assertNotNull(multiChunkDao.getDirtyMultiChunkIds());
assertEquals(1, multiChunkDao.getDirtyMultiChunkIds().size());
// b. Add new database version with DIRTY multichunk; remove DIRTY version
DatabaseVersion newDatabaseVersion = new DatabaseVersion();
newDatabaseVersion.setVectorClock(TestDatabaseUtil.createVectorClock("A5,B2"));
long newDatabaseVersionId = databaseVersionDao.writeDatabaseVersion(newDatabaseVersion);
databaseVersionDao.removeDirtyDatabaseVersions(newDatabaseVersionId);
// c. Test after
// Database version
List<DatabaseVersion> dirtyDatabaseVersionsAfter = TestCollectionUtil.toList(databaseVersionDao.getDirtyDatabaseVersions());
assertNotNull(dirtyDatabaseVersionsAfter);
assertEquals(0, dirtyDatabaseVersionsAfter.size());
// Multichunk from dirty version "moved" to new version
Map<MultiChunkId, MultiChunkEntry> multiChunksA5B2 = multiChunkDao.getMultiChunks(TestDatabaseUtil.createVectorClock("A5,B2"));
assertNotNull(multiChunksA5B2);
assertEquals(1, multiChunksA5B2.size());
assertNotNull(multiChunksA5B2.get(MultiChunkId.parseMultiChunkId("1234567890987654321123456789098765433222")));
// File version/history/content ARE removed
assertNull(fileContentDao.getFileContent(FileChecksum.parseFileChecksum("beefbeefbeefbeefbeefbeefbeefbeefbeefbeef"), true));
// TODO [low] Test file version and file history removal
// Chunks and multichunks are NOT removed!
assertNotNull(chunkDao.getChunk(ChunkChecksum.parseChunkChecksum("beefbeefbeefbeefbeefbeefbeefbeefbeefbeef")));
assertNotNull(multiChunkDao.getMultiChunks(TestDatabaseUtil.createVectorClock("B1")));
assertEquals(0, multiChunkDao.getMultiChunks(TestDatabaseUtil.createVectorClock("B1")).size());
assertNotNull(multiChunkDao.getDirtyMultiChunkIds());
assertEquals(0, multiChunkDao.getDirtyMultiChunkIds().size());
// Tear down
databaseConnection.close();
TestConfigUtil.deleteTestLocalConfigAndData(testConfig);
}
use of org.syncany.database.MultiChunkEntry 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.MultiChunkEntry in project syncany by syncany.
the class DatabaseXmlParseHandler method startElement.
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
elementPath += "/" + qName;
if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion")) {
databaseVersion = new DatabaseVersion();
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/header/time")) {
Date timeValue = new Date(Long.parseLong(attributes.getValue("value")));
databaseVersion.setTimestamp(timeValue);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/header/client")) {
String clientName = attributes.getValue("name");
databaseVersion.setClient(clientName);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/header/vectorClock")) {
vectorClock = new VectorClock();
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/header/vectorClock/client")) {
String clientName = attributes.getValue("name");
Long clientValue = Long.parseLong(attributes.getValue("value"));
vectorClock.setClock(clientName, clientValue);
} else if (readType == DatabaseReadType.FULL) {
if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/chunks/chunk")) {
String chunkChecksumStr = attributes.getValue("checksum");
ChunkChecksum chunkChecksum = ChunkChecksum.parseChunkChecksum(chunkChecksumStr);
int chunkSize = Integer.parseInt(attributes.getValue("size"));
ChunkEntry chunkEntry = new ChunkEntry(chunkChecksum, chunkSize);
databaseVersion.addChunk(chunkEntry);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/fileContents/fileContent")) {
String checksumStr = attributes.getValue("checksum");
long size = Long.parseLong(attributes.getValue("size"));
fileContent = new FileContent();
fileContent.setChecksum(FileChecksum.parseFileChecksum(checksumStr));
fileContent.setSize(size);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/fileContents/fileContent/chunkRefs/chunkRef")) {
String chunkChecksumStr = attributes.getValue("ref");
fileContent.addChunk(ChunkChecksum.parseChunkChecksum(chunkChecksumStr));
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/multiChunks/multiChunk")) {
String multChunkIdStr = attributes.getValue("id");
MultiChunkId multiChunkId = MultiChunkId.parseMultiChunkId(multChunkIdStr);
long size = Long.parseLong(attributes.getValue("size"));
if (multiChunkId == null) {
throw new SAXException("Cannot read ID from multichunk " + multChunkIdStr);
}
multiChunk = new MultiChunkEntry(multiChunkId, size);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/multiChunks/multiChunk/chunkRefs/chunkRef")) {
String chunkChecksumStr = attributes.getValue("ref");
multiChunk.addChunk(ChunkChecksum.parseChunkChecksum(chunkChecksumStr));
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/fileHistories/fileHistory")) {
String fileHistoryIdStr = attributes.getValue("id");
FileHistoryId fileId = FileHistoryId.parseFileId(fileHistoryIdStr);
fileHistory = new PartialFileHistory(fileId);
} else if (elementPath.equalsIgnoreCase("/database/databaseVersions/databaseVersion/fileHistories/fileHistory/fileVersions/fileVersion")) {
String fileVersionStr = attributes.getValue("version");
String path = attributes.getValue("path");
String pathEncoded = attributes.getValue("pathEncoded");
String sizeStr = attributes.getValue("size");
String typeStr = attributes.getValue("type");
String statusStr = attributes.getValue("status");
String lastModifiedStr = attributes.getValue("lastModified");
String updatedStr = attributes.getValue("updated");
String checksumStr = attributes.getValue("checksum");
String linkTarget = attributes.getValue("linkTarget");
String dosAttributes = attributes.getValue("dosattrs");
String posixPermissions = attributes.getValue("posixperms");
if (fileVersionStr == null || (path == null && pathEncoded == null) || typeStr == null || statusStr == null || sizeStr == null || lastModifiedStr == null) {
throw new SAXException("FileVersion: Attributes missing: version, path/pathEncoded, type, status, size and last modified are mandatory");
}
// Filter it if it was purged somewhere in the future, see #58
Long fileVersionNum = Long.parseLong(fileVersionStr);
// Go add it!
FileVersion fileVersion = new FileVersion();
fileVersion.setVersion(fileVersionNum);
if (path != null) {
fileVersion.setPath(path);
} else {
try {
fileVersion.setPath(new String(Base64.decodeBase64(pathEncoded), "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Invalid Base64 encoding for filename: " + pathEncoded);
}
}
fileVersion.setType(FileType.valueOf(typeStr));
fileVersion.setStatus(FileStatus.valueOf(statusStr));
fileVersion.setSize(Long.parseLong(sizeStr));
fileVersion.setLastModified(new Date(Long.parseLong(lastModifiedStr)));
if (updatedStr != null) {
fileVersion.setUpdated(new Date(Long.parseLong(updatedStr)));
}
if (checksumStr != null) {
fileVersion.setChecksum(FileChecksum.parseFileChecksum(checksumStr));
}
if (linkTarget != null) {
fileVersion.setLinkTarget(linkTarget);
}
if (dosAttributes != null) {
fileVersion.setDosAttributes(dosAttributes);
}
if (posixPermissions != null) {
fileVersion.setPosixPermissions(posixPermissions);
}
fileHistory.addFileVersion(fileVersion);
}
}
}
use of org.syncany.database.MultiChunkEntry in project syncany by syncany.
the class MultiChunkSqlDao method createMultiChunkEntriesWithChunks.
private Map<MultiChunkId, MultiChunkEntry> createMultiChunkEntriesWithChunks(ResultSet resultSet) throws SQLException {
Map<MultiChunkId, MultiChunkEntry> multiChunkEntries = new HashMap<MultiChunkId, MultiChunkEntry>();
MultiChunkId currentMultiChunkId = null;
while (resultSet.next()) {
MultiChunkId multiChunkId = MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id"));
long multiChunkSize = resultSet.getLong("size");
MultiChunkEntry multiChunkEntry = null;
if (currentMultiChunkId != null && currentMultiChunkId.equals(multiChunkId)) {
multiChunkEntry = multiChunkEntries.get(multiChunkId);
} else {
multiChunkEntry = new MultiChunkEntry(multiChunkId, multiChunkSize);
}
multiChunkEntry.addChunk(ChunkChecksum.parseChunkChecksum(resultSet.getString("chunk_checksum")));
multiChunkEntries.put(multiChunkId, multiChunkEntry);
currentMultiChunkId = multiChunkId;
}
return multiChunkEntries;
}
use of org.syncany.database.MultiChunkEntry in project syncany by syncany.
the class CleanupOperation method deleteUnusedRemoteMultiChunks.
/**
* This method adds unusedMultiChunks to the @{link RemoteTransaction} for deletion.
*
* @param unusedMultiChunks which are to be deleted because all references to them are gone.
*/
private void deleteUnusedRemoteMultiChunks(Map<MultiChunkId, MultiChunkEntry> unusedMultiChunks) throws StorageException {
logger.log(Level.INFO, "- Deleting remote multichunks ...");
for (MultiChunkEntry multiChunkEntry : unusedMultiChunks.values()) {
logger.log(Level.FINE, " + Deleting remote multichunk " + multiChunkEntry + " ...");
remoteTransaction.delete(new MultichunkRemoteFile(multiChunkEntry.getId()));
}
}
Aggregations