Почему создание neo4j.GraphDatabase из приложения Paste вызывает segfault? - PullRequest
1 голос
/ 30 октября 2011

Следующий код вызывает Java к 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()

Для воспроизведения сначала сохраните этот код в файл (скажем, app.py), а затем запустите python app.py. Затем попробуйте http://localhost:8080 в вашем браузере; вы должны увидеть обработчик сбоя Java.

Вершина трассировки стека Java выглядит следующим образом:

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

Я полагаю, что в Python neo4j.GraphDatabase вызывает JPype для поиска EmbeddedGraphDatabase в neo4j под Java.

Выполнение этого кода в интерактивном сеансе Python не вызывает ошибки:

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

Предположительно, это потому, что я вообще избегаю Пасту в этом примере. Возможно, это как-то связано с тем, что Paste использует потоки, мешающие neo4j? Я заметил похожую проблему на форумах neo4j: http://neo4j -community-discussions.438527.n3.nabble.com / Neo4j-CPython-Pylons-and-threading-td942435.html

... но это происходит только при выключении.

1 Ответ

3 голосов
/ 01 ноября 2011

Проблема не в вставке как таковой, а в привязках Python neo4j, использующих JPype.Paste создает потоки для обработки входящих запросов;Предполагается, что neo4j является поточно-ориентированным, но JPype содержит следующее предупреждение из документации ( 1 ):

"По большей части потоки Python основаны на потоках уровня ОС(т.е. потоки posix), будут работать без проблем. Единственное, что нужно запомнить, это вызвать jpype.attachThreadToJVM () в теле потока, чтобы сделать JVM пригодной для использования из этого потока. Для потоков, которые вы не запускаете самостоятельно, вы можете вызвать isThreadAttachedToJVM() для проверки. "

Я не смог найти код, который делает это, но я думаю, что часть кода Java в привязках neo4j может вызвать attachThreadToJVM во время импорта.Если это так, то когда запрос передается рабочему потоку путем вставки, а затем этот поток переходит к извлечению данных из neo4j, он пересекает границы потока, и правило присоединения JVM может не выполняться.

Вы можетеизбежать сбоев, только запустив import neo4j из одного потока.В приведенном выше случае это - вызываемый объект, предназначенный для threading.Thread.

К сожалению, это означает, что, хотя neo4j является поточно-ориентированным, он должен быть ограничен одним потоком при использовании из Python.Но это не слишком разочаровывает, учитывая.

Обновление : сопровождающие ответили ( 2 ) и исследовали проблему и проверили исправление.Я не знаю, в каком выпуске neo4j это было доступно, и я больше не могу найти коммит для их репозитория github ( 3 ), так что это означает повторное тестирование.

...