113 lines
4.8 KiB
Java
113 lines
4.8 KiB
Java
package it.cavallium.strangedb.database;
|
|
|
|
import it.cavallium.strangedb.database.blocks.DatabaseBlocksIO;
|
|
import it.cavallium.strangedb.database.blocks.DatabaseBlocksMetadata;
|
|
import it.cavallium.strangedb.database.references.DatabaseReferencesIO;
|
|
import it.cavallium.strangedb.database.references.DatabaseReferencesMetadata;
|
|
import it.cavallium.strangedb.database.references.ReferenceInfo;
|
|
|
|
import java.io.IOException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.StandardCopyOption;
|
|
|
|
import static it.cavallium.strangedb.database.references.DatabaseReferencesMetadata.NONEXISTENT_REFERENCE_INFO;
|
|
|
|
public class DatabaseCore implements IDatabase {
|
|
|
|
private final DatabaseFileIO fileIO;
|
|
private final DatabaseBlocksIO blocksIO;
|
|
protected final DatabaseBlocksMetadata blocksMetadata;
|
|
protected final DatabaseReferencesIO referencesIO;
|
|
protected final DatabaseReferencesMetadata referencesMetadata;
|
|
protected final Path dataFile;
|
|
protected final Path blocksMetaFile;
|
|
protected final Path referencesMetaFile;
|
|
protected volatile boolean closed;
|
|
|
|
public DatabaseCore(Path dataFile, Path blocksMetaFile, Path referencesMetaFile) throws IOException {
|
|
if (Files.notExists(dataFile)) {
|
|
Files.createFile(dataFile);
|
|
}
|
|
if (Files.notExists(blocksMetaFile)) {
|
|
Files.createFile(blocksMetaFile);
|
|
}
|
|
if (Files.notExists(referencesMetaFile)) {
|
|
Files.createFile(referencesMetaFile);
|
|
}
|
|
this.dataFile = dataFile;
|
|
this.blocksMetaFile = blocksMetaFile;
|
|
this.referencesMetaFile = referencesMetaFile;
|
|
this.fileIO = new DatabaseFileIO(dataFile);
|
|
this.blocksMetadata = new DatabaseBlocksMetadata(blocksMetaFile);
|
|
this.blocksIO = new DatabaseBlocksIO(fileIO, blocksMetadata);
|
|
this.referencesMetadata = new DatabaseReferencesMetadata(referencesMetaFile);
|
|
this.referencesIO = new DatabaseReferencesIO(blocksIO, referencesMetadata);
|
|
}
|
|
|
|
@Override
|
|
public synchronized void close() throws IOException {
|
|
if (this.closed) {
|
|
throw new IOException("The database has been already closed!");
|
|
}
|
|
this.referencesMetadata.close();
|
|
this.blocksMetadata.close();
|
|
this.fileIO.close();
|
|
this.closed = true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isClosed() {
|
|
return closed;
|
|
}
|
|
|
|
@Override
|
|
public void closeAndClean() throws IOException {
|
|
if (!this.closed) {
|
|
this.close();
|
|
}
|
|
Path newDataFile = dataFile.resolveSibling("compressed-data-file.tmp");
|
|
Path newBlocksFile = blocksMetaFile.resolveSibling("compressed-blocks-file.tmp");
|
|
Path newReferencesFile = referencesMetaFile.resolveSibling("compressed-references-file.tmp");
|
|
Path backupDataFile = dataFile.resolveSibling("backup-data.db.bak");
|
|
Path backupBlocksFile = blocksMetaFile.resolveSibling("backup-blocks.dat.bak");
|
|
Path backupReferencesFile = referencesMetaFile.resolveSibling("backup-references.dat.bak");
|
|
Files.copy(dataFile, backupDataFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
|
|
Files.copy(blocksMetaFile, backupBlocksFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
|
|
Files.copy(referencesMetaFile, backupReferencesFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES);
|
|
Files.move(dataFile, newDataFile, StandardCopyOption.REPLACE_EXISTING);
|
|
Files.move(blocksMetaFile, newBlocksFile, StandardCopyOption.REPLACE_EXISTING);
|
|
Files.move(referencesMetaFile, newReferencesFile, StandardCopyOption.REPLACE_EXISTING);
|
|
DatabaseCore databaseToClean = new DatabaseCore(newDataFile, newBlocksFile, newReferencesFile);
|
|
DatabaseCore newDatabase = new DatabaseCore(dataFile, blocksMetaFile, referencesMetaFile);
|
|
|
|
long referencesCount = databaseToClean.referencesMetadata.getFirstFreeReference();
|
|
long blocksCount = databaseToClean.blocksMetadata.getTotalBlocksCount();
|
|
long writtenReferences = 0;
|
|
long writtenBlocks = 0;
|
|
|
|
for (int referenceID = 0; referenceID < referencesCount; referenceID++) {
|
|
try {
|
|
ReferenceInfo ref = databaseToClean.referencesMetadata.getCleanReference(referenceID);
|
|
if (!NONEXISTENT_REFERENCE_INFO.equals(ref)) {
|
|
ByteBuffer buffer = databaseToClean.referencesIO.readFromReference(referenceID);
|
|
newDatabase.referencesIO.writeToReference(referenceID, ref.getCleanerId(), buffer.limit(), buffer);
|
|
writtenReferences++;
|
|
if (buffer.limit() > 0) {
|
|
writtenBlocks++;
|
|
}
|
|
}
|
|
} catch (IOException ex) {
|
|
System.out.println("Error while reading reference " + referenceID + ". References written: " + writtenReferences);
|
|
}
|
|
}
|
|
System.out.println("[Core Cleaner] References written: " + writtenReferences + ". Removed " + (blocksCount - writtenBlocks) + " blocks. Removed " + (referencesCount - writtenReferences) + " references.");
|
|
databaseToClean.close();
|
|
newDatabase.close();
|
|
Files.deleteIfExists(newDataFile);
|
|
Files.deleteIfExists(newBlocksFile);
|
|
Files.deleteIfExists(newReferencesFile);
|
|
}
|
|
}
|