2011-02-06 6 views
1

J'essaie de parcourir toutes les lignes ("documents"?) Dans ma base de données MongoDB en utilisant Morphia. De temps en temps, je reçois le stacktrace suivant:Morphia/MongoDB: impossible de faire getmore

com.mongodb.MongoInternalException: can't do getmore 
    at com.mongodb.DBApiLayer$Result._advance(DBApiLayer.java:378) 
    at com.mongodb.DBApiLayer$Result.hasNext(DBApiLayer.java:356) 
    at com.mongodb.DBCursor._hasNext(DBCursor.java:436) 
    at com.mongodb.DBCursor.hasNext(DBCursor.java:456) 
    at com.google.code.morphia.query.MorphiaIterator.hasNext(MorphiaIterator.java:40) 
    at 

Dans le fichier journal MongoDB je vois ce qui suit:

$ grep "cursorid not found" output.log 
Sun Feb 6 12:14:35 [conn13] getMore: cursorid not found App 2079575931792020691 
Sun Feb 6 12:44:17 [conn19] getMore: cursorid not found App 8364953818630631317 
Sun Feb 6 13:08:42 [conn20] getMore: cursorid not found App 7142256996888968009 

Mon code pour itérer est assez simple:

for (App app : datastore.createQuery(App.class).fetch()) 
    { 
     log.info("app: " + app.getId()); 
     // do stuff with app 
    } 

bug Morphia? Bug MongoDB? Mon bug?

Mise à jour:

Je vois aussi dans mes journaux GlassFish:

[#|2011-02-16T15:39:58.029+0000|WARNING|glassfish3.0.1|com.mongodb.TRACE|_ThreadID=28;_ThreadName=Thread-1;|The log message is null. 
java.lang.NullPointerException 
    at com.mongodb.DBApiLayer._cleanCursors(DBApiLayer.java:113) 
    at com.mongodb.DBApiLayer$DBCleanerThread.run(DBApiLayer.java:494) 
    at java.lang.Thread.run(Thread.java:662) 

Répondre

1

Juste couru dans le même problème tout en itérant à travers une très grande requête. J'ai trouvé ce bogue Morphia, a rapporté le 21 mars 2011:

http://code.google.com/p/morphia/issues/detail?id=251

Problème 251: activer/délai d'attente désactiver fait le contraire de ce qu'il dit

La question dit que ce sera corrigé dans la version 1.0. La nouvelle API disableCursorTimeout() est exposée dans 1.00-SNAPHSHOT. J'exécute un test long pour voir s'il résout le problème.

1

Comme vous pouvez le voir dans cette thread MongoDB libère le curseur après un certain laps de temps. Une solution possible pourrait être d'émuler l'itération par lots et de renouveler le curseur au début et à la fin du cycle.

1

Est-ce le code actuel? Il semble très improbable que ce code produise cette exception. Le délai d'expiration des curseurs est de 10 minutes d'inactivité. Avec une boucle serrée comme ça, cela semble impossible.

Vous pouvez utiliser datastore.createQuery(App.class).disableTimeout()... pour désactiver le délai d'attente du curseur dans Morphia. Vous pouvez également utiliser datastore.createQuery(App.class).fetchEmptyEntities() si vous voulez juste le champ @Id rempli

En outre, il n'y a pas besoin d'appeler explicitement fetch() si vous voulez juste utiliser l'itérateur dans une boucle for comme ça. fetch est juste nécessaire lorsque vous voulez stocker l'itérateur dans une variable et l'utiliser à plusieurs endroits, mais pas dans une seule boucle for.

+0

J'ai essayé de simplifier le code autant que possible en posant ma question, donc vous avez raison d'oublier des informations potentiellement utiles. Qu'est-ce qui se passe dans "faire des choses avec l'application" est: interroger un service Web et enregistrer les résultats dans un fichier sur le disque. Cela s'exécute généralement en millisecondes, mais je vais ajouter quelques vérifications de temps à la boucle et voir s'il n'y a pas de comportement anormal là-bas qui provoque le délai d'expiration. Merci. –

+0

Juste fait quelques tours de test, et a appris que le délai d'attente se passe 45 minutes dans le processus d'itération, et c'est reproductible. Notez que chaque passage à travers ma boucle d'itération est typiquement <1 seconde, donc il semble être un délai d'attente sur le processus d'itération global, et non le délai entre chaque appel à Iterator.next(). –

+0

Ce n'est pas si simple. Le curseur, itérateur, récupère des données par lots à partir du serveur; chaque appel à next() peut, ou ne peut pas réellement (les tailles de lots peuvent être 200+), doivent parler au serveur. Avez-vous essayé l'option disableTimeout? –