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

Cursor crashes with java.lang.NullPointerException: null #63

Closed
wojsys opened this issue Mar 19, 2018 · 21 comments
Closed

Cursor crashes with java.lang.NullPointerException: null #63

wojsys opened this issue Mar 19, 2018 · 21 comments
Assignees

Comments

@wojsys
Copy link

wojsys commented Mar 19, 2018

java.lang.NullPointerException: null
at org.h2.mvstore.Page.getRawChildPageCount(Page.java:868) ~[h2-mvstore-1.4.196.jar:1.4.196]
at org.h2.mvstore.MVMap.getChildPageCount(MVMap.java:1179) ~[h2-mvstore-1.4.196.jar:1.4.196]
at org.h2.mvstore.Cursor.fetchNext(Cursor.java:149) ~[h2-mvstore-1.4.196.jar:1.4.196]
at org.h2.mvstore.Cursor.next(Cursor.java:50) ~[h2-mvstore-1.4.196.jar:1.4.196]
at org.dizitart.no2.internals.DocumentCursor$DocumentCursorIterator.next(DocumentCursor.java:106) ~[nitrite-2.1.1.jar:na]
at org.dizitart.no2.internals.DocumentCursor$DocumentCursorIterator.next(DocumentCursor.java:92) ~[nitrite-2.1.1.jar:na]
at org.dizitart.no2.objects.ObjectCursor$ObjectCursorIterator.next(ObjectCursor.java:108) ~[nitrite-2.1.1.jar:na]

@anidotnet
Copy link
Contributor

Could you please provide the code to reproduce this error?

@anidotnet
Copy link
Contributor

I could not reproduce this issue. Please provide your response to reproduce this otherwise I have to close this issue.

@wojsys
Copy link
Author

wojsys commented Mar 26, 2018

seems to happen when multiple threads try to access the cursor.

@anidotnet
Copy link
Contributor

Based on your input I have constructed the below test cases, but again I am unable to reproduce this. Could you please try to modify the below test case to match your scenario and reproduce this error?

@Indices({
        @Index(value = "name", type = IndexType.Fulltext)
})
public class PersonEntity {
    @Id
    private String uuid;
    private String name;
    private String status;
    private PersonEntity friend;
    private Date dateCreated;

    public PersonEntity() {
        this.uuid = UUID.randomUUID().toString();
        this.dateCreated = new Date();
    }

    public PersonEntity(String name) {
        this.uuid = UUID.randomUUID().toString();
        this.name = name;
        this.dateCreated = new Date();
    }
	
	// getter and setter...
}

	@Test
    public void testIssue63() throws InterruptedException {
        PersonEntity p1 = new PersonEntity("abcd");
        p1.setStatus("Married");

        PersonEntity p2 = new PersonEntity("efgh");
        p2.setStatus("Married");

        PersonEntity p3 = new PersonEntity("ijkl");
        p3.setStatus("Un-Married");

        ObjectRepository<PersonEntity> repository = db.getRepository(PersonEntity.class);
        repository.insert(p1);
        repository.insert(p2);
        repository.insert(p3);

        final CountDownLatch latch = new CountDownLatch(100);
        ExecutorService executor = Executors.newFixedThreadPool(10);
        final Cursor<PersonEntity> cursor = repository.find();
		
		// now trying to access same cursor from 100 threads
        for (int i = 0; i < 100; i++) {
            executor.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        for (PersonEntity entity : cursor) {
                            assertTrue(entity.getStatus().equals("Married")
                                    || entity.getStatus().equals("Un-Married"));
                        }
                    } catch (Throwable t) {
                        t.printStackTrace();
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }
        latch.await();
    }

@mkagel
Copy link

mkagel commented Mar 27, 2018

I got a similar error on accessing the same cursor from 5 threads:

