Skip to content

Commit

Permalink
Fix crash and data corruption during 1.5 => 2.0 transition
Browse files Browse the repository at this point in the history
  • Loading branch information
pilgr committed Sep 21, 2017
1 parent cc1fcc8 commit 408164c
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void setUp() throws Exception {
public void testWrite() {
Recipe recipe = new Recipe();
recipe.name = "chocolate cake";
recipe.ingredients = new HashMap<String, Integer>();
recipe.ingredients = new HashMap<>();
recipe.ingredients.put("flour", 300);
recipe.ingredients.put("eggs", 4);
recipe.ingredients.put("chocolate", 200);
Expand All @@ -41,6 +41,7 @@ public void testWrite() {
public void testRead() throws IOException {
File filesDir = new File(getTargetContext().getFilesDir(), "io.paperdb");
if (!filesDir.exists()) {
//noinspection ResultOfMethodCallIgnored
filesDir.mkdirs();
}

Expand All @@ -51,13 +52,12 @@ public void testRead() throws IOException {

Recipe recipe = Paper.book().read("recipe");
assertThat(recipe.name).isEqualTo("chocolate cake");

}

private void copyFile(InputStream inputStream, OutputStream outputStream) throws IOException {
byte buffer[] = new byte[2048];

while(true) {
while (true) {
int r = inputStream.read(buffer);
if (r < 0) {
break;
Expand Down
55 changes: 30 additions & 25 deletions paperdb/src/main/java/io/paperdb/DbStoragePlainFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,17 @@ private Kryo getKryo() {
private final ThreadLocal<Kryo> mKryo = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
return createKryoInstance();
return createKryoInstance(false);
}
};

private Kryo createKryoInstance() {
private Kryo createKryoInstance(boolean compatibilityMode) {
Kryo kryo = new Kryo();

if (compatibilityMode) {
kryo.getFieldSerializerConfig().setOptimizedGenerics(true);
}

kryo.register(PaperTable.class);
kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
kryo.setReferences(false);
Expand Down Expand Up @@ -245,40 +249,41 @@ private <E> void writeTableFile(String key, PaperTable<E> paperTable,
}

private <E> E readTableFile(String key, File originalFile) {
return readTableFile(key, originalFile, false);
}

private <E> E readTableFile(String key, File originalFile,
boolean v1CompatibilityMode) {
try {
final Input i = new Input(new FileInputStream(originalFile));
final Kryo kryo = getKryo();
if (v1CompatibilityMode) {
// Set temporary generic optimization to support Kryo 3.x format
kryo.getFieldSerializerConfig().setOptimizedGenerics(true);
}
//noinspection unchecked
final PaperTable<E> paperTable = kryo.readObject(i, PaperTable.class);
i.close();
if (v1CompatibilityMode) {
kryo.getFieldSerializerConfig().setOptimizedGenerics(false);
}
return paperTable.mContent;
return readContent(originalFile, getKryo());
} catch (FileNotFoundException | KryoException | ClassCastException e) {
// Give one more chance, reread data in compatibility mode
if (!v1CompatibilityMode) {
return readTableFile(key, originalFile, true);
Throwable exception = e;
// Give one more chance, read data in paper 1.x compatibility mode
if (e instanceof KryoException) {
try {
return readContent(originalFile, createKryoInstance(true));
} catch (FileNotFoundException | KryoException | ClassCastException compatibleReadException) {
exception = compatibleReadException;
}
}
// TODO Delete this
// Clean up an unsuccessfully written file
if (originalFile.exists()) {
if (!originalFile.delete()) {
throw new PaperDbException("Couldn't clean up broken/unserializable file "
+ originalFile, e);
+ originalFile, exception);
}
}
String errorMessage = "Couldn't read/deserialize file "
+ originalFile + " for table " + key;
throw new PaperDbException(errorMessage, e);
throw new PaperDbException(errorMessage, exception);
}
}

private <E> E readContent(File originalFile, Kryo kryo) throws FileNotFoundException, KryoException {
final Input i = new Input(new FileInputStream(originalFile));
//noinspection TryFinallyCanBeTryWithResources
try {
//noinspection unchecked
final PaperTable<E> paperTable = kryo.readObject(i, PaperTable.class);
return paperTable.mContent;
} finally {
i.close();
}
}

Expand Down

0 comments on commit 408164c

Please sign in to comment.