Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failed to deserialize SerializerPojo #261

Closed
jrumbinas opened this issue Jan 10, 2014 · 30 comments
Closed

Failed to deserialize SerializerPojo #261

jrumbinas opened this issue Jan 10, 2014 · 30 comments
Labels

Comments

@jrumbinas
Copy link

Here's a little background. I have a DB with 5m records (15GB).
Then 53k records are inserted. After insertion I try to reopen DB in read-only mode (on the same thread) and this exception is thrown.
I can repeat this every time I do massive insert.
Tested on master (519f779)
Update: committing and compacting after insert (before re-open) works perfectly however this doesn't fix the situation

DBMaker dbmaker = DBMaker
        .newFileDB(path.toFile())
        .closeOnJvmShutdown();
        .transactionDisable();
        .cacheSize(32768)
        .mmapFileEnablePartial()
        .cacheLRUEnable()
        .fullChunkAllocationEnable();

db.createTreeMap(MAIN_TREE_MAP)
            .counterEnable()
            .valuesOutsideNodesEnable()
            .makeOrGet();

Exception in thread "main" java.lang.IndexOutOfBoundsException
    at java.nio.Buffer.checkIndex(Buffer.java:532)
    at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:139)
    at org.mapdb.DataInput2.readUnsignedByte(DataInput2.java:74)
    at org.mapdb.DataInput2.unpackInt(DataInput2.java:142)
    at org.mapdb.SerializerBase.deserializeString(SerializerBase.java:802)
    at org.mapdb.DataInput2.readUTF(DataInput2.java:131)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:74)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:39)
    at org.mapdb.Store.deserialize(Store.java:270)
    at org.mapdb.StoreDirect.get2(StoreDirect.java:456)
    at org.mapdb.StoreDirect.get(StoreDirect.java:409)
    at org.mapdb.Store.getSerializerPojo(Store.java:86)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.DB.<init>(DB.java:82)
    at org.mapdb.DBMaker.make(DBMaker.java:599)
@jrumbinas
Copy link
Author

Calling these lines before closing fixes the problem:

SerializerPojo serializer = db.getEngine().getSerializerPojo();
serializer.save(db.getEngine());

Update: Calling this resulted in another exception:

Exception in thread "main" java.lang.AssertionError: data were not fully read, check your serializer 
    at org.mapdb.Store.deserialize(Store.java:272)
    at org.mapdb.StoreDirect.get2(StoreDirect.java:456)
    at org.mapdb.StoreDirect.get(StoreDirect.java:409)
    at org.mapdb.EngineWrapper.get(EngineWrapper.java:59)
    at org.mapdb.Caches$LRU.get(Caches.java:69)
    at org.mapdb.BTreeMap.valExpand(BTreeMap.java:606)
    at org.mapdb.BTreeMap.remove2(BTreeMap.java:954)
    at org.mapdb.BTreeMap.remove(BTreeMap.java:926)

@jankotek
Copy link
Owner

How is DB closed on first run? Do
you call db.close() or is it done by
JVM shutdown hook?

@jrumbinas
Copy link
Author

if (!db.isClosed()) {
    db.close();
}
db = open(readOnly);

@jrumbinas
Copy link
Author

Just tested with 519f779 (recreated whole DB)
Note: class name is \u0000!

Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: �
    at org.mapdb.SerializerPojo.classForName(SerializerPojo.java:95)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:74)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:39)
    at org.mapdb.Store.deserialize(Store.java:270)
    at org.mapdb.StoreDirect.get2(StoreDirect.java:456)
    at org.mapdb.StoreDirect.get(StoreDirect.java:409)
    at org.mapdb.Store.getSerializerPojo(Store.java:86)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.DB.<init>(DB.java:82)
    at org.mapdb.DBMaker.make(DBMaker.java:599)
    at com.r9.atlas.util.MapDB.open(MapDB.java:164)
    at com.r9.atlas.util.MapDB.reopen(MapDB.java:184)
    at com.r9.atlas.util.MapDB.applyChanges(MapDB.java:343)

@jrumbinas
Copy link
Author

The strangest thing is that SerializerPojo state doesn't change at all (I've manually checked registered class array)

@jrumbinas
Copy link
Author

I found an actual record, which if added will cause this exception to happen. Only a single instance of GroupedData object containing 106 HotelDescriptionPhoto items. It must be related to storage format change.
In this particular case serialized object takes 11kb.

public class GroupedData implements Serializable {
    private final ArrayList<T> items;

    public GroupedData(List<T> items) {
        if (items == null || items.isEmpty()){
            throw new IllegalArgumentException();
        }
        this.items = new ArrayList<>(items.size());
        this.items.addAll(items);
    }
public class HotelDescriptionPhoto implements Serializable {
    public final Integer hotel_id;
    public final Integer photo_id;
    public final Integer descriptiontype_id;
    public final String url_max300;
    public final String url_original;
    public final String url_square60;
}

@jrumbinas
Copy link
Author

I've filtered the data and inserted only small bunch of records. This resulted in the same exception but with different className

Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: �㢈Of
    at org.mapdb.SerializerPojo.classForName(SerializerPojo.java:95)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:74)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:39)
    at org.mapdb.Store.deserialize(Store.java:270)
    at org.mapdb.StoreDirect.get2(StoreDirect.java:456)
    at org.mapdb.StoreDirect.get(StoreDirect.java:409)
    at org.mapdb.Store.getSerializerPojo(Store.java:86)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.DB.<init>(DB.java:82)
    at org.mapdb.DBMaker.make(DBMaker.java:599)
    at com.r9.atlas.util.MapDB.open(MapDB.java:163)
    at com.r9.atlas.util.MapDB.reopen(MapDB.java:183)
    at com.r9.atlas.util.MapDB.applyChanges(MapDB.java:335)

