Implemented cleaner
This commit is contained in:
parent
5fb0a8a057
commit
84ec606794
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.warp</groupId>
|
||||
<artifactId>jcwdb</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
|
||||
<name>jcwdb</name>
|
||||
<url>https://git.ignuranza.net/andreacavalli/JCWDB</url>
|
||||
|
@ -3,8 +3,10 @@ package org.warp.cowdb;
|
||||
import org.warp.cowdb.database.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public class Database implements IDatabase, IDatabaseTools {
|
||||
|
||||
@ -15,7 +17,11 @@ public class Database implements IDatabase, IDatabaseTools {
|
||||
private final DatabaseReferencesIO referencesIO;
|
||||
private final DatabaseReferencesMetadata referencesMetadata;
|
||||
private final DatabaseObjectsIO objectsIO;
|
||||
private final Path dataFile;
|
||||
private final Path blocksMetaFile;
|
||||
private final Path referencesMetaFile;
|
||||
private EnhancedObject loadedRootObject;
|
||||
private volatile boolean closed;
|
||||
|
||||
public Database(Path dataFile, Path blocksMetaFile, Path referencesMetaFile) throws IOException {
|
||||
if (Files.notExists(dataFile)) {
|
||||
@ -27,6 +33,9 @@ public class Database implements IDatabase, IDatabaseTools {
|
||||
if (Files.notExists(referencesMetaFile)) {
|
||||
Files.createFile(referencesMetaFile);
|
||||
}
|
||||
this.dataFile = dataFile;
|
||||
this.blocksMetaFile = blocksMetaFile;
|
||||
this.referencesMetaFile = referencesMetaFile;
|
||||
this.databaseTools = this;
|
||||
this.fileIO = new DatabaseFileIO(dataFile);
|
||||
this.blocksMetadata = new DatabaseBlocksMetadata(blocksMetaFile);
|
||||
@ -37,11 +46,61 @@ public class Database implements IDatabase, IDatabaseTools {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
public synchronized void close() throws IOException {
|
||||
if (this.closed) {
|
||||
throw new IOException("The database has been already closed!");
|
||||
}
|
||||
this.objectsIO.setEnhancedObject(0, loadedRootObject);
|
||||
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);
|
||||
Database databaseToClean = new Database(newDataFile, newBlocksFile, newReferencesFile);
|
||||
Database newDatabase = new Database(dataFile, blocksMetaFile, referencesMetaFile);
|
||||
|
||||
long referencesCount = databaseToClean.referencesMetadata.getFirstFreeReference();
|
||||
long blocksCount = databaseToClean.blocksMetadata.getTotalBlocksCount();
|
||||
long writtenReferences = 0;
|
||||
|
||||
for (int referenceID = 0; referenceID < referencesCount; referenceID++) {
|
||||
try {
|
||||
ByteBuffer buffer = databaseToClean.referencesIO.readFromReference(referenceID);
|
||||
newDatabase.referencesIO.writeToReference(referenceID, buffer.limit(), buffer);
|
||||
writtenReferences++;
|
||||
} catch (IOException ex) {
|
||||
System.out.println("Error while reading reference " + referenceID + ". References written: " + writtenReferences);
|
||||
}
|
||||
}
|
||||
System.out.println("References written: " + writtenReferences + ". Removed " + (blocksCount - writtenReferences) + " blocks. Removed " + (referencesCount - writtenReferences) + " references.");
|
||||
databaseToClean.close();
|
||||
newDatabase.close();
|
||||
Files.deleteIfExists(newDataFile);
|
||||
Files.deleteIfExists(newBlocksFile);
|
||||
Files.deleteIfExists(newReferencesFile);
|
||||
}
|
||||
|
||||
public <T extends EnhancedObject> T loadRoot(Class<T> type, FunctionWithIO<IDatabaseTools, T> ifAbsent) throws IOException {
|
||||
|
@ -42,4 +42,10 @@ public interface IBlocksMetadata {
|
||||
* Close file
|
||||
*/
|
||||
void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Get total count of blocks
|
||||
* @return
|
||||
*/
|
||||
long getTotalBlocksCount();
|
||||
}
|
||||
|
@ -5,4 +5,8 @@ import java.io.IOException;
|
||||
public interface IDatabase {
|
||||
|
||||
void close() throws IOException;
|
||||
|
||||
boolean isClosed();
|
||||
|
||||
void closeAndClean() throws IOException;
|
||||
}
|
||||
|
@ -75,4 +75,9 @@ public class DatabaseBlocksMetadata implements IBlocksMetadata {
|
||||
data.flip();
|
||||
return metaFileChannel.write(data, blockId * BLOCK_META_BYTES_COUNT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalBlocksCount() {
|
||||
return firstFreeBlock;
|
||||
}
|
||||
}
|
||||
|
88
src/test/java/org/warp/jcwdb/tests/Clean.java
Normal file
88
src/test/java/org/warp/jcwdb/tests/Clean.java
Normal file
@ -0,0 +1,88 @@
|
||||
package org.warp.jcwdb.tests;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.warp.cowdb.EnhancedObject;
|
||||
import org.warp.cowdb.IDatabaseTools;
|
||||
import org.warp.jcwdb.ann.DBDataType;
|
||||
import org.warp.jcwdb.ann.DBField;
|
||||
import org.warp.jcwdb.ann.DBPropertyGetter;
|
||||
import org.warp.jcwdb.ann.DBPropertySetter;
|
||||
import org.warp.jcwdb.utils.NTestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Clean {
|
||||
private NTestUtils.WrappedDb db;
|
||||
private RootTwoClasses root;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
db = NTestUtils.wrapDb().create((db) -> {
|
||||
root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
|
||||
});
|
||||
root.class1 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class1);
|
||||
root.class2 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class2);
|
||||
root.setClass3(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass3());
|
||||
root.setClass4(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass4());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMatchMultipleEnhancedObjects() throws IOException {
|
||||
db.testRootClassValues(root.class1);
|
||||
db.testRootClassValues(root.class2);
|
||||
db.testRootClassValues(root.getClass3());
|
||||
db.testRootClassValues(root.getClass4());
|
||||
db.get().closeAndClean();
|
||||
db = NTestUtils.wrapDb().create((db) -> {
|
||||
root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
db.delete();
|
||||
}
|
||||
|
||||
public static class RootTwoClasses extends EnhancedObject {
|
||||
|
||||
@DBField(id = 0, type = DBDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class1;
|
||||
|
||||
@DBField(id = 1, type = DBDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class2;
|
||||
|
||||
public RootTwoClasses() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RootTwoClasses(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@DBPropertyGetter(id = 0, type = DBDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass3() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DBPropertySetter(id = 0, type = DBDataType.ENHANCED_OBJECT)
|
||||
public void setClass3(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
|
||||
@DBPropertyGetter(id = 1, type = DBDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass4() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DBPropertySetter(id = 1, type = DBDataType.ENHANCED_OBJECT)
|
||||
public void setClass4(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user