Exception in thread "Thread-4" 3f6cc9c3-067f-4b18-b734-70fb93cdf435
9f0a846f-5b8d-4c3f-9000-15a642508f55
java.lang.NullPointerException
	at org.h2.mvstore.Page.getRawChildPageCount(Page.java:868)
	at org.h2.mvstore.MVMap.getChildPageCount(MVMap.java:1179)
	at org.h2.mvstore.Cursor.fetchNext(Cursor.java:149)
	at org.h2.mvstore.Cursor.next(Cursor.java:50)
	at org.dizitart.no2.internals.DocumentCursor$DocumentCursorIterator.nextMatch(DocumentCursor.java:115)
	at org.dizitart.no2.internals.DocumentIterator.next(DocumentIterator.java:54)
	at org.dizitart.no2.internals.DocumentIterator.next(DocumentIterator.java:32)
	at org.dizitart.no2.objects.ObjectCursor$ObjectCursorIterator.next(ObjectCursor.java:120)
	at samples.nitriteperformance.TestThreadMultiCursor.run(TestThreadMultiCursor.java:23)
            Nitrite db = Nitrite.builder().compressed().filePath(dbNameMulti).openOrCreate(); //ohne gummi
            ObjectRepository<Region> repRegion = db.getRepository(Region.class);
            final Cursor<Region> cursor = repRegion.find();
 
            TestThreadMultiCursor t1 = new TestThreadMultiCursor(cursor, 1);
            TestThreadMultiCursor t2 = new TestThreadMultiCursor(cursor, 2);
            TestThreadMultiCursor t3 = new TestThreadMultiCursor(cursor, 3);
            TestThreadMultiCursor t4 = new TestThreadMultiCursor(cursor, 4);
            TestThreadMultiCursor t5 = new TestThreadMultiCursor(cursor, 5);

            t1.start();
            t2.start();
            t3.start();
            t4.start();
            t5.start();
public class TestThreadMultiCursor extends Thread {

    Integer threadID;
    Cursor<Region> cursorRegion;

    public TestThreadMultiCursor(Cursor<Region> cursorRegion, Integer threadID) {
        this.threadID = threadID;
        this.cursorRegion = cursorRegion;
    }

    public void run() {  
                  
        System.out.println("Thread " + threadID);

        for (Region t : cursorRegion) {               
           System.out.println(t.regionName);
        }
    }
}

One cursor per threads doesn't work too (error: db already open),
whereas multithreding insert work, see my post
#57

What is the trick?

@anidotnet anidotnet self-assigned this Mar 27, 2018
@anidotnet
Copy link
Contributor

@swissfreedev I have modified your code a bit as follows:

    @Test
    public void testIssue63_2() throws InterruptedException, IOException {
        Nitrite db = Nitrite.builder().compressed().filePath("/tmp/nitrite.db").openOrCreate(); //ohne gummi
        ObjectRepository<PersonEntity> repRegion = db.getRepository(PersonEntity.class);
        PersonEntity p1 = new PersonEntity("abcd");
        p1.setStatus("Married");

        PersonEntity p2 = new PersonEntity("efgh");
        p2.setStatus("Married");

        PersonEntity p3 = new PersonEntity("ijkl");
        p3.setStatus("Un-Married");
        repRegion.insert(p1);
        repRegion.insert(p2);
        repRegion.insert(p3);

        final Cursor<PersonEntity> cursor = repRegion.find();

        CountDownLatch latch = new CountDownLatch(5);
        TestThreadMultiCursor t1 = new TestThreadMultiCursor(cursor, 1, latch);
        TestThreadMultiCursor t2 = new TestThreadMultiCursor(cursor, 2, latch);
        TestThreadMultiCursor t3 = new TestThreadMultiCursor(cursor, 3, latch);
        TestThreadMultiCursor t4 = new TestThreadMultiCursor(cursor, 4, latch);
        TestThreadMultiCursor t5 = new TestThreadMultiCursor(cursor, 5, latch);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        latch.await();

        Files.delete(Paths.get("/tmp/nitrite.db"));
    }

    public class TestThreadMultiCursor extends Thread {

        Integer threadID;
        Cursor<PersonEntity> cursorRegion;
        CountDownLatch latch;

        public TestThreadMultiCursor(Cursor<PersonEntity> cursorRegion, Integer threadID, CountDownLatch latch) {
            this.threadID = threadID;
            this.cursorRegion = cursorRegion;
            this.latch = latch;
        }

        public void run() {
            System.out.println("Thread " + threadID);
            for (PersonEntity t : cursorRegion) {
                System.out.println(threadID + ". " + t.getName());
            }
            latch.countDown();
        }
    }

But still I could not reproduce it.

image

Can you please provide some additional details like - OS, system arch, java version etc?

@mkagel
Copy link

mkagel commented Mar 27, 2018

Hi Anindya,

in my office: win10, netbeans8.2, jdk8, nitrite 2.1.0 I can upload the entire project if it helps?

funny, don't tell me it's again a win10 issue ;-)
Gotta try it at home on suse linux leap 43.2 this evening.
Best regards
Pascal

@anidotnet
Copy link
Contributor