@jrumbinas
Copy link
Author

I found another test cases when two simple classes (no list) result in the following exception:

public class HotelDescriptionTranslation implements Serializable {
    public final Integer hotel_id;
    public final Integer descriptiontype_id;
    public final String description;
    public final String languagecode;
}

Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: �������쀢.parsers.hotels.BookingUtils.model.Hotel����address��java.lang.Stringch
    at org.mapdb.SerializerPojo.classForName(SerializerPojo.java:95)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:74)
    at org.mapdb.SerializerPojo$1.deserialize(SerializerPojo.java:39)
    at org.mapdb.Store.deserialize(Store.java:270)
    at org.mapdb.StoreDirect.get2(StoreDirect.java:456)
    at org.mapdb.StoreDirect.get(StoreDirect.java:409)
    at org.mapdb.Store.getSerializerPojo(Store.java:86)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.DB.<init>(DB.java:82)
    at org.mapdb.DBMaker.make(DBMaker.java:599)
    at com.r9.atlas.util.MapDB.open(MapDB.java:164)
    at com.r9.atlas.util.MapDB.reopen(MapDB.java:184)
    at com.r9.atlas.util.MapDB.applyChanges(MapDB.java:336)

@jrumbinas
Copy link
Author

Maybe it has something to do with string encoding? We do have text translated in various languages.

@jankotek
Copy link
Owner

MapDB has central class catalog, which stores class names and class structure. It looks like that record got corrupted or overwritten by some other data. I will try to fix it now.

@jankotek
Copy link
Owner

MapDB supports crc32 checksums. Perhaps enable this option to get better error message:

  DBMaker.checksumEnable()

jankotek added a commit that referenced this issue Jan 14, 2014
@jankotek
Copy link
Owner

I have trouble to replicate this issue. Could you:

  1. run your scenario with checksum enabled? I think it could produce more meaning full error message.

  2. checkout this test case, perhaps it needs more settings? I run this example twice, second time with read-only mode enabled.
    https://github.com/jankotek/MapDB/blob/dd39d3c56c2c53e38e85c38e4381a20f7488bc93/src/test/java/org/mapdb/Issues261Test.java

@jrumbinas
Copy link
Author

1st option doesn't help much. DB has 4926540 records, one was added and after reopen I get this:

Exception in thread "main" java.io.IOError: java.io.IOException: Checksum does not match, data broken
    at org.mapdb.StoreDirect.get(StoreDirect.java:411)
    at org.mapdb.Store.getSerializerPojo(Store.java:86)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.EngineWrapper.getSerializerPojo(EngineWrapper.java:123)
    at org.mapdb.DB.<init>(DB.java:82)
    at org.mapdb.DBMaker.make(DBMaker.java:599)
    at com.r9.atlas.util.MapDB.open(MapDB.java:163)
    at com.r9.atlas.util.MapDB.reopen(MapDB.java:183)
    at com.r9.atlas.util.MapDB.applyChanges(MapDB.java:335)

@jrumbinas
Copy link
Author

Unfortunately I'm unable to reproduce this bug in test environment. With 0.9.8 I get the very same error.
Is there anything else I could try? Any Ideas?

@jankotek
Copy link
Owner

1st option helps to isolate problem. I have about 5 theories, it will probably take a week to fix this.

@jankotek
Copy link
Owner

I think enabling transaction could work-around this problem.

@jrumbinas
Copy link
Author

PojoSerializer contains 17 classes. Tuple2 is used as a key: 1st value is hotel ID, 2nd auto pk counter. This results in data sorted by hotel ID. Data is inserted in 8 passes. In the resulting tree single hotel has up to 1000 objects (mean is about 50)

@jrumbinas
Copy link
Author

Enabling transactions actually did not helped to workaround the issue :/
Please let me know when I can test if this bug is fixed for sure.

@jankotek
Copy link
Owner

I have no idea howto reproduce this issue

@jankotek
Copy link
Owner

Perhaps if you could send me your full dataset with code to reproduce it.

@jrumbinas
Copy link
Author

I'm sorry, but the data I'm using is confidential. Have you checked all five theories?

@jankotek
Copy link
Owner

Yes, no luck. For now I think that file failed to sync on last close and some data were not written to disk.

@jankotek
Copy link
Owner

One more thing: would you ran your test with assertions enabled (-ea command line switch). This could catch some issues early.

@jrumbinas
Copy link
Author

Apparently the -ea flag was set by IntelliJ so no luck about it too :/

@jankotek
Copy link
Owner

Hallelujah.

I think I found problem. There was typo and class catalog in SerializerPojo would not be saved when database closed. I am 99% sure this is now fixed in trunk. 0.9.10 with this fix will be released in 2 days.

@jrumbinas
Copy link
Author

Thanks, I'll give it a shot on Monday :)

@jrumbinas
Copy link
Author

Seems like the issue is gone, nice job!

@jrumbinas
Copy link
Author

P.s. do you have a unit test to check this?

@jankotek
Copy link
Owner

I do, but it runs longer, so is not inside mapdb project. I have burn tests
which verify this type of stuff

On Monday, February 17, 2014 05:32:53 Justinas wrote:

P.s. do you have a unit test to check this?

@jankotek
Copy link
Owner

MapDB 0.9.10 is out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants