what used una relaciones para pagina oficial modificar grafos grafo for datos crear como bases transactions neo4j cypher node-neo4j

transactions - used - ¿Las transacciones de cifrado de neo4j están rotas?



neo4j pagina oficial (1)

TL; DR: Me estoy volviendo loco o las transacciones de neo4j están ligeramente rotas. Parece que los nodos no comprometidos están disponibles fuera de las transacciones comprometidas, con propiedades faltantes o algo igualmente extraño.

Nuestra aplicación node.js usa neo4j. Una parte de esto tiene que generar identificaciones únicas. Tenemos la siguiente consulta de cifrado que pretende ubicar el último :Id type node e intento de confirmar un nuevo nodo :Id con last_uuid+1 .

MATCH (i:Id) WITH i ORDER BY i.uuid DESC LIMIT 1 #with it like a sub-return, will "run" the rest with the last i at read-time CREATE (n:Id {label:"Test"}) SET n.uuid = i.uuid + 1 RETURN n

También hay una restricción:

neo4j-sh (?)$ schema Indexes ON :Id(uuid) ONLINE (for uniqueness constraint) Constraints ON (id:Id) ASSERT id.uuid IS UNIQUE

Y el DB se inicializa con un (:Id{uuid:1}) para poner en marcha esta alegría.

El código de la aplicación básicamente reintenta la consulta anterior hasta que tenga éxito. Si dos o más solicitudes de creación de Id tocan al mismo tiempo, solo una de ellas pasará, el resto fallará y el código de la aplicación volverá a intentarlo.

Esto funcionó, hasta que lo intentamos en paralelo.

El código comenzó a devolver datos sin un uuid. Después de mucha investigación, resulta que la parte de escritura de la consulta (CREAR ...) está de alguna manera recibiendo un: Id de MATCH que no tiene propiedades .uuid (u otras). Esto no debería ser posible. Este es el único código que opera en esos nodos.

Lo más extraño (tal vez), es que si nodeid para localizar ese nodo en el DB, realmente existe y tiene una propiedad .uuid.

Para aislar este comportamiento, escribí un PoC: neo4j-transaction-test. Debe ser realmente simple ejecutar con nodejs.

Básicamente es un poquito más que el código anterior: intenta crear el Id, estableciendo la prev_label , el valor prev_nodeid y el prev_uuid previo en los valores del nodo (i) anterior. Ejecuta la consulta para cada solicitud GET que recibe en localhost: 9339 y salidas:

> node server.js * 1412125626667 Listening on 9339 Req Id | Datetime | -> $uuid $nodeid 1 1412125631677 ''GET'' # When it first receives the GET request 1 1412125631710 ''->'' 9 60 # When neo4j returns; numbers are $uuid $node_id)

cuando las cosas comienzan a ser concurrentes, las consultas pueden fallar:

3 1412125777096 ''(retry) (0)'' ''Node 64 already exists with label Id and property "uuid"=[13]'' 4 1412125777098 ''(retry) (0)'' ''Node 64 already exists with label Id and property "uuid"=[13]'' de[]

lo cual es de esperar, y se vuelven a intentar. Si "golpeamos" el servidor con un par de preguntas por segundo ( ab -n 1000 -c 10 http://localhost:9339/ ), eventualmente veremos:

... 59 1412127103011 ''GET'' 23 1412127103024 ''ERROR - EMPTY UUID'' ''{"this_nodeid":22,"prev_nodeid":20,"label":"Test"}'' Error: Empty UUID received

(y al final, me refiero casi al instante) Vuelve un nodo, sin uuid, prev_uuid o prev_label. this_nodeid y prev_nodeid se refieren a la identificación interna de neo4j. Si miramos hacia arriba, comenzando con el nodo anterior ( i ) Id (por nodeid - 20):

neo4j-sh (?)$ match (i) where id(i)=20 return i; +--------------------------------------------------------------------------------------------+ | i | +--------------------------------------------------------------------------------------------+ | Node[20]{uuid:10,label:"Test",prev_label:"Test",prev_uuid:9,prev_nodeid:17,this_nodeid:20} | +--------------------------------------------------------------------------------------------+ 1 row 19 ms

Es exactamente como debería ser. .uuid y todo. El nuevo se crea tal como se devuelve anteriormente:

neo4j-sh (?)$ match (i) where id(i)=22 return i; +------------------------------------------------------+ | i | +------------------------------------------------------+ | Node[22]{label:"Test",prev_nodeid:20,this_nodeid:22} | +------------------------------------------------------+ 1 row 17 ms

No prev_label o prev_uuid. ¿Cómo es esto posible? ¿Qué me estoy perdiendo? Es un nodo incompleto: Id goteando en mi consulta?

He intentado reiniciar, borrar el directorio de datos, reiniciar después de borrar el directorio de datos, buscar los registros (nada interesante, o incluso aburrido, pero en el momento correcto, cuando sucede lo anterior). Ahora estoy en el punto donde estoy cuestionando mi comprensión de cómo se supone que debe funcionar.

Esto es en 12.04 con neo4j 2.1.1. Más información de la versión y registros de inicio / apagado de Neo4j .

Soy consciente de que esta no es una forma óptima de crear UUID. Esta pregunta se trata de entender cómo estos resultados son posibles si las transacciones de neo4j funcionan como se espera.


Notamos un problema similar en Neo4J durante las escrituras transaccionales simultáneas y se introdujo una corrección en Neo4J 2.2.5 para solucionar esto (contamos con soporte de Enterprise y creamos un ticket para solucionarlo). Es posible que no tenga exactamente el mismo problema, pero podría valer la pena volver a intentarlo con 2.2.5 para ver si todavía es un problema.

Como dijiste, hay mejores formas de generar identificadores. Además, debe usar MAX para obtener lo último en lugar de LIMIT y ORDER BY , pero eso es además del punto ;-).

Buena suerte.