2011-10-29 2 views
1

Le code suivant provoque Java segmentation fault:Pourquoi la création d'une neo4j.GraphDatabase à partir d'une application Coller provoque-t-elle un segfault?

import os.path 
import neo4j 
from paste import httpserver, fileapp 
import tempfile 
from webob.dec import wsgify 
from webob import Response, Request 

HOST = '127.0.0.1' 
PORT = 8080 

class DebugApp(object): 
    @wsgify 
    def __call__(self, req): 

     # db = neo4j.GraphDatabase(tempfile.mkdtemp()) 
     db = neo4j.GraphDatabase(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data')) 
     return Response(body='it worked') 

def main(): 
    app = DebugApp() 
    httpserver.serve(app, host=HOST, port=PORT) 

if __name__ == '__main__': 
    main() 

Reproduire, d'abord enregistrer ce code dans un fichier (par exemple, app.py), puis exécutez python app.py. Ensuite, essayez http://localhost:8080 dans votre navigateur; vous devriez voir le gestionnaire d'incident Java.

Le haut de la trace de la pile Java ressemble à ceci:

Stack: [0xb42e7000,0xb4ae8000], sp=0xb4ae44f0, free space=8181k 
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) 
C [_jpype.so+0x26497] JPJavaEnv::NewObjectA(_jclass*, _jmethodID*, jvalue*)+0x37 
C [_jpype.so+0x3c0e8] JPMethodOverload::invokeConstructor(_jclass*, std::vector<HostRef*, std::allocator<HostRef*> >&)+0x178 
C [_jpype.so+0x3a417] JPMethod::invokeConstructor(std::vector<HostRef*, std::allocator<HostRef*> >&)+0x47 
C [_jpype.so+0x1beba] JPClass::newInstance(std::vector<HostRef*, std::allocator<HostRef*> >&)+0x2a 
C [_jpype.so+0x67b9c] PyJPClass::newClassInstance(_object*, _object*)+0xfc 
C [python+0x96822] PyEval_EvalFrameEx+0x4332 
C [python+0x991e7] PyEval_EvalCodeEx+0x127 

Je crois que ce neo4j.GraphDatabase en Python déclenchement JPype pour aller chercher EmbeddedGraphDatabase dans Neo4j, sous Java.

L'exécution de ce code dans une session interactive Python n'a pas segmentation fault:

>>> import webob 
>>> import app 
>>> debug_app = app.DebugApp() 
>>> response = debug_app(webob.Request.blank('/')) 
>>> response.body 
'it worked' 

On peut supposer que parce que je suis tout à fait d'éviter Coller dans cet exemple. Peut-être cela a-t-il quelque chose à voir avec l'utilisation par Paste de threads qui entravent le développement de neo4j? J'ai noté un problème quelque peu similaire dans les forums neo4j: http://neo4j-community-discussions.438527.n3.nabble.com/Neo4j-CPython-Pylons-and-threading-td942435.html

... mais cela ne se produit que lors de l'arrêt.

+0

Utilisez-vous les nouvelles liaisons Python, info ici: http://docs.neo4j.org/chunked/snapshot/python-embedded.html? – nawroth

+0

Oui, ce sont les liens que j'utilise. – marmida

Répondre

3

Le problème ne concerne pas Coller en soi, mais les liaisons Python neo4j, qui utilisent JPype. Coller crée des threads pour gérer les demandes entrantes; Neo4j est censé être thread-safe, mais JPype vient avec cette mise en garde de la documentation (1):

« Pour la plupart, les fils de python à base de fils de niveau OS (c.-à-threads POSIX), fonctionneront sans La seule chose à retenir est d'appeler jpype.attachThreadToJVM() dans le corps du thread pour rendre la JVM utilisable à partir de ce thread.Pour les threads que vous ne démarrez pas vous-même, vous pouvez appeler isThreadAttachedToJVM() pour vérifier. "

Je ne pouvais pas trouver le code qui fait cela, mais je pense que certains du code Java dans les liaisons Neo4j peuvent appeler attachThreadToJVM au moment de l'importation. Si tel est le cas, lorsqu'une requête est transmise à un worker thread par paste, et que ce thread va alors chercher des données à partir de neo4j, il traverse des limites de thread, et la règle de rattachement JVM peut ne pas être satisfaite.

Vous pouvez éviter le blocage en exécutant uniquement import neo4j à partir d'un seul thread. Dans le cas ci-dessus, il s'agit de l'appelable visé par threading.Thread. Malheureusement, cela signifie que même si neo4j est thread-safe, il doit être contraint à un seul thread lorsqu'il est utilisé à partir de Python. Mais ce n'est pas trop décevant, compte tenu.

Mise à jour: les mainteneurs ont répondu (2) et ont étudié le problème et vérifié un correctif. Je ne sais pas quelle version de neo4j était disponible, et je ne peux plus trouver le commit dans leur repo github (3), donc ça veut dire re-testing.

+0

Bienvenue dans StackOverflow. Vous pouvez/devriez marquer cette réponse comme acceptée afin que les autres sachent qu'il existe une solution. –

Questions connexes