Permalink
Browse files

Merge branch 'master' into pql

Conflicts:
	embedded-examples/pom.xml
	neo4j-community/pom.xml
	neo4j/pom.xml
	pql/pom.xml
	pql/src/main/scala/org/neo4j/pql/ExecutionEngine.scala
	pql/src/main/scala/org/neo4j/pql/pipes/EagerAggregationPipe.scala
	pql/src/main/scala/org/neo4j/pql/pipes/SortPipe.scala
	pql/src/test/scala/org/neo4j/pql/PqlParserTest.scala
	pql/src/test/scala/org/neo4j/pql/SematicErrorTest.scala
	pql/src/test/scala/org/neo4j/pql/pipes/SortPipeTest.scala
	server/pom.xml
	server/src/functionaltest/java/org/neo4j/server/webadmin/console/CypherSessionTest.java
	server/src/main/java/org/neo4j/server/webadmin/rest/SessionFactoryImpl.java
	shell/pom.xml
	shell/src/main/java/org/neo4j/shell/kernel/apps/Select.java
  • Loading branch information...
2 parents a735466 + 2dd5bc4 commit 1ce8d9a2728ba3dd9d6b6efc8badb762be527bc0 @systay committed Nov 14, 2011
Showing with 2,912 additions and 864 deletions.
  1. +181 −187 embedded-examples/pom.xml
  2. +128 −0 embedded-examples/src/test/java/org/neo4j/examples/TraversalTest.java
  3. +2 −2 graph-algo/pom.xml
  4. +2 −2 graph-matching/pom.xml
  5. +2 −2 graphviz/pom.xml
  6. +3 −3 jmx/pom.xml
  7. +1 −1 kernel/pom.xml
  8. +8 −8 kernel/src/docs/ops/cache.txt
  9. +2 −0 kernel/src/docs/ops/index.txt
  10. +23 −0 kernel/src/docs/ops/short-arrays.txt
  11. +30 −10 kernel/src/docs/ops/short-strings.txt
  12. +2 −0 kernel/src/main/java/org/neo4j/kernel/AbstractGraphDatabase.java
  13. +28 −3 kernel/src/main/java/org/neo4j/kernel/Config.java
  14. +5 −0 kernel/src/main/java/org/neo4j/kernel/EmbeddedGraphDatabase.java
  15. +6 −0 kernel/src/main/java/org/neo4j/kernel/EmbeddedReadOnlyGraphDatabase.java
  16. +125 −59 kernel/src/main/java/org/neo4j/kernel/impl/batchinsert/BatchInserter.java
  17. +257 −0 kernel/src/main/java/org/neo4j/kernel/impl/batchinsert/BatchInserterImpl.java
  18. +17 −0 kernel/src/main/java/org/neo4j/kernel/impl/cache/LruCache.java
  19. +0 −1 kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java
  20. +0 −6 kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipTypeHolder.java
  21. +19 −0 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/store/StoreAccess.java
  22. +53 −0 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/InterceptingWriteTransaction.java
  23. +37 −24 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/NeoStoreXaDataSource.java
  24. +29 −6 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/WriteTransaction.java
  25. +79 −0 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/InterceptingXaLogicalLog.java
  26. +69 −0 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/TransactionInterceptor.java
  27. +114 −0 ...l/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/TransactionInterceptorProvider.java
  28. +19 −6 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/XaContainer.java
  29. +50 −67 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/XaLogicalLog.java
  30. +6 −0 kernel/src/test/java/org/neo4j/kernel/HighlyConfigurableGraphDatabase.java
  31. +167 −0 kernel/src/test/java/org/neo4j/kernel/impl/batchinsert/TestBatchInsert.java
  32. +1 −1 kernel/src/test/java/org/neo4j/kernel/impl/transaction/xaframework/TestUpgradeOneDotFourToFive.java
  33. +7 −0 kernel/src/test/java/org/neo4j/test/ImpermanentGraphDatabase.java
  34. +17 −5 kernel/src/test/java/org/neo4j/test/TargetDirectory.java
  35. +3 −3 lucene-index/pom.xml
  36. +55 −0 lucene-index/src/main/java/org/neo4j/index/impl/lucene/IndexSearcherLruCache.java
  37. +5 −0 lucene-index/src/main/java/org/neo4j/index/impl/lucene/IndexSearcherRef.java
  38. +54 −0 lucene-index/src/main/java/org/neo4j/index/impl/lucene/IndexWriterLruCache.java
  39. +42 −36 lucene-index/src/main/java/org/neo4j/index/impl/lucene/LuceneDataSource.java
  40. +9 −10 ...ogDeserializer.java → lucene-index/src/test/java/org/apache/lucene/index/IndexWriterAccessor.java
  41. +195 −0 lucene-index/src/test/java/org/neo4j/index/impl/lucene/TestLuceneDataSource.java
  42. +29 −0 lucene-index/src/test/java/org/neo4j/index/impl/lucene/TestLuceneIndex.java
  43. +9 −9 neo4j-community/pom.xml
  44. +10 −10 neo4j/pom.xml
  45. +2 −2 packaging/pom.xml
  46. +1 −1 pom.xml
  47. +11 −11 pql/pom.xml
  48. +8 −0 pql/src/docs/dev/ql/match/index.txt
  49. +7 −0 pql/src/main/java/org/neo4j/pql/javacompat/ExecutionResult.java
  50. +32 −10 pql/src/main/scala/org/neo4j/pql/ExecutionEngine.scala
  51. +17 −13 pql/src/main/scala/org/neo4j/pql/ExecutionResult.scala
  52. +1 −1 pql/src/main/scala/org/neo4j/pql/SymbolTable.scala
  53. +3 −0 pql/src/main/scala/org/neo4j/pql/parser/Tokens.scala
  54. +1 −1 pql/src/main/scala/org/neo4j/pql/parser/Values.scala
  55. +20 −4 pql/src/main/scala/org/neo4j/pql/pipes/EagerAggregationPipe.scala
  56. +16 −4 pql/src/main/scala/org/neo4j/pql/pipes/SortPipe.scala
  57. +45 −0 pql/src/test/scala/org/neo4j/pql/ExecutionEngineTest.scala
  58. +9 −7 pql/src/test/scala/org/neo4j/pql/GraphDatabaseTestBase.scala
  59. +57 −0 pql/src/test/scala/org/neo4j/pql/PqlParserTest.scala
  60. +5 −0 pql/src/test/scala/org/neo4j/pql/SematicErrorTest.scala
  61. +3 −3 pql/src/test/scala/org/neo4j/pql/pipes/EagerAggregationPipeTest.scala
  62. +9 −1 pql/src/test/scala/org/neo4j/pql/pipes/SortPipeTest.scala
  63. +2 −2 server-api/pom.xml
  64. +3 −3 server-examples/pom.xml
  65. +8 −9 server/pom.xml
  66. +1 −1 server/src/docs/dev/server-installation.txt
  67. +25 −2 server/src/functionaltest/java/org/neo4j/server/rest/AbstractRestFunctionalTestBase.java
  68. +40 −8 server/src/functionaltest/java/org/neo4j/server/rest/BatchOperationFunctionalTest.java
  69. +7 −0 server/src/functionaltest/java/org/neo4j/server/webadmin/console/CypherSessionTest.java
  70. +10 −10 server/src/functionaltest/java/org/neo4j/server/webadmin/console/GremlinSessionTest.java
  71. +9 −9 server/src/main/coffeescript/neo4j/webadmin/modules/console/ConsoleRouter.coffee
  72. +11 −2 server/src/main/coffeescript/neo4j/webadmin/modules/console/models/Console.coffee
  73. +0 −29 server/src/main/coffeescript/neo4j/webadmin/modules/console/models/CypherConsole.coffee
  74. +8 −3 server/src/main/coffeescript/neo4j/webadmin/modules/console/views/ConsoleView.coffee
  75. +3 −3 ...escript/neo4j/webadmin/modules/console/views/{CypherConsoleView.coffee → ShellConsoleView.coffee}
  76. +3 −3 server/src/main/coffeescript/neo4j/webadmin/modules/console/views/console.haml
  77. +1 −1 server/src/main/coffeescript/neo4j/webadmin/modules/console/views/{cypher.haml → shell.haml}
  78. +1 −1 server/src/main/coffeescript/neo4j/webadmin/modules/databrowser/views/DataBrowserView.coffee
  79. +14 −6 server/src/main/coffeescript/neo4j/webadmin/modules/databrowser/visualization/models/style.coffee
  80. +2 −0 ...ffeescript/neo4j/webadmin/modules/databrowser/visualization/views/VisualizationProfileView.coffee
  81. +18 −13 server/src/main/coffeescript/ribcage/ui/Nano.coffee
  82. +16 −5 server/src/main/java/org/neo4j/server/rest/web/InternalJettyServletResponse.java
  83. +12 −11 server/src/main/java/org/neo4j/server/webadmin/console/GremlinSession.java
  84. +9 −8 server/src/main/java/org/neo4j/server/webadmin/console/PqlSession.java
  85. +6 −1 server/src/main/java/org/neo4j/server/webadmin/console/ScriptSession.java
  86. +12 −3 server/src/main/java/org/neo4j/server/webadmin/rest/ConsoleService.java
  87. +47 −7 server/src/main/java/org/neo4j/server/webadmin/rest/SessionFactoryImpl.java
  88. +97 −0 server/src/main/java/org/neo4j/server/webadmin/rest/ShellSession.java
  89. +32 −0 server/src/main/resources/webadmin-html/js/lib/jquery.putCursorAtEnd.js
  90. +14 −16 server/src/webtest/java/org/neo4j/server/webadmin/ConsoleWebIT.java
  91. +7 −7 shell/pom.xml
  92. +17 −21 shell/src/main/java/org/neo4j/shell/AppCommandParser.java
  93. +20 −1 shell/src/main/java/org/neo4j/shell/ShellClient.java
  94. +12 −8 shell/src/main/java/org/neo4j/shell/ShellException.java
  95. +1 −1 shell/src/main/java/org/neo4j/shell/ShellServer.java
  96. +14 −0 shell/src/main/java/org/neo4j/shell/TextUtil.java
  97. +1 −1 shell/src/main/java/org/neo4j/shell/impl/AbstractAppServer.java
  98. +79 −52 shell/src/main/java/org/neo4j/shell/impl/AbstractClient.java
  99. +117 −0 shell/src/main/java/org/neo4j/shell/impl/CollectingOutput.java
  100. +7 −2 shell/src/main/java/org/neo4j/shell/impl/RemoteClient.java
  101. +8 −2 shell/src/main/java/org/neo4j/shell/impl/SameJvmClient.java
  102. +6 −0 shell/src/main/java/org/neo4j/shell/impl/ShellServerExtension.java
  103. +5 −4 shell/src/main/java/org/neo4j/shell/kernel/apps/Eval.java
  104. +2 −2 shell/src/main/java/org/neo4j/shell/kernel/apps/GraphDatabaseApp.java
  105. +39 −9 shell/src/main/java/org/neo4j/shell/kernel/apps/Select.java
  106. +3 −64 shell/src/test/java/org/neo4j/shell/AbstractShellTest.java
  107. +13 −12 ...ramework/LogDeserializerProvider.java → shell/src/test/java/org/neo4j/shell/StartDbWithShell.java
  108. +3 −3 udc/pom.xml
