delight-im / Android-DDP

[UNMAINTAINED] Meteor's Distributed Data Protocol (DDP) for clients on Android
Apache License 2.0
274 stars 54 forks source link

java.util.ConcurrentModificationException if i execute the query #117

Open musriabhijit opened 7 years ago

musriabhijit commented 7 years ago

if i call the Query in side the on data added i am getting the below exception how to solve this one

java.util.ConcurrentModificationException at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:346) at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:375) at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:375) at java.util.HashMap.constructorPutAll(HashMap.java:208) at java.util.LinkedHashMap.(LinkedHashMap.java:133) at im.delight.android.ddp.db.memory.InMemoryCollection$DocumentsMap.(InMemoryCollection.java:0) at im.delight.android.ddp.db.memory.InMemoryQuery.(InMemoryQuery.java:37) at im.delight.android.ddp.db.memory.InMemoryCollection.whereEqual(InMemoryCollection.java:65)

ocram commented 7 years ago

Thanks for your report!

Can you share what you're actually doing in that onDataAdded callback with respect to this library?

musriabhijit commented 7 years ago

if the onDataAdded is called then i calling a method in that method i am writing the query to fetch the user documents but i am getting the about exception at run time in the mongo DB

ocram commented 7 years ago

Sorry, that doesn't really help. It would be necessary to see what exactly you're doing in that callback. Of course, you can and should remove everything that is not related to this library, i.e. all your business logic, etc.

kschingiz commented 7 years ago

I also have encountered this kind of issue. It happened if we are trying to add documents to collection in one thread and iterating over it in another thread at the same time. So I'm just waiting for finishing adding to collection after I start iterating. Maybe your case is the same. You can read about this exception here: https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

ocram commented 7 years ago

@kschingiz Thanks a lot for these additional pieces of information!

It happened if we are trying to add documents to collection in one thread and iterating over it in another thread at the same time.

Are you actually writing to the collections or documents returned by the database? As you can see in the README, writing directly to the database by modifying these collections and documents is not supported, yet. You have to issue calls to the insert, update, delete and call methods, etc.

Nonetheless, the problem may occur just as well if you are iterating over such an object and the library adds new entries because you called such a method. Is this what you're doing and what's happening?

So I'm just waiting for finishing adding to collection after I start iterating.

This seems to be a reasonable workaround. Did it work?

kschingiz commented 7 years ago

@ocram

Nonetheless, the problem may occur just as well if you are iterating over such an object and the library adds new entries because you called such a method. Is this what you're doing and what's happening?

Yes, I didn't say that I am inserting to the database by myself, it's done by library.

ocram commented 7 years ago

@kschingiz I know you didn't. That's why I added another paragraph after that. I just wanted to confirm you really aren't doing this.

As far as I can see, the only thing we can do here is return copies of the actual data instead of the objects themselves. This has a small overhead in memory but allows the library to modify the collections and documents while you are iterating over them.

najeebullahshah commented 7 years ago

@kschingiz how did you know that all documents are added to in memory database and then start iterating them, onDataAdded is called for each document. If i am wrong plz correct me, when onDataAdded receives a document it means that document is already added to in memory database. Each time i get a ping for new document in onDataAdded i fetch the document by querying it like this:

MeteorSingleton.getInstance().getDatabase().getCollection(collectionName).getDocument(documentId)

Am i doing something wrong?

ocram commented 7 years ago

Is the data read and written in different threads here? Do we have to fix synchronization perhaps?

kschingiz commented 7 years ago

@najeebullahshah @ocram Sorry for the late reply, I'm just waiting for 3 seconds after onDataAdded occured, but it's bad solution. So, I have implemented "subscription ready" feature. MeteorJS sends a websocket message like this: "{"msg":"ready","subs":["eiyH2CQiWKa3kQzSJ"]}" I start my business logic only if I get this message. But! in case if you are working with database and at this time MeteorJs sends some data, this exception can occur. I don't know how to fix it. Thank you and sorry for my bad english

ocram commented 7 years ago

@musriabhijit @kschingiz @najeebullahshah Really sorry for not having a solution to this problem available yet!

Still, this could be something that we could do here:

As far as I can see, the only thing we can do here is return copies of the actual data instead of the objects themselves. This has a small overhead in memory but allows the library to modify the collections and documents while you are iterating over them.

@kschingiz Instead of catching the "msg":"ready" message yourself, can you try just adding a new SubscribeListener() {} instance as the third argument to the subscribe method call?

ocram commented 7 years ago

@musriabhijit @kschingiz Please try changing your dependency to

compile 'com.github.delight-im:Android-DDP:d09cbe43f824846a9cb3ad4eecd2fd1b1a8d73b5'

which does two things:

Perhaps that fixes the bug. I don't think that calling Collections#synchronizedMap(java.util.Map) or wrapping all operations in synchronized (...) { ... } is necessary.

najeebullahshah commented 7 years ago

@ocram Thanks man for the update, i've compiled witht he mentioned one, I am hopeful now the issue will be resolved. Much appreciated.

ocram commented 7 years ago

@najeebullahshah For you, personally, the fix from https://github.com/delight-im/Android-DDP/issues/125 is probably more relevant, as that was the issue you reported. Unfortunately, you can only test one of the fixes at a time for now. If both issues are reported as being fixed, we can merge back everything into the main branch.

najeebullahshah commented 7 years ago

Ok let me test upload apk to playstore and see if the exception is reported or not?

ocram commented 7 years ago

@najeebullahshah Yes, let's continue this discussion in the other issue's thread.

This issue here is only relevant for @musriabhijit and @kschingiz who found a different bug.

Gurpreet1809 commented 7 years ago

@ocram Hello Have you tried new SubscribeListener() {} instance as the third argument to the subscribe method call? because i am getting issue with this interface and not able to get a result.

Gurpreet1809 commented 7 years ago

After writing this code: new SubscribeListener() {}, if I'll debug the app that it works perfectly fine and I am getting the response in success() method but if I am running the app then these methods (onSuccess() and onError )are not called. Please help me out. I am using InMemoryDatabase() for creating database within app. Please help me out!

ocram commented 7 years ago

@Gurpreet1809 What are you referring to exactly? Did you want to say that the SubscribeListener (which has been tested, of course) does work fine in the emulator or when debugging the app on a device, but does not work when exported as a signed APK and then executed on a device?

Gurpreet1809 commented 7 years ago

@ocram yupzz exactly !! it works fine in debug mode, but when it is executed on device without debug mode, onSuccess method is not called.

ocram commented 7 years ago

@Gurpreet1809 That could be an issue with obfuscation (i.e. ProGuard) then. Can you check this?