In my experience lots of funny things happen in Windows. This is the reason why I moved away from it long ago for my development and day to day work :). It would help immensely if you can test your code on suse. Meantime I'll test it on my Win10 also. Let's see what happens!

@anidotnet
Copy link
Contributor

Oh @swissfreedev one more thing I just noticed. I see @wojsys and you are running old version of nitrite. Is it possible for you to test it against 2.2.0-SNAPSHOT in Win10?

@mkagel
Copy link

mkagel commented Mar 27, 2018

Ok this time win10 is innocent, I got the exception on suse leap 43.2 as well, next step is the update to 2.2.0, news will follow...

test startet db=datamulti.db
Thread 2
Thread 1
Thread 3
Thread 4
Thread 5
Exception in thread "Thread-5" java.lang.NullPointerException
at org.h2.mvstore.Page.getRawChildPageCount(Page.java:868)
at org.h2.mvstore.MVMap.getChildPageCount(MVMap.java:1179)
at org.h2.mvstore.Cursor.fetchNext(Cursor.java:149)
at org.h2.mvstore.Cursor.next(Cursor.java:50)
at org.dizitart.no2.internals.DocumentCursor$DocumentCursorIterator.nextMatch(DocumentCursor.java:115)
at org.dizitart.no2.internals.DocumentIterator.next(DocumentIterator.java:54)
at org.dizitart.no2.internals.DocumentIterator.next(DocumentIterator.java:32)
at org.dizitart.no2.objects.ObjectCursor$ObjectCursorIterator.next(ObjectCursor.java:120)
at samples.nitriteperformance.TestThreadMultiCursor.run(TestThreadMultiCursor.java:23)
112161fc-2bea-4ced-b271-d8364100c769
etc.

@anidotnet
Copy link
Contributor

Really strange. Can you please upload your sample project here?

@mkagel
Copy link

mkagel commented Mar 28, 2018

here it comes: TestMulti() for creating test entries, TestMultiCursor() for producing the error
I' m curious to hear your statement
NitritePerformanceMin.zip

@anidotnet
Copy link
Contributor

anidotnet commented Mar 28, 2018

I ran it using 2.2.0-SNAPSHOT it went smoothly on ubuntu 17.10 (64-bit) with JDK 1.8.0_102

image

Tried with both nitrite 2.1.0 and 2.1.1, no issues either. I'll try to run it on couple other systems to see if I can reproduce it.

@mkagel
Copy link

mkagel commented Mar 28, 2018

more and more strange, in this case I can omit a random test with snapshot 2.2.0
=> woisys what is your environment ?

@mkagel
Copy link

mkagel commented Mar 28, 2018

by the way, I'm continuously implementing a Nitrite Admin tool based on your Nitrite explorer 2.0.1 and have added some useful custom features, if you are interested I can share it in a couple of week once a stable state is reached...
2018-03-28_1159

@anidotnet
Copy link
Contributor

Superb!!!! I am eager to see the final product. Great job indeed.

@mkagel
Copy link

mkagel commented Mar 28, 2018

for my own usage I basically added: connect /disconnect since nitrite allows just one connection and its weird to get always the "already connected" error while running two programs, remember/load database path in the local preferencies, direct and quick start without intermediate dialogs, and some cosmetical features

I would now like to add an edit mode if this isn't a big deal, and a table sql-like view in studio3t...

@anidotnet
Copy link
Contributor

Another development on this issue. I tried it in my office machine - Ubuntu 14.04 (64-bit) with JDK 1.8.0_102. I can see the NPE while using nitrite 2.1.0, but never encountered this with nitrite 2.1.1 or 2.2.0-SNAPSHOT (tried like 30 times with your uploaded code).

Could you please try your code with 2.2.0-SNAPSHOT as well in your machine and share the result?

@mkagel
Copy link

mkagel commented Mar 28, 2018

yes, I'm curious to see what happens, i'll tell you the results soon

@mkagel
Copy link

mkagel commented Mar 28, 2018

Good news: you are right, I switched to 2.1.1 and 2.2.0 the issue is no more reproducible... so just do not use older versions

@anidotnet
Copy link
Contributor

Great, so I can close this issue. @wojsys please revert back if you are seeing this issue in 2.2.0-SNAPSHOT.

On a separate note @swissfreedev I could not thank you enough for being a backer for this project in https://opencollective.com/nitrite-database. It will surely inspire me a lot more to invest my time in this project. Cheers.

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

No branches or pull requests

3 participants