View
368 embedded-examples/pom.xml
@@ -1,198 +1,192 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.neo4j.build</groupId>
- <artifactId>examples-pom</artifactId>
- <version>25</version>
- <relativePath/>
- </parent>
- <groupId>org.neo4j.examples</groupId>
- <artifactId>neo4j-examples</artifactId>
- <name>Neo4j Examples</name>
- <version>1.5-SNAPSHOT</version>
- <description>Neo4j Embedded Examples</description>
- <url>http://components.neo4j.org/${project.artifactId}/${project.version}/</url>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.neo4j.build</groupId>
+ <artifactId>examples-pom</artifactId>
+ <version>25</version>
+ <relativePath />
+ </parent>
+ <groupId>org.neo4j.examples</groupId>
+ <artifactId>neo4j-examples</artifactId>
+ <name>Neo4j Examples</name>
+ <version>1.6-SNAPSHOT</version>
+ <description>Neo4j Embedded Examples</description>
+ <url>http://components.neo4j.org/${project.artifactId}/${project.version}/</url>
- <scm>
- <url>https://github.com/neo4j/community/tree/master/embedded-examples</url>
- </scm>
+ <scm>
+ <url>https://github.com/neo4j/community/tree/master/embedded-examples</url>
+ </scm>
- <properties>
- <short-name>neo4j-examples</short-name>
- <bundle.namespace>org.neo4j.examples</bundle.namespace>
- <apidocs-unpack>${project.build.directory}/neo4j-apidocs</apidocs-unpack>
- <apidocs-target>${project.build.directory}/site/apidocs</apidocs-target>
- <license-text.header>ApacheLicense-2.0-header.txt</license-text.header>
- </properties>
+ <properties>
+ <short-name>neo4j-examples</short-name>
+ <bundle.namespace>org.neo4j.examples</bundle.namespace>
+ <apidocs-unpack>${project.build.directory}/neo4j-apidocs</apidocs-unpack>
+ <apidocs-target>${project.build.directory}/site/apidocs</apidocs-target>
+ <license-text.header>ApacheLicense-2.0-header.txt</license-text.header>
+ </properties>
- <dependencies>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j</artifactId>
- <version>1.5-SNAPSHOT</version>
- <!-- In this context, keep this artifact as type pom -->
- <type>pom</type>
- <exclusions>
- <exclusion>
- <artifactId>neo4j-udc</artifactId>
- <groupId>org.neo4j</groupId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j-shell</artifactId>
- <version>1.5-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j-graphviz</artifactId>
- <version>1.5-SNAPSHOT</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j-udc</artifactId>
- <version>1.5-SNAPSHOT</version>
- <classifier>neo4j</classifier>
- </dependency>
- <dependency>
- <groupId>org.neo4j</groupId>
- <artifactId>neo4j-pql</artifactId>
- <version>1.5-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit-dep</artifactId>
- </dependency>
- <dependency>
- <groupId>org.hamcrest</groupId>
- <artifactId>hamcrest-all</artifactId>
- </dependency>
- </dependencies>
+ <dependencies>
+ <dependency>
+ <groupId>org.neo4j</groupId>
+ <artifactId>neo4j</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ <!-- In this context, keep this artifact as type pom -->
+ <type>pom</type>
+ <exclusions>
+ <exclusion>
+ <artifactId>neo4j-udc</artifactId>
+ <groupId>org.neo4j</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.neo4j</groupId>
+ <artifactId>neo4j-shell</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.neo4j</groupId>
+ <artifactId>neo4j-kernel</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.neo4j</groupId>
+ <artifactId>neo4j-graphviz</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.neo4j</groupId>
+ <artifactId>neo4j-udc</artifactId>
+ <version>1.6-SNAPSHOT</version>
+ <classifier>neo4j</classifier>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit-dep</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-all</artifactId>
+ </dependency>
+ </dependencies>
- <licenses>
- <license>
- <name>Apache License Version 2.0</name>
- <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
- <comments>
- Note that this license is for the project itself,
- and not for its dependencies. See the included NOTICE.txt
- file for further details.
- </comments>
- </license>
- </licenses>
+ <licenses>
+ <license>
+ <name>Apache License Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <comments>
+ Note that this license is for the project itself,
+ and not for its dependencies. See the included NOTICE.txt
+ file for further details.
+ </comments>
+ </license>
+ </licenses>
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-site-plugin</artifactId>
- <executions>
- <execution>
- <id>create-site</id>
- <phase>none</phase>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <id>get-javadoc-sources</id>
- <phase>none</phase>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-assembly-plugin</artifactId>
- <executions>
- <execution>
- <id>docs-assembly</id>
- <phase>package</phase>
- <configuration>
- <attach>true</attach>
- <appendAssemblyId>true</appendAssemblyId>
- <descriptors>
- <descriptor>src/main/assembly/docs-assembly.xml</descriptor>
- </descriptors>
- </configuration>
- <goals>
- <goal>single</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <artifactId>maven-source-plugin</artifactId>
- <executions>
- <execution>
- <id>attach-sources</id>
- <phase>package</phase>
- <goals>
- <goal>jar-no-fork</goal>
- <goal>test-jar-no-fork</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>create-site</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>get-javadoc-sources</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>docs-assembly</id>
+ <phase>package</phase>
+ <configuration>
+ <attach>true</attach>
+ <appendAssemblyId>true</appendAssemblyId>
+ <descriptors>
+ <descriptor>src/main/assembly/docs-assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-source-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar-no-fork</goal>
+ <goal>test-jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
- <reporting>
- <plugins>
- <plugin>
- <artifactId>maven-javadoc-plugin</artifactId>
- <reportSets>
- <reportSet>
- <id>javadoc-aggregated-report</id>
- <configuration>
- <skip>true</skip>
- </configuration>
- </reportSet>
- </reportSets>
- </plugin>
- </plugins>
- </reporting>
+ <reporting>
+ <plugins>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <reportSets>
+ <reportSet>
+ <id>javadoc-aggregated-report</id>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
- <distributionManagement>
- <site>
- <id>neo4j-site</id>
- <url>scpexe://components.neo4j.org/home/neo/components/${project.artifactId}/${project.version}</url>
- </site>
- </distributionManagement>
+ <distributionManagement>
+ <site>
+ <id>neo4j-site</id>
+ <url>scpexe://components.neo4j.org/home/neo/components/${project.artifactId}/${project.version}</url>
+ </site>
+ </distributionManagement>
- <repositories>
- <repository>
- <id>neo4j-release-repository</id>
- <name>Neo4j Maven 2 release repository</name>
- <url>http://m2.neo4j.org/releases</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- <repository>
- <id>neo4j-snapshot-repository</id>
- <name>Neo4j Maven 2 snapshot repository</name>
- <url>http://m2.neo4j.org/snapshots</url>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- <releases>
- <enabled>false</enabled>
- </releases>
- </repository>
- </repositories>
+ <repositories>
+ <repository>
+ <id>neo4j-release-repository</id>
+ <name>Neo4j Maven 2 release repository</name>
+ <url>http://m2.neo4j.org/releases</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>neo4j-snapshot-repository</id>
+ <name>Neo4j Maven 2 snapshot repository</name>
+ <url>http://m2.neo4j.org/snapshots</url>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ </repository>
+ </repositories>
</project>
View
128 embedded-examples/src/test/java/org/neo4j/examples/TraversalTest.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to Neo Technology under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Neo Technology licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+// START SNIPPET: sampleDocumentation
+// START SNIPPET: _sampleDocumentation
+package org.neo4j.examples;
+
+import static org.neo4j.visualization.asciidoc.AsciidocHelper.createGraphViz;
+import static org.neo4j.visualization.asciidoc.AsciidocHelper.createOutputSnippet;
+
+import org.junit.Test;
+import org.neo4j.graphdb.Direction;
+import org.neo4j.graphdb.Node;
+import org.neo4j.graphdb.Path;
+import org.neo4j.graphdb.RelationshipType;
+import org.neo4j.graphdb.traversal.TraversalDescription;
+import org.neo4j.kernel.Traversal;
+import org.neo4j.kernel.Uniqueness;
+import org.neo4j.kernel.impl.annotations.Documented;
+import org.neo4j.test.GraphDescription.Graph;
+
+public class TraversalTest extends AbstractJavaDocTestbase
+{
+ /**
+ * In contrary to
+ * http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/Node.html#traverse[Node#traverse] a
+ * http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/TraversalDescription.html[traversal description] is built (using a
+ * fluent interface) and such a description can spawn
+ * http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/Traverser.html[traversers].
+ *
+ * @@graph
+ *
+ * With the definition of the +RelationshipTypes+ as
+ *
+ * @@sourceRels
+ *
+ * The graph can be traversed with
+ *
+ * @@source1
+ *
+ * Since http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/TraversalDescription.html[+TraversalDescription+]s
+ * are immutable it is also useful to create template descriptions which holds common
+ * settings shared by different traversals, for example:
+ *
+ * @@source2
+ *
+ * If you're not interested in the http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/Path.html[+Path+]s,
+ * but f.ex. the http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/Node.html[+Node+]s
+ * you can transform the traverser into an iterable of http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/Traverser.html#nodes()[nodes]
+ * or http://components.neo4j.org/neo4j/{neo4j-version}/apidocs/org/neo4j/graphdb/traversal/Traverser.html#relationships()[relationships]:
+ *
+ * @@source3
+ *
+ * The full source for this example is available at
+ *
+ * @@github
+ */
+ @Test
+ @Documented
+ @Graph( {"Joe KNOWS Sara", "Lisa LIKES Joe" })
+ public void how_to_use_the_Traversal_framework()
+ {
+ Node joe = data.get().get( "Joe" );
+ gen.get().addSnippet(
+ "graph",
+ createGraphViz( "Hello World Graph", graphdb(),
+ gen.get().getTitle() ) );
+ // START SNIPPET: source1
+
+ for ( Path position : Traversal.description()
+ .depthFirst()
+ .relationships( Rels.KNOWS )
+ .relationships( Rels.LIKES, Direction.INCOMING )
+ .prune( Traversal.pruneAfterDepth( 5 ) )
+ .traverse( joe ) )
+ {
+ System.out.println( "Path from start node to current position is " + position );
+ }
+ // END SNIPPET: source1
+
+ // START SNIPPET: source2
+ final TraversalDescription FRIENDS_TRAVERSAL = Traversal.description()
+ .relationships( Rels.KNOWS )
+ .depthFirst()
+ .uniqueness( Uniqueness.RELATIONSHIP_GLOBAL );
+
+ // Don't go further than depth 3
+ for ( Path position : FRIENDS_TRAVERSAL
+ .prune( Traversal.pruneAfterDepth( 3 ) )
+ .traverse( joe ) ) {}
+ // Don't go further than depth 4
+ for ( Path position : FRIENDS_TRAVERSAL
+ .prune( Traversal.pruneAfterDepth( 4 ) )
+ .traverse( joe ) ) {}
+ // END SNIPPET: source2
+ // START SNIPPET: source3
+ for ( Node position : FRIENDS_TRAVERSAL.traverse( joe ).nodes() ) {}
+ // END SNIPPET: source3
+
+ gen.get().addSnippet( "output",
+ createOutputSnippet( "Hello graphy world!" ) );
+ gen.get().addSourceSnippets( this.getClass(), "source1","sourceRels","source2","source3" );
+ gen.get().addGithubLink( "github", this.getClass(), "neo4j/community",
+ "embedded-examples" );
+ }
+
+ // START SNIPPET: sourceRels
+ private static enum Rels implements RelationshipType
+ {
+ LIKES, KNOWS
+ }
+ // END SNIPPET: sourceRels
+}
View
4 graph-algo/pom.xml
@@ -16,7 +16,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>neo4j-graph-algo</artifactId>
<groupId>org.neo4j</groupId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Neo4j - Graph Algorithms</name>
<description>Graph algorithms for Neo4j.</description>
@@ -50,7 +50,7 @@ the relevant Commercial Agreement.
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
View
4 graph-matching/pom.xml
@@ -16,7 +16,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-graph-matching</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<name>Neo4j - Graph Matching</name>
<description>A graph pattern matcher for Neo4j.</description>
<url>http://components.neo4j.org/${project.artifactId}/${project.version}</url>
@@ -49,7 +49,7 @@
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
View
4 graphviz/pom.xml
@@ -11,7 +11,7 @@
<groupId>org.neo4j</groupId>
<artifactId>neo4j-graphviz</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<name>Neo4j - Graphviz generation</name>
<description>Utility component to generate Graphviz .dot notation from Neo4j graphs.</description>
@@ -46,7 +46,7 @@ the relevant Commercial Agreement.
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
View
6 jmx/pom.xml
@@ -10,7 +10,7 @@
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jmx</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<name>Neo4j - JMX support</name>
<description>Management support using JMX.</description>
<url>http://components.neo4j.org/${project.artifactId}/${project.version}</url>
@@ -51,7 +51,7 @@ the relevant Commercial Agreement.
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -62,7 +62,7 @@ the relevant Commercial Agreement.
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
View
2 kernel/pom.xml
@@ -10,7 +10,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-kernel</artifactId>
- <version>1.5-SNAPSHOT</version>
+ <version>1.6-SNAPSHOT</version>
<name>Neo4j - Graph Database Kernel</name>
<description>
Neo4j kernel is a lightweight, embedded Java database designed to
View
16 kernel/src/docs/ops/cache.txt
@@ -35,15 +35,15 @@ Each Neo4j storage file contains uniform fixed size records of a particular type
| Store file | Record size | Contents
| nodestore | 9 B | Nodes
| relstore | 33 B | Relationships
-| propstore | 25 B | Properties for nodes and relationships
-| stringstore | 133 B | Values of string properties
-| arraystore | 133 B | Values of array properties
+| propstore | 41 B | Properties for nodes and relationships
+| stringstore | 128 B | Values of string properties
+| arraystore | 128 B | Values of array properties
|============================================
-For strings and arrays, where data can be of variable length, data is stored in one or more 120B chunks, with 13B record overhead.
+For strings and arrays, where data can be of variable length, data is stored in one or more 120B chunks, with 8B record overhead.
The sizes of these blocks can actually be configured when the store is created using the `string_block_size` and `array_block_size` parameters.
The size of each record type can also be used to calculate the storage requirements of a Neo4j graph or the appropriate cache size for each file buffer cache.
-Note that some strings can be stored without using the string store, see <<short-strings>>.
+Note that some strings and arrays can be stored without using the string store or the array store respectively, see <<short-strings>> and <<short-arrays>>.
Neo4j uses multiple file buffer caches, one for each different storage file.
Each file buffer cache divides its storage file into a number of equally sized windows.
@@ -85,12 +85,12 @@ Configuration
Specifies the block size for storing strings.
This parameter is only honored when the store is created, otherwise it is ignored.
Note that each character in a string occupies two bytes, meaning that a block size of 120 (the default size) will hold a 60 character long string before overflowing into a second block.
- Also note that each block carries an overhead of 13 bytes.
- This means that if the block size is 120, the size of the stored records will be 133 bytes.
+ Also note that each block carries an overhead of 8 bytes.
+ This means that if the block size is 120, the size of the stored records will be 128 bytes.
| array_block_size |
Specifies the block size for storing arrays.
This parameter is only honored when the store is created, otherwise it is ignored.
- The default block size is 120 bytes, and the overhead of each block is the same as for string blocks, i.e., 13 bytes.
+ The default block size is 120 bytes, and the overhead of each block is the same as for string blocks, i.e., 8 bytes.
| dump_configuration | `true` or `false` | If set to `true` the current configuration settings will be written to the default system output, mostly the console or the logfiles.
|========================================================
View
2 kernel/src/docs/ops/index.txt
@@ -23,6 +23,8 @@ include::filesystem.txt[]
include::short-strings.txt[]
+include::short-arrays.txt[]
+
include::io-examples.txt[]
include::linux-performance.txt[]
View
23 kernel/src/docs/ops/short-arrays.txt
@@ -0,0 +1,23 @@
+[[short-arrays]]
+Compressed storage of short arrays
+===================================
+
+Neo4j will try to store your primitive arrays in a compressed way, so as to save disk space and possibly an I/O operation.
+To do that, it employs a "bit-shaving" algorithm that tries to reduce the number of bits required for storing the members
+of the array. In particular:
+
+1. For each member of the array, it determines the position of leftmost set bit.
+2. Determines the largest such position among all members of the array
+3. It reduces all members to that number of bits
+4. Stores those values, prefixed by a small header.
+
+That means that when even a single negative value is included in the array then the natural size of the primitives will be used.
+
+There is a possibility that the result can be inlined in the property record if:
+
+* It is less than 24 bytes after compression
+* It has less than 64 members
+
+For example, an array long[] {0L, 1L, 2L, 4L} will be inlined, as the largest entry (4) will require 3 bits to store so the whole array will be stored in 4*3=12 bits. The array long[] {-1L, 1L, 2L, 4L}
+however will require the whole 64 bits for the -1 entry so it needs 64*4 = 32 bytes and it will end up in the dynamic store.
+
View
40 kernel/src/docs/ops/short-strings.txt
@@ -2,15 +2,35 @@
Compressed storage of short strings
===================================
-Neo4j will classify your strings and store them accordingly.
-If a string is classified as a short string it will be stored without indirection in the property store.
-This means that there will be no string records created for storing that string.
-Additionally, when no string record is needed to store the property, it can be read and written in a single lookup.
-This leads to improvements in performance and lower storage overhead.
+Neo4j will try to classify your strings in a short string class and if it manages that it will treat it accordingly.
+In that case, it will be stored without indirection in the property store, inlining it instead in the property record,
+meaning that the dynamic string store will not be involved in storing that value, leading to reduced disk footprint.
+Additionally, when no string record is needed to store the property, it can be read and written in a single lookup,
+leading to performance improvements.
-For a string to be classified as a short string, one of the following must hold:
+The various classes for short strings are:
-* It is encodable in UTF-8 or Latin-1, 7 bytes or less.
-* It is alphanumerical, and 10 characters or less (9 if using accented european characters).
-* It consists of only upper case, or only lower case characters, including the punctuation characters space, underscore, period, dash, colon, or slash. Then it is allowed to be up to 12 characters.
-* It consists of only numerical characters, inlcuding the punctuation characters plus, comma, single quote, space, period, or dash. Then it is allowed to be up to 15 characters.
+* Numerical, consisting of digits 0..9 and the punctuation space, period, dash, plus, comma and apostrophe.
+* Date, consisting of digits 0..9 and the punctuation space dash, colon, slash, plus and comma.
+* Uppercase, consisting of uppercase letters A..Z, and the punctuation space, underscore, period, dash, colon and slash.
+* Lowercase, like upper but with lowercase letters a..z instead of uppercase
+* E-mail, consisting of lowercase letters a..z and the punctuation comma, underscore, period, dash, plus and the at sign (@)
+* URI, consisting of lowercase letters a..z, digits 0..9 and most punctuation available.
+* Alphanumerical, consisting of both upper and lowercase letters a..zA..z, digits 0..9 and punctuation space and underscore.
+* Alphasymbolical, consisting of both upper and lowercase letters a..zA..Z and the punctuation space, underscore, period, dash, colon, slash, plus, comma, apostrophe, at sign, pipe and semicolon.
+* European, consisting of most accented european characters and digits plus punctuation space, dash, underscore and period - like latin1 but with less punctuation
+* Latin 1
+* UTF-8
+
+In addition to the string's contents, the number of characters also determines if the string can be inlined or not. Each class has its own character count limits, which are
+
+* For Numerical and Date, 54
+* For Uppercase, Lowercase and E-mail, 43
+* For URI, Alphanumerical and Alphasymbolical, 36
+* For European, 31
+* For Latin1, 27
+* For UTF-8, 14
+
+That means that the largest inline-able string is 54 characters long and must be of the Numerical class and also that all Strings of size 14 or less will always be inlined.
+
+Also note that the above limits are for the default 41 byte PropertyRecord layout - if that parameter is changed via editing the source and recompiling, the above have to be recalculated.
View
2 kernel/src/main/java/org/neo4j/kernel/AbstractGraphDatabase.java
@@ -63,6 +63,8 @@
public abstract <T> Collection<T> getManagementBeans( Class<T> type );
public abstract boolean isReadOnly();
+
+ public abstract KernelData getKernelData();
@Override
public String toString()
View
31 kernel/src/main/java/org/neo4j/kernel/Config.java
@@ -130,12 +130,14 @@
/** Relative path for where the Neo4j storage information file is located */
@Documented
public static final String NEO_STORE = "neo_store";
+
/**
* The type of cache to use for nodes and relationships, one of [weak, soft,
* none]
*/
@Documented
public static final String CACHE_TYPE = "cache_type";
+
/**
* The name of the Transaction Manager service to use as defined in the TM
* service provider constructor, defaults to native.
@@ -144,11 +146,20 @@
public static final String TXMANAGER_IMPLEMENTATION = "tx_manager_impl";
/**
- * The name of the log deserializer implementation to use for externally
- * supplied transactions. Defaults to native.
+ * Determines whether any TransactionInterceptors loaded will intercept
+ * prepared transactions before they reach the logical log. Defaults to
+ * false.
*/
@Documented
- public static final String LOG_DESERIALIZER_IMPLEMENTATION = "log_deserializer_impl";
+ public static final String INTERCEPT_COMMITTING_TRANSACTIONS = "intercept_committing_transactions";
+
+ /**
+ * Determines whether any TransactionInterceptors loaded will intercept
+ * externally received transactions (e.g. in HA) before they reach the
+ * logical log and are applied to the store. Defaults to false.
+ */
+ @Documented
+ public static final String INTERCEPT_DESERIALIZED_TRANSACTIONS = "intercept_deserialized_transactions";
/**
* Boolean (one of true,false) defining whether to allow a store upgrade
@@ -195,6 +206,20 @@
@Documented
public static final String RELATIONSHIP_AUTO_INDEXING = "relationship_auto_indexing";
+ /**
+ * Integer value that sets the maximum number of open lucene index searchers.
+ * The default is Integer.MAX_VALUE
+ */
+ @Documented
+ public static final String LUCENE_SEARCHER_CACHE_SIZE = "lucene_searcher_cache_size";
+
+ /**
+ * Integer value that sets the maximum number of open lucene index writers.
+ * The default is Integer.MAX_VALUE
+ */
+ @Documented
+ public static final String LUCENE_WRITER_CACHE_SIZE = "lucene_writer_cache_size";
+
static final String LOAD_EXTENSIONS = "load_kernel_extensions";
private final AdaptiveCacheManager cacheManager;
View
5 kernel/src/main/java/org/neo4j/kernel/EmbeddedGraphDatabase.java
@@ -163,6 +163,11 @@ public boolean isReadOnly()
return false;
}
+ @Override
+ public KernelData getKernelData()
+ {
+ return graphDbImpl.getKernelData();
+ }
@Override
public String getStoreDir()
View
6 kernel/src/main/java/org/neo4j/kernel/EmbeddedReadOnlyGraphDatabase.java
@@ -160,6 +160,12 @@ public boolean isReadOnly()
{
return true;
}
+
+ @Override
+ public KernelData getKernelData()
+ {
+ return graphDbImpl.getKernelData();
+ }
@Override
public String toString()
View
184 kernel/src/main/java/org/neo4j/kernel/impl/batchinsert/BatchInserter.java
@@ -25,163 +25,229 @@
import org.neo4j.graphdb.RelationshipType;
/**
- * The batch inserter drops support for transactions and concurrency in favor
- * of insertion speed. When done using the batch inserter {@link #shutdown()}
- * must be invoked and complete successfully for the Neo4j store to be in
- * consistent state.
+ * The batch inserter drops support for transactions and concurrency in favor
+ * of insertion speed. When done using the batch inserter {@link #shutdown()}
+ * must be invoked and complete successfully for the Neo4j store to be in
+ * consistent state.
* <p>
- * Only one thread at a time may work against the batch inserter, multiple
- * threads performing concurrent access has to be synchronized.
+ * Only one thread at a time may work against the batch inserter, multiple
+ * threads performing concurrent access have to employ synchronization.
* <p>
- * Transactions are not supported so if your JVM/machine crash or you fail to
- * invoke {@link #shutdown()} before JVM exits the Neo4j store can be considered
- * being in non consistent state and the insertion has to be re-done from
+ * Transactions are not supported so if the JVM/machine crashes or you fail to
+ * invoke {@link #shutdown()} before JVM exits the Neo4j store can be considered
+ * being in non consistent state and the insertion has to be re-done from
* scratch.
*/
public interface BatchInserter
{
/**
- * Creates a node assigning next available id to id and also adds any
+ * Creates a node assigning next available id to id and also adds any
* properties supplied.
- *
- * @param properties a map containing properties or <code>null</code> if no
+ *
+ * @param properties a map containing properties or <code>null</code> if no
* properties should be added.
- *
+ *
* @return The id of the created node.
*/
public long createNode( Map<String,Object> properties );
-
+
/**
* Checks if a node with the given id exists.
- *
+ *
* @param nodeId the id of the node.
* @return <code>true</code> if the node exists.
*/
public boolean nodeExists( long nodeId );
-
+
/**
- * Sets the properties of a node. This method will remove any properties
+ * Sets the properties of a node. This method will remove any properties
* already existing and replace it with properties in the supplied map.
* <p>
- * For best performance try supply all the nodes properties upon creation
- * of the node. This method will delete any existing properties so using it
+ * For best performance try supply all the nodes properties upon creation
+ * of the node. This method will delete any existing properties so using it
* together with {@link #getNodeProperties(long)} will have bad performance.
- *
+ *
* @param node the id of the node.
- * @param properties map containing the properties or <code>null</code> to
+ * @param properties map containing the properties or <code>null</code> to
* clear all properties.
*/
public void setNodeProperties( long node, Map<String,Object> properties );
-
+
+ /**
+ * Returns true iff the node with id {@value node} has a property with name
+ * {@value propertyName}.
+ *
+ * @param node The node id of the node to check.
+ * @param propertyName The property name to check for
+ * @return True if the node has the named property - false otherwise.
+ */
+ public boolean nodeHasProperty( long node, String propertyName );
+
+ /**
+ * Returns true iff the relationship with id {@value relationship} has a
+ * property with name {@value propertyName}.
+ *
+ * @param relationship The relationship id of the relationship to check.
+ * @param propertyName The property name to check for
+ * @return True if the relationship has the named property - false
+ * otherwise.
+ */
+ public boolean relationshipHasProperty( long relationship,
+ String propertyName );
+
+ /**
+ * Sets the property with name {@value propertyName} of node with id
+ * {@value node} to the value {@propertyValue}. If the property exists it is
+ * updated, otherwise created.
+ *
+ * @param node The node id of the node whose property is to be set
+ * @param propertyName The name of the property to set
+ * @param propertyValue The value of the property to set
+ */
+ public void setNodeProperty( long node, String propertyName,
+ Object propertyValue );
+
+ /**
+ * Sets the property with name {@value propertyName} of relationship with id
+ * {@value relationship} to the value {@value propertyValue}. If the
+ * property
+ * exists it is updated, otherwise created.
+ *
+ * @param relationship The node id of the relationship whose property is to
+ * be set
+ * @param propertyName The name of the property to set
+ * @param propertyValue The value of the property to set
+ */
+ public void setRelationshipProperty( long relationship,
+ String propertyName, Object propertyValue );
/**
* Returns a map containing all the properties of this node.
- *
+ *
* @param nodeId the id of the node.
- *
+ *
* @return map containing this node's properties.
*/
public Map<String,Object> getNodeProperties( long nodeId );
-
+
/**
- * Returns an iterable over all the relationship ids connected to node with
- * supplied id.
- *
+ * Returns an iterable over all the relationship ids connected to node with
+ * supplied id.
+ *
* @param nodeId the id of the node.
* @return iterable over the relationship ids connected to the node.
*/
public Iterable<Long> getRelationshipIds( long nodeId );
-
+
/**
* Returns an iterable of {@link SimpleRelationship relationships} connected
* to the node with supplied id.
- *
+ *
* @param nodeId the id of the node.
* @return iterable over the relationships connected to the node.
*/
public Iterable<SimpleRelationship> getRelationships( long nodeId );
-
+
/**
- * Creates a node with supplied id and properties. If a node with the given
+ * Creates a node with supplied id and properties. If a node with the given
* id exist a runtime exception will be thrown.
- *
+ *
* @param id the id of the node to create.
- * @param properties map containing properties or <code>null</code> if no
+ * @param properties map containing properties or <code>null</code> if no
* properties should be added.
*/
public void createNode( long id, Map<String,Object> properties );
/**
- * Creates a relationship between two nodes of a specific type.
- *
+ * Creates a relationship between two nodes of a specific type.
+ *
* @param node1 the start node.
* @param node2 the end node.
- * @param type relationship type.
- * @param properties map containing properties or <code>null</code> if no
+ * @param type relationship type.
+ * @param properties map containing properties or <code>null</code> if no
* properties should be added.
* @return the id of the created relationship.
*/
public long createRelationship( long node1, long node2, RelationshipType
type, Map<String,Object> properties );
-
+
/**
* Gets a relationship by id.
- *
+ *
* @param relId the relationship id.
* @return a simple relationship wrapper for the relationship.
*/
public SimpleRelationship getRelationshipById( long relId );
-
+
/**
- * Sets the properties of a relationship. This method will remove any
- * properties already existing and replace it with properties in the
+ * Sets the properties of a relationship. This method will remove any
+ * properties already existing and replace it with properties in the
* supplied map.
* <p>
- * For best performance try supply all the relationship properties upon
- * creation of the relationship. This method will delete any existing
- * properties so using it together with
+ * For best performance try supply all the relationship properties upon
+ * creation of the relationship. This method will delete any existing
+ * properties so using it together with
* {@link #getRelationshipProperties(long)} will have bad performance.
- *
+ *
* @param rel the id of the relationship.
- * @param properties map containing the properties or <code>null</code> to
+ * @param properties map containing the properties or <code>null</code> to
* clear all properties.
*/
- public void setRelationshipProperties( long rel,
+ public void setRelationshipProperties( long rel,
Map<String,Object> properties );
-
+
/**
* Returns a map containing all the properties of the relationships.
- *
+ *
* @param relId the id of the relationship.
* @return map containing the relationship's properties.
*/
public Map<String,Object> getRelationshipProperties( long relId );
/**
- * Shuts down this batch inserter syncing all changes that are still only
- * in memory to disk. Failing to invoke this method may leave the Neo4j
+ * Removes the property named {@value property} from the node with id
+ * {@value id}, if present.
+ *
+ * @param node The id of the node from which to remove the property
+ * @param property The name of the property
+ */
+ public void removeNodeProperty( long node, String property );
+
+ /**
+ * Removes the property named {@value property} from the relationship with
+ * id {@value id}, if present.
+ *
+ * @param relationship The id of the relationship from which to remove the
+ * property
+ * @param property The name of the property
+ */
+ public void removeRelationshipProperty( long relationship, String property );
+
+ /**
+ * Shuts down this batch inserter syncing all changes that are still only
+ * in memory to disk. Failing to invoke this method may leave the Neo4j
* store in a inconsistent state.
* <p>
- * After this method has been invoked any other method call to this batch
+ * After this method has been invoked any other method call to this batch
* inserter is illegal.
*/
public void shutdown();
/**
* Returns the path to this Neo4j store.
- *
+ *
* @return the path to this Neo4j store.
*/
public String getStore();
-
+
/**
* Returns the reference node id or <code>-1</code> if it doesn't exist.
- *
+ *
* @return the reference node
*/
public long getReferenceNode();
-
+
/**
- *
+ *
* @return a GraphDatabaseService that does not support deletion and transactions
*/
public GraphDatabaseService getGraphDbService();
View
257 kernel/src/main/java/org/neo4j/kernel/impl/batchinsert/BatchInserterImpl.java
@@ -49,6 +49,7 @@
import org.neo4j.kernel.impl.nioneo.store.NeoStore;
import org.neo4j.kernel.impl.nioneo.store.NodeRecord;
import org.neo4j.kernel.impl.nioneo.store.NodeStore;
+import org.neo4j.kernel.impl.nioneo.store.PrimitiveRecord;
import org.neo4j.kernel.impl.nioneo.store.PropertyBlock;
import org.neo4j.kernel.impl.nioneo.store.PropertyData;
import org.neo4j.kernel.impl.nioneo.store.PropertyIndexData;
@@ -129,6 +130,262 @@ public BatchInserterImpl( String storeDir,
indexStore = new IndexStore( storeDir );
}
+ @Override
+ public boolean nodeHasProperty( long node, String propertyName )
+ {
+ return primitiveHasProperty( getNodeRecord( node ), propertyName );
+ }
+
+ @Override
+ public boolean relationshipHasProperty( long relationship,
+ String propertyName )
+ {
+ return primitiveHasProperty( getRelationshipRecord( relationship ),
+ propertyName );
+ }
+
+ @Override
+ public void setNodeProperty( long node, String propertyName,
+ Object propertyValue )
+ {
+ NodeRecord nodeRec = getNodeRecord( node );
+ if ( setPrimitiveProperty( nodeRec, propertyName, propertyValue ) )
+ {
+ getNodeStore().updateRecord( nodeRec );
+ }
+ }
+
+ @Override
+ public void setRelationshipProperty( long relationship,
+ String propertyName, Object propertyValue )
+ {
+ RelationshipRecord relRec = getRelationshipRecord( relationship );
+ if ( setPrimitiveProperty( relRec, propertyName, propertyValue ) )
+ {
+ getRelationshipStore().updateRecord( relRec );
+ }
+ }
+
+ @Override
+ public void removeNodeProperty( long node, String propertyName )
+ {
+ NodeRecord nodeRec = getNodeRecord( node );
+ if ( removePrimitiveProperty( nodeRec, propertyName ) )
+ {
+ getNodeStore().updateRecord( nodeRec );
+ }
+ }
+
+ @Override
+ public void removeRelationshipProperty( long relationship,
+ String propertyName )
+ {
+ RelationshipRecord relationshipRec = getRelationshipRecord( relationship );
+ if ( removePrimitiveProperty( relationshipRec, propertyName ) )
+ {
+ getRelationshipStore().updateRecord( relationshipRec );
+ }
+ }
+
+ private boolean removePrimitiveProperty( PrimitiveRecord primitive,
+ String property )
+ {
+ PropertyRecord current = null;
+ PropertyBlock target = null;
+ long nextProp = primitive.getNextProp();
+ int propIndex = indexHolder.getKeyId( property );
+ if ( nextProp == Record.NO_NEXT_PROPERTY.intValue() || propIndex == -1 )
+ {
+ // No properties or no one has that property, nothing changed
+ return false;
+ }
+ while ( nextProp != Record.NO_NEXT_PROPERTY.intValue() )
+ {
+ current = getPropertyStore().getRecord( nextProp );
+ if ( ( target = current.removePropertyBlock( propIndex ) ) != null )
+ {
+ if ( target.isLight() )
+ {
+ getPropertyStore().makeHeavy( target );
+ }
+ for ( DynamicRecord dynRec : target.getValueRecords() )
+ {
+ current.addDeletedRecord( dynRec );
+ }
+ break;
+ }
+ nextProp = current.getNextProp();
+ }
+ if ( current.size() > 0 )
+ {
+ getPropertyStore().updateRecord( current );
+ return false;
+ }
+ else
+ {
+ return unlinkPropertyRecord( current, primitive );
+ }
+ }
+
+ private boolean unlinkPropertyRecord( PropertyRecord propRecord,
+ PrimitiveRecord primitive )
+ {
+ assert propRecord.size() == 0;
+ boolean primitiveChanged = false;
+ long prevProp = propRecord.getPrevProp();
+ long nextProp = propRecord.getNextProp();
+ if ( primitive.getNextProp() == propRecord.getId() )
+ {
+ assert propRecord.getPrevProp() == Record.NO_PREVIOUS_PROPERTY.intValue() : propRecord
+ + " for "
+ + primitive;
+ primitive.setNextProp( nextProp );
+ primitiveChanged = true;
+ }
+ if ( prevProp != Record.NO_PREVIOUS_PROPERTY.intValue() )
+ {
+ PropertyRecord prevPropRecord = getPropertyStore().getRecord(
+ prevProp );
+ assert prevPropRecord.inUse() : prevPropRecord + "->" + propRecord
+ + " for " + primitive;
+ prevPropRecord.setNextProp( nextProp );
+ getPropertyStore().updateRecord( prevPropRecord );
+ }
+ if ( nextProp != Record.NO_NEXT_PROPERTY.intValue() )
+ {
+ PropertyRecord nextPropRecord = getPropertyStore().getRecord(
+ nextProp );
+ assert nextPropRecord.inUse() : propRecord + "->" + nextPropRecord
+ + " for " + primitive;
+ nextPropRecord.setPrevProp( prevProp );
+ getPropertyStore().updateRecord( nextPropRecord );
+ }
+ propRecord.setInUse( false );
+ /*
+ * The following two are not needed - the above line does all the work (PropertyStore
+ * does not write out the prev/next for !inUse records). It is nice to set this
+ * however to check for consistency when assertPropertyChain().
+ */
+ propRecord.setPrevProp( Record.NO_PREVIOUS_PROPERTY.intValue() );
+ propRecord.setNextProp( Record.NO_NEXT_PROPERTY.intValue() );
+ getPropertyStore().updateRecord( propRecord );
+ return primitiveChanged;
+ }
+
+ /**
+ * @return true if the passed primitive needs updating in the store.
+ */
+ private boolean setPrimitiveProperty( PrimitiveRecord primitive,
+ String name,
+ Object value )
+ {
+ boolean result = false;
+ long nextProp = primitive.getNextProp();
+ int index = indexHolder.getKeyId( name );
+
+ if ( index == -1 )
+ {
+ index = createNewPropertyIndex( name );
+ }
+ PropertyBlock block = new PropertyBlock();
+ getPropertyStore().encodeValue( block, index, value );
+ int size = block.getSize();
+
+ /*
+ * current is the current record traversed
+ * thatFits is the earliest record that can host the block
+ * thatHas is the record that already has a block for this index
+ */
+ PropertyRecord current = null, thatFits = null, thatHas = null;
+ /*
+ * We keep going while there are records or until we both found the
+ * property if it exists and the place to put it, if exists.
+ */
+ while ( !( nextProp == Record.NO_NEXT_PROPERTY.intValue() || ( thatHas != null && thatFits != null ) ) )
+ {
+ current = getPropertyStore().getRecord( nextProp );
+ /*
+ * current.getPropertyBlock() is cheap but not free. If we already
+ * have found thatHas, then we can skip this lookup.
+ */
+ if ( thatHas == null && current.getPropertyBlock( index ) != null )
+ {
+ thatHas = current;
+ PropertyBlock removed = thatHas.removePropertyBlock( index );
+ if ( removed.isLight() )
+ {
+ getPropertyStore().makeHeavy( removed );
+ for ( DynamicRecord dynRec : removed.getValueRecords() )
+ {
+ thatHas.addDeletedRecord( dynRec );
+ }
+ }
+ getPropertyStore().updateRecord( thatHas );
+ }
+ /*
+ * We check the size after we remove - potentially we can put in the same record.
+ *
+ * current.size() is cheap but not free. If we already found somewhere
+ * where it fits, no need to look again.
+ */
+ if ( thatFits == null
+ && ( PropertyType.getPayloadSize() - current.size() >= size ) )
+ {
+ thatFits = current;
+ }
+ nextProp = current.getNextProp();
+ }
+ /*
+ * thatHas is of no importance here. We know that the block is definitely not there.
+ * However, we can be sure that if the property existed, thatHas is not null and does
+ * not contain the block.
+ *
+ * thatFits is interesting. If null, we need to create a new record and link, otherwise
+ * just add the block there.
+ */
+ if ( thatFits == null )
+ {
+ thatFits = new PropertyRecord( getPropertyStore().nextId() );
+
+ if ( primitive.getNextProp() != Record.NO_NEXT_PROPERTY.intValue() )
+ {
+ PropertyRecord first = getPropertyStore().getRecord(
+ primitive.getNextProp() );
+ thatFits.setNextProp( first.getId() );
+ first.setPrevProp( thatFits.getId() );
+ getPropertyStore().updateRecord( first );
+ result = true;
+ }
+ primitive.setNextProp( thatFits.getId() );
+ }
+ thatFits.addPropertyBlock( block );
+ getPropertyStore().updateRecord( thatFits );
+ return result;
+ }
+
+ private boolean primitiveHasProperty( PrimitiveRecord record,
+ String propertyName )
+ {
+ long nextProp = record.getNextProp();
+ int propertyIndex = indexHolder.getKeyId( propertyName );
+ if (nextProp == Record.NO_NEXT_PROPERTY.intValue() || propertyIndex == -1)
+ {
+ return false;
+ }
+
+ PropertyRecord current = null;
+ while ( nextProp != Record.NO_NEXT_PROPERTY.intValue() )
+ {
+ current = getPropertyStore().getRecord( nextProp );
+ if ( current.getPropertyBlock( propertyIndex ) != null )
+ {
+ return true;
+ }
+ nextProp = current.getNextProp();
+ }
+ return false;
+ }
+
private void rejectAutoUpgrade( Map<String, String> stringParams )
{
if ( parseBoolean( stringParams.get( ALLOW_STORE_UPGRADE ) ) )
View
17 kernel/src/main/java/org/neo4j/kernel/impl/cache/LruCache.java
@@ -19,8 +19,10 @@
*/
package org.neo4j.kernel.impl.cache;
+import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Set;
/**
* Simple implementation of Least-recently-used cache.
@@ -138,6 +140,21 @@ public synchronized int size()
return cache.size();
}
+ public synchronized Set<K> keySet()
+ {
+ return cache.keySet();
+ }
+
+ public synchronized Collection<E> values()
+ {
+ return cache.values();
+ }
+
+ public synchronized Set<java.util.Map.Entry<K,E>> entrySet()
+ {
+ return cache.entrySet();
+ }
+
/**
* Returns the maximum size of this cache.
*
View
1 kernel/src/main/java/org/neo4j/kernel/impl/core/NodeManager.java
@@ -250,7 +250,6 @@ public void stop()
cacheManager.unregisterCache( nodeCache );
cacheManager.unregisterCache( relCache );
}
- relTypeHolder.clear();
}
public Node createNode()
View
6 kernel/src/main/java/org/neo4j/kernel/impl/core/RelationshipTypeHolder.java
@@ -188,10 +188,4 @@ RelationshipType getRelationshipType( int id )
}
return relTypeList;
}
-
- void clear()
- {
- relTypes = new ArrayMap<String,Integer>();
- relTranslation = new ConcurrentHashMap<Integer, RelationshipTypeImpl>();
- }
}
View
19 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/store/StoreAccess.java
@@ -23,10 +23,13 @@
import java.util.HashMap;
import java.util.Map;
+import org.neo4j.kernel.AbstractGraphDatabase;
import org.neo4j.kernel.CommonFactories;
import org.neo4j.kernel.Config;
import org.neo4j.kernel.IdGeneratorFactory;
import org.neo4j.kernel.IdType;
+import org.neo4j.kernel.impl.nioneo.xa.NeoStoreXaDataSource;
+import org.neo4j.kernel.impl.transaction.xaframework.XaDataSource;
/**
* Not thread safe (since DiffRecordStore is not thread safe), intended for
@@ -84,6 +87,22 @@ public StoreAccess( String path, Map<Object, Object> params )
relTypeStore.makeStoreOk();
}
+ public StoreAccess( AbstractGraphDatabase graphdb )
+ {
+ this( getNeoStoreFrom( graphdb ) );
+ }
+
+ private static NeoStore getNeoStoreFrom( AbstractGraphDatabase graphdb )
+ {
+ XaDataSource nioneo = graphdb.getConfig().getTxModule().getXaDataSourceManager().getXaDataSource(
+ Config.DEFAULT_DATA_SOURCE_NAME );
+ if ( nioneo instanceof NeoStoreXaDataSource )
+ {
+ return ( (NeoStoreXaDataSource) nioneo ).getNeoStore();
+ }
+ throw new IllegalArgumentException( "Could not access NeoStore from " + graphdb );
+ }
+
public StoreAccess( NeoStore store )
{
this( store.getNodeStore(), store.getRelationshipStore(), store.getPropertyStore(),
View
53 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/InterceptingWriteTransaction.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (c) 2002-2011 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.kernel.impl.nioneo.xa;
+
+import java.util.List;
+
+import org.neo4j.kernel.impl.core.LockReleaser;
+import org.neo4j.kernel.impl.nioneo.store.NeoStore;
+import org.neo4j.kernel.impl.transaction.LockManager;
+import org.neo4j.kernel.impl.transaction.xaframework.TransactionInterceptor;
+import org.neo4j.kernel.impl.transaction.xaframework.XaLogicalLog;
+
+public class InterceptingWriteTransaction extends WriteTransaction
+{
+ private final TransactionInterceptor interceptor;
+
+ InterceptingWriteTransaction( int identifier, XaLogicalLog log,
+ NeoStore neoStore, LockReleaser lockReleaser,
+ LockManager lockManager, TransactionInterceptor interceptor )
+ {
+ super( identifier, log, neoStore, lockReleaser,
+ lockManager );
+ this.interceptor = interceptor;
+ }
+
+ @Override
+ protected void intercept( List<Command> commands )
+ {
+ super.intercept( commands );
+ for ( Command command : commands )
+ {
+ command.accept( interceptor );
+ }
+ interceptor.complete();
+ }
+}
View
61 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/NeoStoreXaDataSource.java
@@ -36,6 +36,7 @@
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.helpers.Exceptions;
+import org.neo4j.helpers.Pair;
import org.neo4j.helpers.Service;
import org.neo4j.helpers.UTF8;
import org.neo4j.helpers.collection.ClosableIterable;
@@ -51,7 +52,8 @@
import org.neo4j.kernel.impl.persistence.IdGenerationFailedException;
import org.neo4j.kernel.impl.transaction.LockManager;
import org.neo4j.kernel.impl.transaction.xaframework.LogBackedXaDataSource;
-import org.neo4j.kernel.impl.transaction.xaframework.LogDeserializerProvider;
+import org.neo4j.kernel.impl.transaction.xaframework.TransactionInterceptor;
+import org.neo4j.kernel.impl.transaction.xaframework.TransactionInterceptorProvider;
import org.neo4j.kernel.impl.transaction.xaframework.XaCommand;
import org.neo4j.kernel.impl.transaction.xaframework.XaCommandFactory;
import org.neo4j.kernel.impl.transaction.xaframework.XaConnection;
@@ -89,6 +91,8 @@
private final String storeDir;
private final boolean readOnly;
+ private final List<Pair<TransactionInterceptorProvider, Object>> providers;
+
private boolean logApplied = false;
private final StringLogger msgLog;
@@ -136,38 +140,34 @@ public NeoStoreXaDataSource( Map<Object,Object> config ) throws IOException,
NeoStore.createStore( store, config );
}
- String deserializerProviderName = (String) config.get( Config.LOG_DESERIALIZER_IMPLEMENTATION );
- LogDeserializerProvider deserializerProvider;
- if ( deserializerProviderName == null
- || deserializerProviderName.equals( "native" ) )
+ providers = new ArrayList<Pair<TransactionInterceptorProvider, Object>>(
+ 2 );
+ for ( TransactionInterceptorProvider provider : Service.load( TransactionInterceptorProvider.class ) )
{
- deserializerProvider = null;
- }
- else
- {
- deserializerProvider = Service.load( LogDeserializerProvider.class,
- deserializerProviderName );
- if ( deserializerProvider == null )
- {
- throw new IllegalStateException(
- "Unknown log deserializer provide name "
- + deserializerProviderName );
- }
- else
+ Object conf = config.get( provider.getClass().getSimpleName()
+ + "." + provider.name() );
+ if ( conf != null )
{
- msgLog.logMessage( "Using "
- + deserializerProvider.getClass()
- + " as the log deserializer implementation, trigger by config option "
- + deserializerProviderName );
+ providers.add( Pair.of( provider, conf ) );
}
}
+ TransactionFactory tf = null;
+ if ( "true".equalsIgnoreCase( (String) config.get( Config.INTERCEPT_COMMITTING_TRANSACTIONS ) )
+ && !providers.isEmpty() )
+ {
+ tf = new InterceptingTransactionFactory();
+ }
+ else
+ {
+ tf = new TransactionFactory();
+ }
neoStore = new NeoStore( config );
config.put( NeoStore.class, neoStore );
xaContainer = XaContainer.create( this,
(String) config.get( "logical_log" ), new CommandFactory(
- neoStore ), new TransactionFactory(),
- deserializerProvider, config );
+ neoStore ), tf, providers.isEmpty() ? null : providers,
+ config );
try
{
if ( !readOnly )
@@ -340,6 +340,19 @@ public XaCommand readCommand( ReadableByteChannel byteChannel,
}
}
+ private class InterceptingTransactionFactory extends TransactionFactory
+ {
+ @Override
+ public XaTransaction create( int identifier )
+ {
+
+ TransactionInterceptor first = TransactionInterceptorProvider.resolveChain(
+ providers, NeoStoreXaDataSource.this );
+ return new InterceptingWriteTransaction( identifier,
+ getLogicalLog(), neoStore, lockReleaser, lockManager, first );
+ }
+ }
+
private class TransactionFactory extends XaTransactionFactory
{
TransactionFactory()
View
35 kernel/src/main/java/org/neo4j/kernel/impl/nioneo/xa/WriteTransaction.java
@@ -109,7 +109,7 @@
private XaConnection xaConnection;
WriteTransaction( int identifier, XaLogicalLog log, NeoStore neoStore,
- LockReleaser lockReleaser, LockManager lockManager )
+ LockReleaser lockReleaser, LockManager lockManager )
{
super( identifier, log );
this.neoStore = neoStore;
@@ -148,6 +148,10 @@ public void doAddCommand( XaCommand command )
@Override
protected void doPrepare() throws XAException
{
+ int noOfCommands = relTypeRecords.size() + nodeRecords.size()
+ + relRecords.size() + propIndexRecords.size()
+ + propertyRecords.size();
+ List<Command> commands = new ArrayList<Command>( noOfCommands );
if ( committed )
{
throw new XAException( "Cannot prepare committed transaction["
@@ -166,7 +170,8 @@ protected void doPrepare() throws XAException
new Command.RelationshipTypeCommand(
neoStore.getRelationshipTypeStore(), record );
relTypeCommands.add( command );
- addCommand( command );
+ commands.add( command );
+ // addCommand( command );
}
for ( NodeRecord record : nodeRecords.values() )
{
@@ -183,7 +188,8 @@ protected void doPrepare() throws XAException
{
removeNodeFromCache( record.getId() );
}
- addCommand( command );
+ commands.add( command );
+ // addCommand( command );
}
for ( RelationshipRecord record : relRecords.values() )
{
@@ -195,23 +201,40 @@ protected void doPrepare() throws XAException
{
removeRelationshipFromCache( record.getId() );
}
- addCommand( command );
+ commands.add( command );
+ // addCommand( command );
}
for ( PropertyIndexRecord record : propIndexRecords.values() )
{
Command.PropertyIndexCommand command =
new Command.PropertyIndexCommand(
neoStore.getPropertyStore().getIndexStore(), record );
propIndexCommands.add( command );
- addCommand( command );
+ commands.add( command );
+ // addCommand( command );
}
for ( PropertyRecord record : propertyRecords.values() )
{
Command.PropertyCommand command = new Command.PropertyCommand(
neoStore.getPropertyStore(), record );
propCommands.add( command );
- addCommand( command );
+ commands.add( command );
+ // addCommand( command );
}
+ assert commands.size() == noOfCommands : "Expected " + noOfCommands
+ + " final commands, got "
+ + commands.size() + " instead";
+ intercept( commands );
+
+ for ( Command command : commands )
+ {
+ addCommand(command);
+ }
+ }
+
+ protected void intercept( List<Command> commands )
+ {
+ // default no op
}
@Override
View
79 ...src/main/java/org/neo4j/kernel/impl/transaction/xaframework/InterceptingXaLogicalLog.java
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2002-2011 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.kernel.impl.transaction.xaframework;
+
+import java.nio.channels.ReadableByteChannel;
+import java.util.List;
+import java.util.Map;
+
+import org.neo4j.helpers.Pair;
+import org.neo4j.kernel.impl.nioneo.xa.Command;
+
+public class InterceptingXaLogicalLog extends XaLogicalLog
+{
+ private final List<Pair<TransactionInterceptorProvider, Object>> providers;
+ private final XaDataSource ds;
+
+ InterceptingXaLogicalLog( String fileName, XaResourceManager xaRm,
+ XaCommandFactory cf, XaTransactionFactory xaTf,
+ Map<Object, Object> config, List<Pair<TransactionInterceptorProvider, Object>> providers )
+ {
+ super( fileName, xaRm, cf, xaTf, config );
+ this.providers = providers;
+ this.ds = xaRm.getDataSource();
+ }
+
+ @Override
+ protected LogDeserializer getLogDeserializer(
+ ReadableByteChannel byteChannel )
+ {
+ final TransactionInterceptor first = TransactionInterceptorProvider.resolveChain(
+ providers, ds );
+
+ LogDeserializer toReturn = new LogDeserializer( byteChannel )
+ {
+ @Override
+ protected void intercept( List<LogEntry> entries )
+ {
+ for ( LogEntry entry : entries )
+ {
+ if ( entry instanceof LogEntry.Command )
+ {
+ LogEntry.Command commandEntry = (LogEntry.Command) entry;
+ if ( commandEntry.getXaCommand() instanceof Command )
+ {
+ ( (Command) commandEntry.getXaCommand() ).accept( first );
+ }
+ }
+ else if ( entry instanceof LogEntry.Start )
+ {
+ first.setStartEntry( (LogEntry.Start) entry );
+ }
+ else if ( entry instanceof LogEntry.Commit )
+ {
+ first.setCommitEntry( (LogEntry.Commit) entry );
+ }
+ }
+ first.complete();
+ }
+ };
+ return toReturn;
+ }
+}
View
69 ...l/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/TransactionInterceptor.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2002-2011 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.kernel.impl.transaction.xaframework;
+
+import org.neo4j.kernel.impl.nioneo.xa.CommandRecordVisitor;
+
+/**
+ * A TransactionInterceptor has the opportunity to perform a check on a
+ * transaction before it touches the store and logical log, potentially
+ * interrupting the process by throwing an exception. The initial idea
+ * around this functionality was a consistency checking implementation but
+ * any sort of run over the commands that comprise the transaction can be
+ * done. Extending {@link CommandRecordVisitor} enables for visiting all
+ * the records in the transaction and perform whatever work is necessary.
+ *
+ * TransactionInterceptors are instantiated by
+ * {@link TransactionInterceptorProvider}s and are possible to form a chain
+ * of responsibility.
+ */
+public interface TransactionInterceptor extends CommandRecordVisitor
+{
+ /**
+ * The main work method, supposed to be called by users when the whole
+ * required set of Commands has been met.
+ * The last operation in a normal completion scenario for this method
+ * must be calling complete() on the following member of the chain, if
+ * present.
+ */
+ public void complete();
+
+ /**
+ * Set, if available, the log start entry for this transaction. The
+ * implementation is not expected to act on it in any meaningful way
+ * but it is required to pass it on in the chain before throwing it
+ * out. Also, the implementation should not count on it being set
+ * during its lifetime - it is possible that it is not available.
+ *
+ * @param entry The start log entry for this transaction
+ */
+ public void setStartEntry( LogEntry.Start entry );
+
+ /**
+ * Set, if available, the log commit entry for this transaction. The
+ * implementation is not expected to act on it in any meaningful way
+ * but it is required to pass it on in the chain before throwing it
+ * out. Also, the implementation should not count on it being set
+ * during its lifetime - it is possible that it is not available.
+ *
+ * @param entry The commit log entry for this transaction
+ */
+ public void setCommitEntry( LogEntry.Commit entry );
+}
View
114 ...in/java/org/neo4j/kernel/impl/transaction/xaframework/TransactionInterceptorProvider.java
@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2002-2011 "Neo Technology,"
+ * Network Engine for Objects in Lund AB [http://neotechnology.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package org.neo4j.kernel.impl.transaction.xaframework;
+
+import java.util.List;
+
+import org.neo4j.helpers.Pair;
+import org.neo4j.helpers.Service;
+
+/**
+ * The basic service implementation for TransactionInterceptorProviders.
+ * Offers two ways to instantiate a TransactionInterceptor - one is
+ * standalone, the other is with an existing one as the next in the chain
+ * of responsibility.
+ */
+public abstract class TransactionInterceptorProvider extends Service
+{
+ public TransactionInterceptorProvider( String name )
+ {
+ super( name );
+ }
+
+ /**
+ * Returns the name of this provider
+ *
+ * @return The name of this provider
+ */
+ public abstract String name();
+
+ /**
+ * Creates a TransactionInterceptor with the given datasource and options.
+ * It is possible for this method to return null, signifying that the
+ * options passed did not allow for instantiation.
+ *
+ * @param ds The datasource the TransactionInterceptor will communicate with
+ * @param options An object that can be the options to instantiate the
+ * interceptor with - e.g "false" to prevent instantiation
+ * @return An implementation of TransactionInterceptor or null if the
+ * options say so.
+ */
+ public abstract TransactionInterceptor create( XaDataSource ds,
+ Object options );
+
+ /**
+ * Creates a TransactionInterceptor with the given datasource and options
+ * and the given TransactionInterceptor as the next in the chain.
+ * It is possible for this method to return null, signifying that the
+ * options passed did not allow for instantiation.
+ *
+ * @param ds The datasource the TransactionInterceptor will communicate with
+ * @param options An object that can be the options to instantiate the
+ * interceptor with - e.g "false" to prevent instantiation
+ * @param next The next interceptor in the chain - can be null
+ * @return An implementation of TransactionInterceptor or null if the
+ * options say so.
+ */
+ public abstract TransactionInterceptor create( TransactionInterceptor next,
+ XaDataSource ds, Object options );
+
+ /**
+ * A utility method that given some TransactionInterceptorProviders and
+ * their configuration objects returns a fully resolved chain of
+ * TransactionInterceptors - the return object is the first interceptor
+ * in the chain.
+ *
+ * @param providers A list of {@link Pair} of
+ * TransactionInterceptorProviders with
+ * the detected config objects